Spaces:
Sleeping
Sleeping
| 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", | |
| } | |
| def index(): | |
| return jsonify({"name": "CodeRescue API", "version": "1.0.0", "status": "running"}) | |
| def health(): | |
| return jsonify({"status": "ok"}) | |
| 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 | |
| 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) |