Update app/main.py
Browse files- app/main.py +66 -92
app/main.py
CHANGED
|
@@ -4,13 +4,12 @@ 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 agent_system import orchestrator
|
| 8 |
-
from
|
| 9 |
|
| 10 |
-
app = FastAPI(title="PraisonChat", version="
|
| 11 |
-
|
| 12 |
-
app.add_middleware(CORSMiddleware, allow_origins=["*"],
|
| 13 |
-
allow_methods=["*"], allow_headers=["*"])
|
| 14 |
|
| 15 |
STATIC_DIR = Path(__file__).parent / "static"
|
| 16 |
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
|
@@ -18,144 +17,119 @@ app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
|
| 18 |
|
| 19 |
@app.get("/", response_class=HTMLResponse)
|
| 20 |
async def root():
|
| 21 |
-
return HTMLResponse(
|
| 22 |
|
| 23 |
|
| 24 |
@app.get("/api/health")
|
| 25 |
def health():
|
| 26 |
-
return {"status":
|
|
|
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
@app.get("/api/models")
|
| 30 |
def models():
|
| 31 |
-
return {"models":
|
| 32 |
-
{"id":"LongCat-Flash-Lite", "name":"LongCat Flash Lite",
|
| 33 |
-
{"id":"LongCat-Flash-Chat", "name":"LongCat Flash Chat",
|
| 34 |
-
{"id":"LongCat-Flash-Thinking-2601", "name":"LongCat Flash Thinking",
|
| 35 |
]}
|
| 36 |
|
| 37 |
|
| 38 |
-
@app.get("/api/builtin-tools")
|
| 39 |
-
def builtin_tools():
|
| 40 |
-
items = [
|
| 41 |
-
{"name":"get_current_datetime","description":"Real system date & time","icon":"π"},
|
| 42 |
-
{"name":"search_web", "description":"Real DuckDuckGo search", "icon":"π"},
|
| 43 |
-
{"name":"fetch_webpage", "description":"Real webpage content fetch","icon":"π"},
|
| 44 |
-
{"name":"run_python_code", "description":"Real Python execution", "icon":"π"},
|
| 45 |
-
{"name":"create_voice", "description":"Real MP3 audio via gTTS", "icon":"π"},
|
| 46 |
-
{"name":"calculate", "description":"Real math evaluation", "icon":"π’"},
|
| 47 |
-
]
|
| 48 |
-
return {"tools": items}
|
| 49 |
-
|
| 50 |
-
|
| 51 |
@app.post("/api/chat")
|
| 52 |
async def chat(request: Request):
|
| 53 |
try:
|
| 54 |
body = await request.json()
|
| 55 |
except Exception:
|
| 56 |
-
raise HTTPException(400, "Invalid JSON
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
api_key = body.get("api_key") or os.getenv("LONGCAT_API_KEY","")
|
| 60 |
model = body.get("model","LongCat-Flash-Lite")
|
| 61 |
-
|
| 62 |
if not api_key:
|
| 63 |
-
raise HTTPException(400,
|
| 64 |
if not messages:
|
| 65 |
-
raise HTTPException(400,
|
| 66 |
-
|
|
|
|
| 67 |
user_message = messages[-1].get("content","")
|
| 68 |
history = messages[:-1]
|
| 69 |
-
|
| 70 |
async def stream():
|
| 71 |
async for chunk in orchestrator.stream_response(user_message, history, api_key, model):
|
| 72 |
yield f"data: {chunk}\n\n"
|
| 73 |
-
|
| 74 |
return StreamingResponse(stream(), media_type="text/event-stream",
|
| 75 |
headers={"X-Accel-Buffering":"no","Cache-Control":"no-cache"})
|
| 76 |
|
| 77 |
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
|
|
|
|
|
|
| 82 |
@app.post("/telegram/webhook")
|
| 83 |
async def telegram_webhook(request: Request, background_tasks: BackgroundTasks):
|
| 84 |
-
|
| 85 |
-
from telegram_bot import handle_telegram_update
|
| 86 |
try:
|
| 87 |
update = await request.json()
|
| 88 |
except Exception:
|
| 89 |
-
return JSONResponse({"ok":
|
| 90 |
-
|
| 91 |
-
api_key =
|
| 92 |
-
model =
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
|
| 100 |
@app.post("/api/telegram/setup")
|
| 101 |
async def telegram_setup(request: Request):
|
| 102 |
-
"""Set up the Telegram webhook."""
|
| 103 |
from telegram_bot import set_webhook, get_bot_info
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
if
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
if not
|
| 116 |
-
raise HTTPException(400,
|
| 117 |
-
|
| 118 |
-
bot_info = await get_bot_info()
|
| 119 |
-
if not bot_info.get("ok"):
|
| 120 |
-
raise HTTPException(400, f"Invalid bot token: {bot_info}")
|
| 121 |
-
|
| 122 |
if base_url:
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
return {"ok":True,"bot":bot_info.get("result",{})}
|
| 127 |
|
| 128 |
|
| 129 |
@app.get("/api/telegram/status")
|
| 130 |
async def telegram_status():
|
| 131 |
-
"""Get Telegram bot status."""
|
| 132 |
from telegram_bot import get_webhook_info, get_bot_info
|
| 133 |
-
token =
|
| 134 |
if not token:
|
| 135 |
-
return {"connected":
|
| 136 |
bot = await get_bot_info()
|
| 137 |
hook = await get_webhook_info()
|
| 138 |
-
return {
|
| 139 |
-
|
| 140 |
-
"bot": bot.get("result",{}),
|
| 141 |
-
"webhook": hook.get("result",{}),
|
| 142 |
-
}
|
| 143 |
|
| 144 |
|
| 145 |
@app.delete("/api/telegram/disconnect")
|
| 146 |
async def telegram_disconnect():
|
| 147 |
from telegram_bot import delete_webhook
|
| 148 |
result = await delete_webhook()
|
| 149 |
-
|
| 150 |
-
return {"ok":True,"result":result}
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
@app.post("/api/install-package")
|
| 154 |
-
async def install_package(request: Request):
|
| 155 |
-
"""Manually install a Python package into the agent environment."""
|
| 156 |
-
body = await request.json()
|
| 157 |
-
packages = body.get("packages",[])
|
| 158 |
-
if not packages:
|
| 159 |
-
raise HTTPException(400,"No packages specified")
|
| 160 |
-
ok, msg = pip_install(packages)
|
| 161 |
-
return {"ok":ok,"message":msg}
|
|
|
|
| 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")
|
|
|
|
| 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 βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 75 |
@app.post("/telegram/webhook")
|
| 76 |
async def telegram_webhook(request: Request, background_tasks: BackgroundTasks):
|
| 77 |
+
from telegram_bot import handle_update
|
|
|
|
| 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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|