| |
| import difflib |
| import json |
| import os |
| from typing import Dict, Any |
|
|
| from fastapi import FastAPI, Request |
| from fastapi.responses import JSONResponse |
| from fastapi.middleware.cors import CORSMiddleware |
|
|
| APP_NAME = "Python_ai" |
| app = FastAPI(title=APP_NAME) |
|
|
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], allow_credentials=True, |
| allow_methods=[""], allow_headers=[""], |
| ) |
|
|
| def ok(payload: Dict[str, Any] | None = None) -> JSONResponse: |
| return JSONResponse({"ok": True, **(payload or {})}) |
|
|
| @app.get("/health") |
| def health(): |
| return ok() |
|
|
| def make_unified_diff(filename: str, old_text: str, new_text: str) -> str: |
| |
| if not old_text.endswith("\n"): old_text += "\n" |
| if not new_text.endswith("\n"): new_text += "\n" |
| diff = difflib.unified_diff( |
| old_text.splitlines(keepends=True), |
| new_text.splitlines(keepends=True), |
| fromfile=f"a/{filename}", |
| tofile=f"b/{filename}", |
| n=3, |
| ) |
| return "".join(diff) |
|
|
| def minimal_fix(view_text: str) -> tuple[str, str, str]: |
| """ |
| Very small heuristic fixer: |
| - reslt -> result (common typo) |
| - NameError 'bar' if foo returns bar but bar undefined -> return 'result' instead |
| Only edits when the change is obvious; otherwise returns original text. |
| """ |
| old = view_text |
| new = old |
|
|
| |
| if "reslt" in new: |
| new = new.replace("reslt", "result") |
|
|
| |
| |
| |
| |
|
|
| return old, new, "Fixed trivial misspelling(s) where obvious." |
|
|
| @app.post("/code_help") |
| async def code_help(req: Request): |
| """ |
| Accepts ANY JSON shape to avoid 422. We only read fields we need. |
| Returns a PATCH-first JSON as your 'PythonFixer' contract expects. |
| """ |
| try: |
| body = await req.json() |
| except Exception: |
| body = {} |
|
|
| |
| utterance = body.get("utterance", "") |
| telemetry = body.get("telemetry", {}) or {} |
| filename = telemetry.get("file", "main.py") |
| viewport = telemetry.get("viewport", {}) or {} |
| view_text = viewport.get("text", "") |
|
|
| |
| old_text, new_text, why = minimal_fix(view_text) |
|
|
| if new_text != old_text: |
| patch = make_unified_diff(filename, old_text, new_text) |
| resp = { |
| "mode": "patch", |
| "patch": patch, |
| "full_text": "", |
| "explanation": why, |
| "confidence": 0.96, |
| "need": {"function": False, "xrefs": [], "page_ids": []}, |
| } |
| else: |
| |
| resp = { |
| "mode": "ask", |
| "patch": "", |
| "full_text": "", |
| "explanation": "Need more context or a specific error message to propose a safe minimal patch.", |
| "confidence": 0.55, |
| "need": {"function": False, "xrefs": [], "page_ids": []}, |
| } |
|
|
| |
| return JSONResponse(resp) |
|
|
| |
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run("app:app", host="0.0.0.0", port=int(os.getenv("PORT", "7860")), reload=False) |