Python_ai / app.py
Percy3822's picture
Update app.py
37e7757 verified
raw
history blame
3.4 kB
# app.py (Python_ai)
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)
# Allow CORS just in case you call it directly from the Brain UI
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:
# Ensure both end with newline so ranges are sane
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
# Trivial typo fix
if "reslt" in new:
new = new.replace("reslt", "result")
# If there's a pattern like:
# def foo():\n return bar\n\nresult = foo()
# we can't know bar; safer to leave it alone here.
# Keep this service minimal/fast.
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 = {}
# Extract with defaults (never 422)
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", "")
# Minimal edit logic
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:
# Nothing obvious to fix; ask for more context (keeps contract)
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": []},
}
# Always 200 with the contract object
return JSONResponse(resp)
# HF entry
if _name_ == "_main_":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=int(os.getenv("PORT", "7860")), reload=False)