sumit989's picture
Update app.py
82d1363 verified
import os
import json
import re
from time import time
from flask import Flask, request, jsonify
from flask_cors import CORS
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
app = Flask(__name__)
allowed_origins = os.getenv("ALLOWED_ORIGINS", "https://sumit989bishnoi-crypto.github.io")
CORS(app, origins=allowed_origins.split(","))
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
MODEL_NAME = os.getenv("MODEL_NAME", "google/gemma-4-31B-it")
API_KEY = os.getenv("API_KEY") or os.getenv("HF_TOKEN")
client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY) if API_KEY else None
_last_request: dict[str, float] = {}
def is_rate_limited(ip: str) -> bool:
now = time()
if ip in _last_request and now - _last_request[ip] < 2:
return True
_last_request[ip] = now
return False
def extract_json(raw: str) -> dict | None:
"""Strip markdown fences then attempt JSON parse two ways."""
cleaned = re.sub(r"^```(?:json)?\s*", "", raw.strip())
cleaned = re.sub(r"\s*```$", "", cleaned).strip()
try:
return json.loads(cleaned)
except json.JSONDecodeError:
pass
# Boundary-aware fallback β€” stops exactly where JSON ends
try:
idx = cleaned.index("{")
decoded, _ = json.JSONDecoder().raw_decode(cleaned, idx)
return decoded
except (ValueError, json.JSONDecodeError):
return None
def safe_parse(raw: str) -> dict:
"""
Always returns a valid dict.
Runs extract_json first; falls back to a safe default on any failure
so a bad model response never crashes the endpoint.
"""
if not raw:
return {
"language": "unknown",
"explanation": "The AI returned an empty response. Please try again.",
"fixed_code": "",
"confidence": "low",
}
result = extract_json(raw)
if result and isinstance(result, dict):
return result
# Last-resort: return the raw text as the explanation so the user sees something
return {
"language": "unknown",
"explanation": "Output parsing failed β€” the AI did not return valid JSON.",
"fixed_code": raw[:800],
"confidence": "low",
}
@app.route("/")
def index():
return jsonify({"name": "CodeRescue API", "version": "1.0.0", "status": "running"})
@app.route("/health")
def health():
return jsonify({"status": "ok"})
@app.route("/analyze", methods=["POST"])
def analyze_code():
forwarded = request.headers.get("X-Forwarded-For", "")
ip = forwarded.split(",")[0].strip() if forwarded else (request.remote_addr or "unknown")
if is_rate_limited(ip):
return jsonify({
"error": "Too many requests. Please wait a moment.",
"fixed_code": "",
"language": ""
}), 429
if not client:
return jsonify({"error": "API key not configured", "fixed_code": "", "language": ""}), 500
data = request.get_json(silent=True)
if not data or not data.get("code", "").strip():
return jsonify({"error": "No code provided"}), 400
raw_code = data["code"].strip()
warning = ""
if len(raw_code) > 800:
warning = "Code was truncated to 800 characters for processing."
user_code = raw_code[:800]
try:
response = client.chat.completions.create(
model=MODEL_NAME,
max_tokens=1200, # raised: 800 caused truncated JSON for longer fixes
messages=[
{
"role": "system",
"content": (
"You are an expert developer and code debugger.\n"
"\n"
"OUTPUT RULES β€” follow exactly:\n"
"1. Return ONLY valid, complete JSON. No markdown. No prose outside JSON.\n"
"2. The JSON object MUST be fully closed with all braces and brackets.\n"
"3. Do NOT truncate fixed_code under any circumstance.\n"
"4. Escape all special characters inside strings properly:\n"
" - newlines β†’ \\n\n"
" - tabs β†’ \\t\n"
" - backslashes β†’ \\\\\n"
" - double quotes β†’ \\\"\n"
"5. Never wrap the JSON in ```code fences```.\n"
"Before answering, verify:\n"
"1. Is there memory issue?\n"
"2. Is there concurrency issue?\n"
"3. Is fix consistent with explanation\n"
"4. Does fix preserve original logic?\n"
"\n"
"STEPS:\n"
"Step 1 β€” Detect the programming language automatically.\n"
"Step 2 β€” Find all bugs or errors in the code.\n"
"Step 3 β€” Explain briefly WHY the error happened (2-3 line).\n"
"Step 4 β€” Write the fully corrected code.\n"
"Step 5 β€” Rate your confidence as 'high', 'medium', or 'low'.\n"
"\n"
"REQUIRED JSON FORMAT (no deviations):\n"
"{\"language\":\"...\",\"explanation\":\"...\","
"\"fixed_code\":\"...\",\"confidence\":\"high|medium|low\"}"
),
},
{
"role": "user",
"content": f"Code:\n{user_code}",
},
],
)
raw = response.choices[0].message.content.strip()
# safe_parse always returns a dict β€” never raises
parsed = safe_parse(raw)
fixed_code = parsed.get("fixed_code", "")
# Unescape literal \n / \t the model emits inside JSON strings
fixed_code = fixed_code.replace("\\n", "\n").replace("\\t", "\t")
return jsonify({
"explanation": parsed.get("explanation", "No explanation provided."),
"fixed_code": fixed_code,
"language": parsed.get("language", "unknown"),
"confidence": parsed.get("confidence", "medium"),
"warning": warning,
})
except Exception as e:
return jsonify({
"explanation": f"Server error: {str(e)}",
"fixed_code": "",
"language": "unknown",
"confidence": "low",
"warning": warning
}), 500
@app.route("/openenv/reset", methods=["POST"])
@app.route("/reset", methods=["POST"])
def openenv_reset():
return jsonify({"status": "success"})
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
app.run(host="0.0.0.0", port=port)