Spaces:
Running
Running
feat: initial deploy of clarity hybrid backend with gemini and qwen support
Browse files- main.py +13 -4
- model_service.py +89 -0
- requirements.txt +1 -1
main.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
from pydantic import BaseModel
|
|
|
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
|
| 5 |
-
from model_service import correct_code_with_ai
|
|
|
|
| 6 |
app = FastAPI()
|
|
|
|
| 7 |
app.add_middleware(
|
| 8 |
CORSMiddleware,
|
| 9 |
allow_origins=["*"], # Allows all origins for simplicity.
|
|
@@ -14,6 +17,8 @@ app.add_middleware(
|
|
| 14 |
|
| 15 |
class CodeSnippet(BaseModel):
|
| 16 |
code: str
|
|
|
|
|
|
|
| 17 |
|
| 18 |
@app.get("/api/health")
|
| 19 |
def health_check():
|
|
@@ -21,10 +26,14 @@ def health_check():
|
|
| 21 |
|
| 22 |
@app.post("/api/correct")
|
| 23 |
def correct_code_endpoint(snippet: CodeSnippet):
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
# result is now a dict: {"code": "...", "language": {"name": "...", "ext": "..."}}
|
| 26 |
return {
|
| 27 |
"corrected_code": result["code"],
|
| 28 |
"language": result["language"]
|
| 29 |
-
}
|
| 30 |
-
|
|
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
from pydantic import BaseModel
|
| 3 |
+
from typing import Optional
|
| 4 |
from fastapi.middleware.cors import CORSMiddleware
|
| 5 |
|
| 6 |
+
from model_service import correct_code_with_ai, correct_code_with_gemini
|
| 7 |
+
|
| 8 |
app = FastAPI()
|
| 9 |
+
|
| 10 |
app.add_middleware(
|
| 11 |
CORSMiddleware,
|
| 12 |
allow_origins=["*"], # Allows all origins for simplicity.
|
|
|
|
| 17 |
|
| 18 |
class CodeSnippet(BaseModel):
|
| 19 |
code: str
|
| 20 |
+
model_provider: str = "local" # "local" or "google"
|
| 21 |
+
api_key: Optional[str] = None
|
| 22 |
|
| 23 |
@app.get("/api/health")
|
| 24 |
def health_check():
|
|
|
|
| 26 |
|
| 27 |
@app.post("/api/correct")
|
| 28 |
def correct_code_endpoint(snippet: CodeSnippet):
|
| 29 |
+
if snippet.model_provider == "google":
|
| 30 |
+
result = correct_code_with_gemini(snippet.code, snippet.api_key)
|
| 31 |
+
else:
|
| 32 |
+
# Default to local
|
| 33 |
+
result = correct_code_with_ai(snippet.code)
|
| 34 |
+
|
| 35 |
# result is now a dict: {"code": "...", "language": {"name": "...", "ext": "..."}}
|
| 36 |
return {
|
| 37 |
"corrected_code": result["code"],
|
| 38 |
"language": result["language"]
|
| 39 |
+
}
|
|
|
model_service.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
from transformers import pipeline
|
| 3 |
import torch
|
|
|
|
| 4 |
|
| 5 |
# --- Configuration ---
|
| 6 |
# Using the standard Qwen 2.5 Coder 0.5B Instruct model (Native PyTorch)
|
|
@@ -23,6 +24,12 @@ try:
|
|
| 23 |
device_map="auto"
|
| 24 |
)
|
| 25 |
print("Success: Clarity AI Model loaded.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
except Exception as e:
|
| 28 |
print(f"CRITICAL ERROR: Failed to load model. {e}")
|
|
@@ -197,3 +204,85 @@ def correct_code_with_ai(code: str) -> dict:
|
|
| 197 |
"code": f"# An error occurred during processing: {str(e)}",
|
| 198 |
"language": detected_lang
|
| 199 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
from transformers import pipeline
|
| 3 |
import torch
|
| 4 |
+
import google.generativeai as genai
|
| 5 |
|
| 6 |
# --- Configuration ---
|
| 7 |
# Using the standard Qwen 2.5 Coder 0.5B Instruct model (Native PyTorch)
|
|
|
|
| 24 |
device_map="auto"
|
| 25 |
)
|
| 26 |
print("Success: Clarity AI Model loaded.")
|
| 27 |
+
|
| 28 |
+
# Warm-up inference
|
| 29 |
+
print("Warming up model...")
|
| 30 |
+
warmup_msg = [{"role": "user", "content": "print('hello')"}]
|
| 31 |
+
pipe(warmup_msg, max_new_tokens=10)
|
| 32 |
+
print("Model warmup complete.")
|
| 33 |
|
| 34 |
except Exception as e:
|
| 35 |
print(f"CRITICAL ERROR: Failed to load model. {e}")
|
|
|
|
| 204 |
"code": f"# An error occurred during processing: {str(e)}",
|
| 205 |
"language": detected_lang
|
| 206 |
}
|
| 207 |
+
|
| 208 |
+
def correct_code_with_gemini(code: str, api_key: str = None) -> dict:
|
| 209 |
+
"""
|
| 210 |
+
Uses Google's Gemini 1.5 Flash model for code correction.
|
| 211 |
+
"""
|
| 212 |
+
detected_lang = detect_language(code)
|
| 213 |
+
|
| 214 |
+
# 1. Resolve API Key
|
| 215 |
+
final_key = api_key if api_key else os.environ.get("GOOGLE_API_KEY")
|
| 216 |
+
|
| 217 |
+
if not final_key:
|
| 218 |
+
return {
|
| 219 |
+
"code": "# Error: No Google API Key provided. Please add it in Settings.",
|
| 220 |
+
"language": detected_lang
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
try:
|
| 224 |
+
genai.configure(api_key=final_key)
|
| 225 |
+
|
| 226 |
+
# Stricter System Prompt (Same as Local)
|
| 227 |
+
system_prompt = (
|
| 228 |
+
"You are Clarity, an intelligent coding assistant designed for students and junior developers. "
|
| 229 |
+
"You were created by a team of college students (see projects.md) for a minor project to help peers write better code.\n\n"
|
| 230 |
+
"Your Mission:\n"
|
| 231 |
+
"1. **Review & Fix:** Correct syntax and logical errors.\n"
|
| 232 |
+
"2. **Educate:** Improve variable naming (use industry standards like Google Style Guide), readability, and structure.\n"
|
| 233 |
+
"3. **Optimize:** Remove redundancy and improve logic.\n"
|
| 234 |
+
"4. **Be Concise:** Provide objective, short, and high-value feedback. Avoid long lectures.\n\n"
|
| 235 |
+
"Guidelines:\n"
|
| 236 |
+
"- **Style:** Follow the Google Style Guide for the respective language.\n"
|
| 237 |
+
"- **Comments:** Add comments ONLY for complex logic or educational 'aha!' moments.\n"
|
| 238 |
+
"- **Tone:** Concise, Objective, and Mentor-like.\n"
|
| 239 |
+
"- **Identity:** You are 'Clarity'. If asked about your version, refer users to the GitHub repo. If asked non-code questions, answer only if factual and harmless; otherwise, politely decline.\n\n"
|
| 240 |
+
"Constraint: Return ONLY the corrected code with necessary educational comments inline. Do not output a separate explanation block unless absolutely necessary for a critical concept."
|
| 241 |
+
)
|
| 242 |
+
|
| 243 |
+
model = genai.GenerativeModel(
|
| 244 |
+
model_name="gemini-1.5-flash",
|
| 245 |
+
system_instruction=system_prompt
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
# One-shot example
|
| 249 |
+
example_input = "def sum(a,b): return a+b" if detected_lang["name"] == "Python" else "int sum(int a, int b) { return a+b; }"
|
| 250 |
+
example_output = (
|
| 251 |
+
"def sum(operand_a, operand_b):\n"
|
| 252 |
+
" # Descriptive names improve readability\n"
|
| 253 |
+
" return operand_a + operand_b"
|
| 254 |
+
) if detected_lang["name"] == "Python" else (
|
| 255 |
+
"int sum(int operand_a, int operand_b) {\n"
|
| 256 |
+
" // Descriptive names improve readability\n"
|
| 257 |
+
" return operand_a + operand_b;\n"
|
| 258 |
+
"}"
|
| 259 |
+
)
|
| 260 |
+
|
| 261 |
+
# Start chat with history
|
| 262 |
+
chat = model.start_chat(history=[
|
| 263 |
+
{"role": "user", "parts": [example_input]},
|
| 264 |
+
{"role": "model", "parts": [example_output]},
|
| 265 |
+
])
|
| 266 |
+
|
| 267 |
+
response = chat.send_message(code)
|
| 268 |
+
|
| 269 |
+
cleaned_response = response.text.strip()
|
| 270 |
+
|
| 271 |
+
# Cleanup markdown
|
| 272 |
+
if "```" in cleaned_response:
|
| 273 |
+
lines = cleaned_response.split("\n")
|
| 274 |
+
if lines[0].strip().startswith("```"): lines = lines[1:]
|
| 275 |
+
if lines and lines[-1].strip().startswith("```"): lines = lines[:-1]
|
| 276 |
+
cleaned_response = "\n".join(lines).strip()
|
| 277 |
+
|
| 278 |
+
return {
|
| 279 |
+
"code": cleaned_response,
|
| 280 |
+
"language": detect_language(cleaned_response)
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
except Exception as e:
|
| 284 |
+
print(f"Gemini Inference Error: {e}")
|
| 285 |
+
return {
|
| 286 |
+
"code": f"# Gemini Error: {str(e)}",
|
| 287 |
+
"language": detected_lang
|
| 288 |
+
}
|
requirements.txt
CHANGED
|
@@ -2,4 +2,4 @@ fastapi
|
|
| 2 |
uvicorn
|
| 3 |
transformers
|
| 4 |
torch
|
| 5 |
-
|
|
|
|
| 2 |
uvicorn
|
| 3 |
transformers
|
| 4 |
torch
|
| 5 |
+
accelerategoogle-generativeai
|