Percy3822 commited on
Commit
37e7757
·
verified ·
1 Parent(s): a7001e9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -58
app.py CHANGED
@@ -1,58 +1,110 @@
1
- from fastapi import FastAPI
2
- from pydantic import BaseModel
3
- from typing import List, Literal
4
-
5
- app = FastAPI(title="Python AI Stub")
6
-
7
- class Cursor(BaseModel):
8
- l: int
9
- c: int
10
-
11
- class Viewport(BaseModel):
12
- start: int
13
- end: int
14
- text: str
15
-
16
- class Diagnostic(BaseModel):
17
- l: int
18
- sev: str
19
- msg: str
20
-
21
- class Memory(BaseModel):
22
- short: List[str] = []
23
- sess: List[str] = []
24
- proj: List[str] = []
25
-
26
- class Inp(BaseModel):
27
- intent: str
28
- file: str
29
- lang: str
30
- cursor: Cursor
31
- viewport: Viewport
32
- diag: List[Diagnostic] = []
33
- term: str = ""
34
- mem: Memory = Memory()
35
-
36
- class Need(BaseModel):
37
- function: bool = False
38
- xrefs: List[str] = []
39
- page_ids: List[str] = []
40
-
41
- class Out(BaseModel):
42
- mode: Literal["patch","full","ask"]
43
- patch: str = ""
44
- full_text: str = ""
45
- explanation: str = ""
46
- confidence: float = 0.9
47
- need: Need = Need()
48
-
49
- @app.post("/code_help", response_model=Out)
50
- def code_help(x: Inp):
51
- before = x.viewport.text
52
- if "print(reslt)" in before:
53
- after = before.replace("print(reslt)","print(result)",1)
54
- h_start = x.viewport.start
55
- h_count = x.viewport.end - x.viewport.start + 1
56
- patch = f"--- a/{x.file}\n+++ b/{x.file}\n@@ -{h_start},{h_count} +{h_start},{h_count} @@\n-{before}\n+{after}\n"
57
- return Out(mode="patch", patch=patch, full_text="", explanation="Fixed misspelling: reslt -> result.", confidence=0.96)
58
- return Out(mode="ask", explanation="Need more context.", confidence=0.6)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py (Python_ai)
2
+ import difflib
3
+ import json
4
+ import os
5
+ from typing import Dict, Any
6
+
7
+ from fastapi import FastAPI, Request
8
+ from fastapi.responses import JSONResponse
9
+ from fastapi.middleware.cors import CORSMiddleware
10
+
11
+ APP_NAME = "Python_ai"
12
+ app = FastAPI(title=APP_NAME)
13
+
14
+ # Allow CORS just in case you call it directly from the Brain UI
15
+ app.add_middleware(
16
+ CORSMiddleware,
17
+ allow_origins=["*"], allow_credentials=True,
18
+ allow_methods=[""], allow_headers=[""],
19
+ )
20
+
21
+ def ok(payload: Dict[str, Any] | None = None) -> JSONResponse:
22
+ return JSONResponse({"ok": True, **(payload or {})})
23
+
24
+ @app.get("/health")
25
+ def health():
26
+ return ok()
27
+
28
+ def make_unified_diff(filename: str, old_text: str, new_text: str) -> str:
29
+ # Ensure both end with newline so ranges are sane
30
+ if not old_text.endswith("\n"): old_text += "\n"
31
+ if not new_text.endswith("\n"): new_text += "\n"
32
+ diff = difflib.unified_diff(
33
+ old_text.splitlines(keepends=True),
34
+ new_text.splitlines(keepends=True),
35
+ fromfile=f"a/{filename}",
36
+ tofile=f"b/{filename}",
37
+ n=3,
38
+ )
39
+ return "".join(diff)
40
+
41
+ def minimal_fix(view_text: str) -> tuple[str, str, str]:
42
+ """
43
+ Very small heuristic fixer:
44
+ - reslt -> result (common typo)
45
+ - NameError 'bar' if foo returns bar but bar undefined -> return 'result' instead
46
+ Only edits when the change is obvious; otherwise returns original text.
47
+ """
48
+ old = view_text
49
+ new = old
50
+
51
+ # Trivial typo fix
52
+ if "reslt" in new:
53
+ new = new.replace("reslt", "result")
54
+
55
+ # If there's a pattern like:
56
+ # def foo():\n return bar\n\nresult = foo()
57
+ # we can't know bar; safer to leave it alone here.
58
+ # Keep this service minimal/fast.
59
+
60
+ return old, new, "Fixed trivial misspelling(s) where obvious."
61
+
62
+ @app.post("/code_help")
63
+ async def code_help(req: Request):
64
+ """
65
+ Accepts ANY JSON shape to avoid 422. We only read fields we need.
66
+ Returns a PATCH-first JSON as your 'PythonFixer' contract expects.
67
+ """
68
+ try:
69
+ body = await req.json()
70
+ except Exception:
71
+ body = {}
72
+
73
+ # Extract with defaults (never 422)
74
+ utterance = body.get("utterance", "")
75
+ telemetry = body.get("telemetry", {}) or {}
76
+ filename = telemetry.get("file", "main.py")
77
+ viewport = telemetry.get("viewport", {}) or {}
78
+ view_text = viewport.get("text", "")
79
+
80
+ # Minimal edit logic
81
+ old_text, new_text, why = minimal_fix(view_text)
82
+
83
+ if new_text != old_text:
84
+ patch = make_unified_diff(filename, old_text, new_text)
85
+ resp = {
86
+ "mode": "patch",
87
+ "patch": patch,
88
+ "full_text": "",
89
+ "explanation": why,
90
+ "confidence": 0.96,
91
+ "need": {"function": False, "xrefs": [], "page_ids": []},
92
+ }
93
+ else:
94
+ # Nothing obvious to fix; ask for more context (keeps contract)
95
+ resp = {
96
+ "mode": "ask",
97
+ "patch": "",
98
+ "full_text": "",
99
+ "explanation": "Need more context or a specific error message to propose a safe minimal patch.",
100
+ "confidence": 0.55,
101
+ "need": {"function": False, "xrefs": [], "page_ids": []},
102
+ }
103
+
104
+ # Always 200 with the contract object
105
+ return JSONResponse(resp)
106
+
107
+ # HF entry
108
+ if _name_ == "_main_":
109
+ import uvicorn
110
+ uvicorn.run("app:app", host="0.0.0.0", port=int(os.getenv("PORT", "7860")), reload=False)