Spaces:
Running
Running
# /app.py | |
import os | |
import subprocess | |
from fastapi import FastAPI, Request | |
from fastapi.responses import HTMLResponse | |
from pydantic import BaseModel | |
from mistralai.client import MistralClient | |
# --- 1. FastAPI μ± λ° Mistral ν΄λΌμ΄μΈνΈ μ΄κΈ°ν --- | |
app = FastAPI() | |
API_KEY = os.environ.get("MISTRAL_API_KEY") | |
CLIENT = None | |
if API_KEY: | |
try: | |
CLIENT = MistralClient(api_key=API_KEY) | |
print("Mistral API Client initialized successfully.") | |
except Exception as e: | |
print(f"Error initializing Mistral Client: {e}") | |
else: | |
print("FATAL: MISTRAL_API_KEY is not set in Space Secrets.") | |
# --- 2. λ°±μλ ν΅μ¬ κΈ°λ₯ ν¨μ --- | |
def generate_c_code(description: str) -> str: | |
"""Generates C code based on a natural language description.""" | |
if not CLIENT: return "Error: Mistral API key not configured." | |
prompt = f"You are a C programming expert. Generate a complete, compilable C code for this request: '{description}'. ONLY output the raw C code within a single ```c code block." | |
messages = [{"role": "user", "content": prompt}] | |
response = CLIENT.chat(model="codestral-latest", messages=messages) | |
code = response.choices[0].message.content | |
if "```c" in code: | |
code = code.split("```c")[1].split("```")[0].strip() | |
elif "```" in code: | |
code = code.split("```")[1].split("```")[0].strip() | |
return code | |
def compile_and_run_c_code(code: str) -> str: | |
"""Compiles and runs a given C code snippet and returns its output or any errors.""" | |
try: | |
with open("main.c", "w", encoding='utf-8') as f: | |
f.write(code) | |
compile_proc = subprocess.run( | |
["gcc", "main.c", "-o", "main.out", "-lm", "-w"], | |
capture_output=True, text=True, timeout=15 | |
) | |
if compile_proc.returncode != 0: | |
return f"--- COMPILATION FAILED ---\n{compile_proc.stderr}" | |
run_proc = subprocess.run( | |
["./main.out"], capture_output=True, text=True, timeout=15 | |
) | |
if run_proc.returncode != 0: | |
return f"--- RUNTIME ERROR ---\n{run_proc.stderr}" | |
output = run_proc.stdout | |
if not output.strip(): | |
return "--- EXECUTION SUCCEEDED ---\n(No output was produced)" | |
return f"--- EXECUTION SUCCEEDED ---\n{output}" | |
except Exception as e: | |
return f"--- SYSTEM ERROR ---\nAn unexpected error occurred: {str(e)}" | |
# --- 3. HTML, CSS, JavaScript νλ‘ νΈμλ --- | |
HTML_TEMPLATE = """ | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>C-Codestral Agent</title> | |
<style> | |
body { font-family: sans-serif; background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } | |
#app-container { width: 100%; max-width: 800px; height: 90vh; background: white; border-radius: 8px; box-shadow: 0 0 20px rgba(0,0,0,0.1); display: flex; flex-direction: column; } | |
h1 { text-align: center; color: #333; padding: 20px; margin: 0; border-bottom: 1px solid #eee; } | |
#chat-box { flex-grow: 1; padding: 20px; overflow-y: auto; } | |
.message { margin-bottom: 15px; } | |
.user-msg { text-align: right; } | |
.bot-msg { text-align: left; } | |
.msg-bubble { display: inline-block; padding: 10px 15px; border-radius: 18px; max-width: 80%; } | |
.user-msg .msg-bubble { background-color: #007bff; color: white; } | |
.bot-msg .msg-bubble { background-color: #e9e9eb; color: black; } | |
pre { background-color: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; white-space: pre-wrap; word-wrap: break-word; } | |
#input-area { display: flex; padding: 20px; border-top: 1px solid #eee; } | |
#user-input { flex-grow: 1; padding: 10px; border: 1px solid #ccc; border-radius: 20px; outline: none; } | |
#send-btn { background: #007bff; color: white; border: none; padding: 10px 20px; margin-left: 10px; border-radius: 20px; cursor: pointer; } | |
</style> | |
</head> | |
<body> | |
<div id="app-container"> | |
<h1>π C-Codestral Agent</h1> | |
<div id="chat-box"></div> | |
<div id="input-area"> | |
<input type="text" id="user-input" placeholder="Ask me to generate or run C code..."> | |
<button id="send-btn">Send</button> | |
</div> | |
</div> | |
<script> | |
const chatBox = document.getElementById('chat-box'); | |
const userInput = document.getElementById('user-input'); | |
const sendBtn = document.getElementById('send-btn'); | |
let chatHistory = []; | |
function addMessage(sender, text) { | |
const msgDiv = document.createElement('div'); | |
msgDiv.classList.add('message', sender === 'user' ? 'user-msg' : 'bot-msg'); | |
const bubble = document.createElement('div'); | |
bubble.classList.add('msg-bubble'); | |
// Convert ```c ... ``` to <pre><code>...</code> | |
if (text.includes('```')) { | |
const parts = text.split(/```c|```/); | |
parts.forEach((part, index) => { | |
if (index % 2 === 1) { // Code block | |
const pre = document.createElement('pre'); | |
const code = document.createElement('code'); | |
code.textContent = part.trim(); | |
pre.appendChild(code); | |
bubble.appendChild(pre); | |
} else { // Regular text | |
const textNode = document.createTextNode(part); | |
bubble.appendChild(textNode); | |
} | |
}); | |
} else { | |
bubble.textContent = text; | |
} | |
msgDiv.appendChild(bubble); | |
chatBox.appendChild(msgDiv); | |
chatBox.scrollTop = chatBox.scrollHeight; | |
} | |
async function sendMessage() { | |
const message = userInput.value.trim(); | |
if (!message) return; | |
addMessage('user', message); | |
chatHistory.push({ "role": "user", "content": message }); | |
userInput.value = ''; | |
const response = await fetch('/chat', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ message: message, history: chatHistory }) | |
}); | |
const data = await response.json(); | |
const botResponse = data.response; | |
addMessage('bot', botResponse); | |
chatHistory.push({ "role": "assistant", "content": botResponse }); | |
} | |
sendBtn.addEventListener('click', sendMessage); | |
userInput.addEventListener('keypress', (e) => { | |
if (e.key === 'Enter') sendMessage(); | |
}); | |
</script> | |
</body> | |
</html> | |
""" | |
# --- 4. FastAPI μλν¬μΈνΈ --- | |
class ChatRequest(BaseModel): | |
message: str | |
history: list | |
async def get_home(): | |
return HTML_TEMPLATE | |
async def handle_chat(request: ChatRequest): | |
message = request.message | |
history = request.history | |
lower_message = message.lower() | |
response_text = "" | |
if "compile" in lower_message or "run" in lower_message or "μ€ν" in lower_message: | |
code_to_run = "" | |
for item in reversed(history): | |
if item['role'] == 'assistant' and "```c" in item['content']: | |
code_to_run = item['content'].split("```c")[1].split("```")[0].strip() | |
break | |
if not code_to_run: | |
response_text = "μ»΄νμΌν μ½λλ₯Ό μ°Ύμ μ μμ΅λλ€. λ¨Όμ μ½λλ₯Ό μμ±ν΄μ£ΌμΈμ." | |
else: | |
response_text = compile_and_run_c_code(code_to_run) | |
elif "generate" in lower_message or "create" in lower_message or "λ§λ€μ΄μ€" in lower_message or "μ§μ€" in lower_message: | |
generated_code = generate_c_code(message) | |
response_text = f"μ½λκ° μμ±λμμ΅λλ€. 'run this code'λΌκ³ μ λ ₯νμ¬ μ€νν μ μμ΅λλ€.\n\n```c\n{generated_code}\n```" | |
else: | |
if not CLIENT: | |
response_text = "MISTRAL_API_KEYκ° μ€μ λμ§ μμμ΅λλ€." | |
else: | |
messages = history + [{"role": "user", "content": message}] | |
response = CLIENT.chat(model="codestral-latest", messages=messages) | |
response_text = response.choices[0].message.content | |
return {"response": response_text} |