# imports 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()# load env app = Flask(__name__) # frontend lock allowed_origins = os.getenv("ALLOWED_ORIGINS", "https://sumit989bishnoi-crypto.github.io") CORS(app, origins=allowed_origins.split(",")) # model call API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1") MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-Coder-7B-Instruct") 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] = {} # rate limit 1 requesr for 2 sec 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 # stops exactly where JSON ends try: idx = cleaned.index("{") decoded, _ = json.JSONDecoder().raw_decode(cleaned, idx) return decoded except (ValueError, json.JSONDecodeError): return None # always return a valid result 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. """ # low confidence 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 # always return a valid explanation return { "language": "unknown", "explanation": "Output parsing failed — the AI did not return valid JSON.", "fixed_code": raw[:1500], "confidence": "low", } # status @app.route("/") def index(): return jsonify({"name": "CodeRescue API", "version": "42.0", "status": "running"}) # to show when backend is running correct # health check @app.route("/health") def health(): return jsonify({"status": "ok"}) # analyze @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") # rate limit error to show 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 start = time() 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) > 1500: warning = "Code was truncated to 1500 characters for processing." user_code = raw_code[:1500] try: response = client.chat.completions.create( model=MODEL_NAME, max_tokens=400, # max tokens usage limit messages=[ {"role": "system", "content": ( "You are a code debugger.\n" "RULES:\n" "1. Return ONLY valid JSON.\n" # always give json "2. No markdown, no extra text.\n" "3. Keep explanation to MAX 2 lines.\n" "4. Always return FULL fixed code.\n" "5. Keep code minimal and clean.\n" "6.Prefer fixes that preserve original logic and intent over simply avoiding errors.\n" # for low error "If code is too large:\n" # faster speed "- Simplify it while preserving logic.\n" "- Remove unnecessary parts if safe.\n" "JSON FORMAT:\n" # formoat to show "{\"language\":\"...\"," "\"explanation\":\"...\"," "\"fixed_code\":\"...\"," "\"confidence\":\"high|medium|low\"}" ), }, { "role": "user", "content": f"Code:\n{user_code}", }, ], ) # calculate latency end = time() 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, "time_taken": round(end - start, 3), }) # warning when it is server side error except Exception as e: return jsonify({ "explanation": f"Server error: {str(e)}", "fixed_code": "", "language": "unknown", "confidence": "low", "warning": warning }), 500 # route for /openenv/reset &&& /reset @app.route("/openenv/reset", methods=["POST"]) @app.route("/reset", methods=["POST"]) def openenv_reset(): return jsonify({"status": "success"}) # ip && port if __name__ == "__main__": port = int(os.environ.get("PORT", 7860)) app.run(host="0.0.0.0", port=port)