Mayank2027 commited on
Commit
2ee810f
·
verified ·
1 Parent(s): 7dcabe2

Update backend/main.py

Browse files
Files changed (1) hide show
  1. backend/main.py +31 -189
backend/main.py CHANGED
@@ -1,193 +1,35 @@
1
- import os, json, asyncio, subprocess, uuid
2
- from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, BackgroundTasks, Request
3
- from fastapi.responses import FileResponse, StreamingResponse
4
- from pydantic import BaseModel
5
- from typing import List, Optional, Dict, Any
6
- from pathlib import Path
7
-
8
- from model_router import route_chat, get_available_models
9
- from agent import CodingAgent
10
- from autocomplete import generate_autocomplete
11
-
12
- # Lazy import for codebase index (fails gracefully if sentence-transformers missing)
13
- CodebaseIndex = None
14
-
15
- def get_codebase_index():
16
- global CodebaseIndex
17
- if CodebaseIndex is None:
18
- try:
19
- from codebase_index import CodebaseIndex as CBI
20
- CodebaseIndex = CBI
21
- except ImportError:
22
- raise HTTPException(status_code=503, detail="Codebase indexing unavailable – rebuild with updated sentence-transformers")
23
- return CodebaseIndex
24
-
25
- app = FastAPI(title="Codeki API")
26
-
27
- indexers = {}
28
- agents = {}
29
- STATIC_DIR = "static"
30
-
31
- # ---------- API Models ----------
32
- class ChatRequest(BaseModel):
33
- model: str = "groq-mixtral-8x7b-32768"
34
- messages: List[Dict[str, str]]
35
- context_files: Optional[List[str]] = None
36
- project_path: str = "/app/sandbox"
37
-
38
- class AgentTaskRequest(BaseModel):
39
- prompt: str
40
- model: str = "openrouter-anthropic/claude-3-opus"
41
- project_path: str
42
- auto_approve: bool = False
43
- background: bool = False
44
-
45
- class AutocompleteRequest(BaseModel):
46
- prefix: str
47
- suffix: str = ""
48
- filepath: str
49
- language: str
50
- max_tokens: int = 64
51
- model: str = "groq-llama3-8b-8192"
52
-
53
- class IndexRequest(BaseModel):
54
- project_path: str
55
-
56
- class BugFixRequest(BaseModel):
57
- file_path: str
58
- error_output: str
59
- project_path: str
60
-
61
- class ReviewRequest(BaseModel):
62
- pr_diff: str
63
- project_path: str
64
-
65
- # ---------- API Routes (before catch-all) ----------
66
- @app.get("/api/models")
67
- async def get_models():
68
- return get_available_models()
69
-
70
- @app.post("/api/chat")
71
- async def chat(req: ChatRequest):
72
- context = ""
73
- if req.context_files:
74
- for f in req.context_files:
75
- p = Path(req.project_path) / f
76
- if p.exists():
77
- context += f"\n--- {f} ---\n{p.read_text()}\n"
78
- req.messages.insert(0, {"role": "system", "content": f"Relevant codebase context:\n{context}"})
79
- async def event_stream():
80
- try:
81
- async for token in route_chat(req.model, req.messages):
82
- yield f"data: {json.dumps({'token': token})}\n\n"
83
- yield "data: [DONE]\n\n"
84
- except Exception as e:
85
- yield f"data: {json.dumps({'token': f'ERROR: {str(e)}'})}\n\n"
86
- yield "data: [DONE]\n\n"
87
- return StreamingResponse(event_stream(), media_type="text/event-stream")
88
-
89
- @app.post("/api/agent/run")
90
- async def run_agent(req: AgentTaskRequest, background_tasks: BackgroundTasks):
91
- agent = CodingAgent(project_path=req.project_path, model=req.model)
92
- if req.background:
93
- task_id = str(uuid.uuid4())
94
- agents[task_id] = agent
95
- background_tasks.add_task(agent.execute_task, req.prompt, auto_approve=req.auto_approve)
96
- return {"task_id": task_id, "status": "started"}
97
- else:
98
- async def event_stream():
99
- async for event in agent.execute_task_stream(req.prompt, auto_approve=req.auto_approve):
100
- yield f"data: {json.dumps(event)}\n\n"
101
- yield "data: [DONE]\n\n"
102
- return StreamingResponse(event_stream(), media_type="text/event-stream")
103
-
104
- @app.post("/api/autocomplete")
105
- async def autocomplete(req: AutocompleteRequest):
106
- suggestions = await generate_autocomplete(req)
107
- return {"completions": suggestions}
108
-
109
- @app.post("/api/index")
110
- async def index_project(req: IndexRequest):
111
- CBI = get_codebase_index()
112
- idx = CBI(req.project_path)
113
- idx.build_index()
114
- indexers[req.project_path] = idx
115
- return {"status": "indexed", "files": len(idx.file_list)}
116
-
117
- @app.post("/api/bugfix")
118
- async def bugfix(req: BugFixRequest):
119
- agent = CodingAgent(project_path=req.project_path, model="openrouter-anthropic/claude-3-opus")
120
- result = await agent.fix_error(req.file_path, req.error_output)
121
- return result
122
-
123
- @app.post("/api/review")
124
- async def review_code(req: ReviewRequest):
125
- agent = CodingAgent(project_path=req.project_path, model="openrouter-anthropic/claude-3-opus")
126
- review = await agent.review_pr(req.pr_diff)
127
- return {"review": review}
128
-
129
- @app.post("/api/git")
130
- async def git_operation(action: str, project_path: str, args: Optional[dict] = None):
131
- import git
132
  try:
133
- repo = git.Repo(project_path)
134
- if action == "commit":
135
- repo.git.add(A=True)
136
- repo.git.commit(m=args.get("message", "auto commit"))
137
- elif action == "log":
138
- logs = list(repo.iter_commits(max_count=10))
139
- return {"log": [{"message": c.message, "hash": c.hexsha} for c in logs]}
140
- elif action == "branch":
141
- branches = [b.name for b in repo.branches]
142
- return {"branches": branches}
143
- else:
144
- raise HTTPException(400, "Unknown action")
145
  except Exception as e:
146
  raise HTTPException(400, str(e))
147
 
148
- @app.websocket("/ws/terminal")
149
- async def terminal_ws(websocket: WebSocket):
150
- await websocket.accept()
151
- proc = None
152
- try:
153
- while True:
154
- cmd = await websocket.receive_text()
155
- if cmd.startswith("exec:"):
156
- command = cmd[5:]
157
- proc = await asyncio.create_subprocess_shell(
158
- command,
159
- stdout=asyncio.subprocess.PIPE,
160
- stderr=asyncio.subprocess.PIPE,
161
- cwd="/app/sandbox"
162
- )
163
- stdout, stderr = await proc.communicate()
164
- output = stdout.decode() + stderr.decode()
165
- await websocket.send_text(output)
166
- elif cmd == "ctrl-c" and proc:
167
- proc.terminate()
168
- except WebSocketDisconnect:
169
- pass
170
-
171
- @app.post("/api/agent/task/{task_id}")
172
- async def get_agent_status(task_id: str):
173
- agent = agents.get(task_id)
174
- if not agent:
175
- raise HTTPException(404, "Task not found")
176
- return {"status": agent.status, "logs": agent.logs}
177
-
178
- # ---------- Serve Frontend (catch-all, must be last) ----------
179
- @app.get("/{full_path:path}")
180
- async def serve_frontend(full_path: str):
181
- if full_path.startswith("api"):
182
- raise HTTPException(404)
183
- file_path = os.path.join(STATIC_DIR, full_path)
184
- if os.path.isfile(file_path):
185
- return FileResponse(file_path)
186
- index_path = os.path.join(STATIC_DIR, "index.html")
187
- if os.path.isfile(index_path):
188
- return FileResponse(index_path)
189
- raise HTTPException(404, detail="Not found")
190
-
191
- if __name__ == "__main__":
192
- import uvicorn
193
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ @app.get("/api/files")
2
+ async def list_files(project_path: str = "/app/sandbox"):
3
+ # Return a tree of the project folder
4
+ import os
5
+ def build_tree(path):
6
+ tree = []
7
+ for item in sorted(os.listdir(path)):
8
+ if item.startswith('.') or item == '__pycache__':
9
+ continue
10
+ full = os.path.join(path, item)
11
+ node = {"name": item, "path": full.replace(project_path, "").lstrip("/"), "type": "folder" if os.path.isdir(full) else "file"}
12
+ if os.path.isdir(full):
13
+ node["children"] = build_tree(full)
14
+ tree.append(node)
15
+ return tree
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  try:
17
+ tree = build_tree(project_path)
18
+ return tree
 
 
 
 
 
 
 
 
 
 
19
  except Exception as e:
20
  raise HTTPException(400, str(e))
21
 
22
+ @app.post("/api/search")
23
+ async def search_codebase(query: str, project_path: str = "/app/sandbox", top_k: int = 5):
24
+ if project_path not in indexers:
25
+ # Auto-build index if not present
26
+ CBI = get_codebase_index()
27
+ idx = CBI(project_path)
28
+ try:
29
+ idx.build_index()
30
+ except Exception as e:
31
+ raise HTTPException(503, f"Indexing failed: {str(e)}")
32
+ indexers[project_path] = idx
33
+ idx = indexers[project_path]
34
+ results = idx.search(query, top_k)
35
+ return {"results": results}