Sanyam400 commited on
Commit
7a3dae7
Β·
verified Β·
1 Parent(s): 1ed2170

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +158 -47
app/main.py CHANGED
@@ -1,74 +1,155 @@
1
- import os
2
  from pathlib import Path
3
  from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
4
  from fastapi.responses import StreamingResponse, HTMLResponse, JSONResponse
5
  from fastapi.staticfiles import StaticFiles
6
  from fastapi.middleware.cors import CORSMiddleware
 
 
7
  import config as cfg
8
  from agent_system import orchestrator
9
  from sandbox import pip_install
10
 
11
- app = FastAPI(title="PraisonChat", version="4.0.0")
12
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
 
13
 
14
  STATIC_DIR = Path(__file__).parent / "static"
15
  app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
16
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  @app.get("/", response_class=HTMLResponse)
19
  async def root():
20
  return HTMLResponse((STATIC_DIR / "index.html").read_text(encoding="utf-8"))
21
 
22
 
 
23
  @app.get("/api/health")
24
  def health():
25
- return {"status":"ok","version":"4.0.0",
26
- "longcat_key_set": bool(cfg.get_longcat_key()),
27
- "telegram_set": bool(cfg.get_telegram_token())}
28
-
29
 
30
  @app.get("/api/models")
31
  def models():
32
- return {"models":[
33
  {"id":"LongCat-Flash-Lite", "name":"LongCat Flash Lite", "context":"320K","speed":"⚑ Fastest","quota":"50M/day"},
34
  {"id":"LongCat-Flash-Chat", "name":"LongCat Flash Chat", "context":"256K","speed":"πŸš€ Fast", "quota":"500K/day"},
35
  {"id":"LongCat-Flash-Thinking-2601", "name":"LongCat Flash Thinking", "context":"256K","speed":"🧠 Deep", "quota":"500K/day"},
36
  ]}
37
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  @app.post("/api/chat")
40
  async def chat(request: Request):
41
  try:
42
  body = await request.json()
43
  except Exception:
44
- raise HTTPException(400, "Invalid JSON")
45
- messages = body.get("messages",[])
 
 
46
  api_key = body.get("api_key","").strip() or cfg.get_longcat_key()
47
  model = body.get("model","LongCat-Flash-Lite")
 
48
  if not api_key:
49
- raise HTTPException(400,"LongCat API key required. Add it in Settings.")
 
50
  if not messages:
51
- raise HTTPException(400,"No messages")
 
 
52
  if api_key != cfg.get_longcat_key(): cfg.set_longcat_key(api_key)
53
  if model != cfg.get_model(): cfg.set_model(model)
 
54
  user_message = messages[-1].get("content","")
55
  history = messages[:-1]
 
56
  async def stream():
57
- async for chunk in orchestrator.stream_response(user_message, history, api_key, model):
 
 
58
  yield f"data: {chunk}\n\n"
 
59
  return StreamingResponse(stream(), media_type="text/event-stream",
60
- headers={"X-Accel-Buffering":"no","Cache-Control":"no-cache"})
61
 
62
 
 
63
  @app.post("/api/install-package")
64
  async def install_package(request: Request):
65
- body = await request.json()
66
- packages = body.get("packages",[])
67
- if not packages: raise HTTPException(400,"No packages")
 
 
 
 
68
  import asyncio
69
  loop = asyncio.get_event_loop()
70
  ok, msg = await loop.run_in_executor(None, pip_install, packages)
71
- return {"ok":ok,"message":msg}
72
 
73
 
74
  # ── Telegram ───────────────────────────────────────────────────
@@ -78,58 +159,88 @@ async def telegram_webhook(request: Request, background_tasks: BackgroundTasks):
78
  try:
79
  update = await request.json()
80
  except Exception:
81
- return JSONResponse({"ok":True})
82
- print(f"[WEBHOOK] {str(update)[:200]}")
 
83
  api_key = cfg.get_longcat_key()
84
  model = cfg.get_model()
 
85
  if not api_key:
86
- msg = update.get("message",{})
87
- chat_id = msg.get("chat",{}).get("id")
88
  if chat_id:
89
  from telegram_bot import send_message
90
- await send_message(chat_id,"⚠️ No LongCat API key. Open the web UI, go to Settings, and save your key.")
91
- return JSONResponse({"ok":True})
 
 
 
92
  background_tasks.add_task(handle_update, update, api_key, model)
93
- return JSONResponse({"ok":True})
94
 
95
 
96
  @app.post("/api/telegram/setup")
97
  async def telegram_setup(request: Request):
98
- from telegram_bot import set_webhook, get_bot_info
99
- body = await request.json()
 
 
 
100
  token = body.get("token","").strip()
101
  base_url = body.get("base_url","").strip()
102
  api_key = body.get("api_key","").strip()
103
  model = body.get("model","").strip()
 
104
  if token: cfg.set_telegram_token(token)
105
  if api_key: cfg.set_longcat_key(api_key)
106
  if model: cfg.set_model(model)
 
107
  if not cfg.get_telegram_token():
108
- raise HTTPException(400,"No Telegram bot token")
109
- bot = await get_bot_info()
110
- if not bot.get("ok"):
111
- raise HTTPException(400,f"Invalid token: {bot}")
112
- webhook_result = {}
113
- if base_url:
114
- webhook_result = await set_webhook(base_url)
115
- return {"ok":True,"bot":bot.get("result",{}),"webhook":webhook_result}
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
 
118
  @app.get("/api/telegram/status")
119
  async def telegram_status():
120
- from telegram_bot import get_webhook_info, get_bot_info
121
- token = cfg.get_telegram_token()
122
- if not token:
123
- return {"connected":False,"message":"No bot token"}
124
- bot = await get_bot_info()
125
- hook = await get_webhook_info()
126
- return {"connected":bot.get("ok",False),"bot":bot.get("result",{}),
127
- "webhook":hook.get("result",{}),"longcat_key_set":bool(cfg.get_longcat_key())}
 
 
 
 
 
128
 
129
 
130
  @app.delete("/api/telegram/disconnect")
131
  async def telegram_disconnect():
132
- from telegram_bot import delete_webhook
133
- result = await delete_webhook()
134
- cfg.set("telegram_token","")
135
- return {"ok":True,"result":result}
 
 
 
 
1
+ import os, json, traceback
2
  from pathlib import Path
3
  from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
4
  from fastapi.responses import StreamingResponse, HTMLResponse, JSONResponse
5
  from fastapi.staticfiles import StaticFiles
6
  from fastapi.middleware.cors import CORSMiddleware
7
+ from fastapi.exception_handlers import http_exception_handler
8
+ from starlette.exceptions import HTTPException as StarletteHTTPException
9
  import config as cfg
10
  from agent_system import orchestrator
11
  from sandbox import pip_install
12
 
13
+ app = FastAPI(title="PraisonChat", version="5.0.0")
14
+ app.add_middleware(CORSMiddleware, allow_origins=["*"],
15
+ allow_methods=["*"], allow_headers=["*"])
16
 
17
  STATIC_DIR = Path(__file__).parent / "static"
18
  app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
19
 
20
 
21
+ # ── ALWAYS return JSON errors, never HTML ─────────────────────
22
+ @app.exception_handler(StarletteHTTPException)
23
+ async def json_http_exception(request, exc):
24
+ return JSONResponse(
25
+ status_code=exc.status_code,
26
+ content={"ok": False, "detail": str(exc.detail)}
27
+ )
28
+
29
+ @app.exception_handler(Exception)
30
+ async def json_generic_exception(request, exc):
31
+ tb = traceback.format_exc()
32
+ print(f"[SERVER] Unhandled: {exc}\n{tb}")
33
+ return JSONResponse(
34
+ status_code=500,
35
+ content={"ok": False, "detail": str(exc)}
36
+ )
37
+
38
+
39
+ # ── Pages ──────────────────────────────────────────────────────
40
  @app.get("/", response_class=HTMLResponse)
41
  async def root():
42
  return HTMLResponse((STATIC_DIR / "index.html").read_text(encoding="utf-8"))
43
 
44
 
45
+ # ── System ─────────────────────────────────────────────────────
46
  @app.get("/api/health")
47
  def health():
48
+ return {"ok": True, "version": "5.0.0",
49
+ "longcat_key": bool(cfg.get_longcat_key()),
50
+ "telegram": bool(cfg.get_telegram_token())}
 
51
 
52
  @app.get("/api/models")
53
  def models():
54
+ return {"models": [
55
  {"id":"LongCat-Flash-Lite", "name":"LongCat Flash Lite", "context":"320K","speed":"⚑ Fastest","quota":"50M/day"},
56
  {"id":"LongCat-Flash-Chat", "name":"LongCat Flash Chat", "context":"256K","speed":"πŸš€ Fast", "quota":"500K/day"},
57
  {"id":"LongCat-Flash-Thinking-2601", "name":"LongCat Flash Thinking", "context":"256K","speed":"🧠 Deep", "quota":"500K/day"},
58
  ]}
59
 
60
+ @app.get("/api/builtin-tools")
61
+ def builtin_tools():
62
+ return {"tools":[
63
+ {"name":"datetime", "description":"Real system date & time", "icon":"πŸ•"},
64
+ {"name":"web_search", "description":"Real DuckDuckGo search", "icon":"πŸ”"},
65
+ {"name":"fetch_page", "description":"Real webpage content", "icon":"🌐"},
66
+ {"name":"run_python", "description":"Real Python code execution", "icon":"🐍"},
67
+ {"name":"voice", "description":"Real MP3 audio via gTTS", "icon":"πŸ”Š"},
68
+ {"name":"math", "description":"Real math & calculations", "icon":"πŸ”’"},
69
+ {"name":"qr_code", "description":"QR code generation", "icon":"πŸ“±"},
70
+ {"name":"charts", "description":"Charts & graphs via matplotlib","icon":"πŸ“Š"},
71
+ ]}
72
 
73
+ @app.get("/api/memory")
74
+ def get_memory():
75
+ from memory import get_all_for_api
76
+ return get_all_for_api()
77
+
78
+ @app.delete("/api/memory/{key}")
79
+ def delete_memory(key: str):
80
+ from memory import MEM_DIR
81
+ safe = "".join(c if c.isalnum() or c in "-_" else "_" for c in key)
82
+ path = MEM_DIR / f"{safe}.md"
83
+ if path.exists():
84
+ path.unlink()
85
+ return {"ok": True}
86
+ return {"ok": False, "detail": "Not found"}
87
+
88
+ @app.get("/api/skills")
89
+ def get_skills():
90
+ from memory import list_skills, load_skill
91
+ skills = list_skills()
92
+ for s in skills:
93
+ s["code"] = load_skill(s["name"])[:800]
94
+ return {"skills": skills}
95
+
96
+ @app.delete("/api/skills/{name}")
97
+ def delete_skill_route(name: str):
98
+ from memory import delete_skill
99
+ ok = delete_skill(name)
100
+ return {"ok": ok}
101
+
102
+
103
+ # ── Chat ───────────────────────────────────────────────────────
104
  @app.post("/api/chat")
105
  async def chat(request: Request):
106
  try:
107
  body = await request.json()
108
  except Exception:
109
+ return JSONResponse(status_code=400,
110
+ content={"ok":False,"detail":"Invalid JSON body"})
111
+
112
+ messages = body.get("messages", [])
113
  api_key = body.get("api_key","").strip() or cfg.get_longcat_key()
114
  model = body.get("model","LongCat-Flash-Lite")
115
+
116
  if not api_key:
117
+ return JSONResponse(status_code=400,
118
+ content={"ok":False,"detail":"LongCat API key required. Add it in Settings."})
119
  if not messages:
120
+ return JSONResponse(status_code=400,
121
+ content={"ok":False,"detail":"No messages provided"})
122
+
123
  if api_key != cfg.get_longcat_key(): cfg.set_longcat_key(api_key)
124
  if model != cfg.get_model(): cfg.set_model(model)
125
+
126
  user_message = messages[-1].get("content","")
127
  history = messages[:-1]
128
+
129
  async def stream():
130
+ async for chunk in orchestrator.stream_response(
131
+ user_message, history, api_key, model
132
+ ):
133
  yield f"data: {chunk}\n\n"
134
+
135
  return StreamingResponse(stream(), media_type="text/event-stream",
136
+ headers={"X-Accel-Buffering":"no","Cache-Control":"no-cache","Connection":"keep-alive"})
137
 
138
 
139
+ # ── Package installer ──────────────────────────────────────────
140
  @app.post("/api/install-package")
141
  async def install_package(request: Request):
142
+ try:
143
+ body = await request.json()
144
+ except Exception:
145
+ return JSONResponse(status_code=400, content={"ok":False,"detail":"Invalid JSON"})
146
+ packages = body.get("packages", [])
147
+ if not packages:
148
+ return JSONResponse(status_code=400, content={"ok":False,"detail":"No packages"})
149
  import asyncio
150
  loop = asyncio.get_event_loop()
151
  ok, msg = await loop.run_in_executor(None, pip_install, packages)
152
+ return {"ok": ok, "message": msg}
153
 
154
 
155
  # ── Telegram ───────────────────────────────────────────────────
 
159
  try:
160
  update = await request.json()
161
  except Exception:
162
+ return JSONResponse({"ok": True})
163
+
164
+ print(f"[WEBHOOK] {str(update)[:150]}")
165
  api_key = cfg.get_longcat_key()
166
  model = cfg.get_model()
167
+
168
  if not api_key:
169
+ msg = update.get("message", {})
170
+ chat_id = msg.get("chat", {}).get("id")
171
  if chat_id:
172
  from telegram_bot import send_message
173
+ await send_message(chat_id,
174
+ "⚠️ No API key saved. Open the web UI β†’ Settings β†’ save your LongCat key, "
175
+ "then re-connect Telegram.")
176
+ return JSONResponse({"ok": True})
177
+
178
  background_tasks.add_task(handle_update, update, api_key, model)
179
+ return JSONResponse({"ok": True})
180
 
181
 
182
  @app.post("/api/telegram/setup")
183
  async def telegram_setup(request: Request):
184
+ try:
185
+ body = await request.json()
186
+ except Exception:
187
+ return JSONResponse(status_code=400, content={"ok":False,"detail":"Invalid JSON"})
188
+
189
  token = body.get("token","").strip()
190
  base_url = body.get("base_url","").strip()
191
  api_key = body.get("api_key","").strip()
192
  model = body.get("model","").strip()
193
+
194
  if token: cfg.set_telegram_token(token)
195
  if api_key: cfg.set_longcat_key(api_key)
196
  if model: cfg.set_model(model)
197
+
198
  if not cfg.get_telegram_token():
199
+ return JSONResponse(status_code=400,
200
+ content={"ok":False,"detail":"No Telegram bot token provided"})
201
+
202
+ try:
203
+ from telegram_bot import get_bot_info, set_webhook
204
+ bot = await get_bot_info()
205
+ if not bot.get("ok"):
206
+ return JSONResponse(status_code=400,
207
+ content={"ok":False,"detail":f"Invalid bot token: {bot.get('description','')}"})
208
+
209
+ webhook_result = {}
210
+ if base_url:
211
+ webhook_result = await set_webhook(base_url)
212
+
213
+ return JSONResponse({"ok":True,
214
+ "bot":bot.get("result",{}),
215
+ "webhook":webhook_result})
216
+ except Exception as e:
217
+ return JSONResponse(status_code=500,
218
+ content={"ok":False,"detail":str(e)})
219
 
220
 
221
  @app.get("/api/telegram/status")
222
  async def telegram_status():
223
+ try:
224
+ token = cfg.get_telegram_token()
225
+ if not token:
226
+ return {"connected":False,"message":"No bot token set"}
227
+ from telegram_bot import get_bot_info, get_webhook_info
228
+ bot = await get_bot_info()
229
+ hook = await get_webhook_info()
230
+ return {"connected":bot.get("ok",False),
231
+ "bot":bot.get("result",{}),
232
+ "webhook":hook.get("result",{}),
233
+ "longcat_key_set":bool(cfg.get_longcat_key())}
234
+ except Exception as e:
235
+ return {"connected":False,"message":str(e)}
236
 
237
 
238
  @app.delete("/api/telegram/disconnect")
239
  async def telegram_disconnect():
240
+ try:
241
+ from telegram_bot import delete_webhook
242
+ result = await delete_webhook()
243
+ cfg.set("telegram_token","")
244
+ return {"ok":True,"result":result}
245
+ except Exception as e:
246
+ return JSONResponse(status_code=500, content={"ok":False,"detail":str(e)})