c / app.py
kimhyunwoo's picture
Update app.py
6a21a24 verified
raw
history blame
8.55 kB
# /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
@app.get("/", response_class=HTMLResponse)
async def get_home():
return HTML_TEMPLATE
@app.post("/chat")
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}