Spaces:
Running
Running
Commit
·
7e89912
1
Parent(s):
1883e73
updated api routes
Browse files- backend/api.py +5 -49
- backend/app.py +1 -0
- ui/src/useChat.tsx +1 -1
backend/api.py
CHANGED
|
@@ -52,7 +52,7 @@ def _client_config():
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
-
@api.get("/oauth/google/start")
|
| 56 |
def oauth_start():
|
| 57 |
# optional CSRF protection
|
| 58 |
state = secrets.token_urlsafe(16)
|
|
@@ -65,7 +65,7 @@ def oauth_start():
|
|
| 65 |
# You can store `state` server-side if you validate it later
|
| 66 |
return RedirectResponse(url=auth_url)
|
| 67 |
|
| 68 |
-
@api.get("/oauth/google/callback")
|
| 69 |
def oauth_callback(request: Request):
|
| 70 |
# Exchange code for tokens
|
| 71 |
full_url = str(request.url) # includes ?code=...
|
|
@@ -76,57 +76,13 @@ def oauth_callback(request: Request):
|
|
| 76 |
TOKEN_FILE.write_text(creds.to_json())
|
| 77 |
return PlainTextResponse("Google Calendar connected. You can close this tab.")
|
| 78 |
|
| 79 |
-
@api.get("/health")
|
| 80 |
def health():
|
| 81 |
return {"ok": True}
|
| 82 |
|
| 83 |
-
async def _event_stream(thread_id: str, message: str, request: Request):
|
| 84 |
-
"""
|
| 85 |
-
Common generator for SSE. Emits:
|
| 86 |
-
- thread: thread_id to persist in the client
|
| 87 |
-
- token : streamed model text tokens
|
| 88 |
-
- done : end-of-stream sentinel
|
| 89 |
-
"""
|
| 90 |
-
config = {"configurable": {"thread_id": thread_id}}
|
| 91 |
-
|
| 92 |
-
# send thread id early so the client can store it immediately
|
| 93 |
-
yield {"event": "thread", "data": thread_id}
|
| 94 |
-
|
| 95 |
-
try:
|
| 96 |
-
# stream events directly from LangGraph
|
| 97 |
-
async for ev in lg_app.astream_events(
|
| 98 |
-
{"messages": [("user", message)]},
|
| 99 |
-
config=config,
|
| 100 |
-
version="v2",
|
| 101 |
-
):
|
| 102 |
-
# model token stream
|
| 103 |
-
if ev["event"] == "on_chat_model_stream":
|
| 104 |
-
chunk = ev["data"]["chunk"].content
|
| 105 |
-
# chunk can be a string, None, or (rarely) list of content parts
|
| 106 |
-
if isinstance(chunk, list):
|
| 107 |
-
text = "".join(getattr(p, "text", "") or str(p) for p in chunk)
|
| 108 |
-
else:
|
| 109 |
-
text = chunk or ""
|
| 110 |
-
if text:
|
| 111 |
-
yield {"event": "token", "data": text}
|
| 112 |
-
|
| 113 |
-
# (optional) forward tool results:
|
| 114 |
-
# if ev["event"] == "on_tool_end":
|
| 115 |
-
# tool_name = ev["name"]
|
| 116 |
-
# tool_out = ev["data"].get("output")
|
| 117 |
-
# yield {"event": "tool", "data": json.dumps({"name": tool_name, "output": tool_out})}
|
| 118 |
-
|
| 119 |
-
# stop if client disconnects
|
| 120 |
-
if await request.is_disconnected():
|
| 121 |
-
break
|
| 122 |
-
|
| 123 |
-
finally:
|
| 124 |
-
# explicit completion so the client can stop spinners immediately
|
| 125 |
-
yield {"event": "done", "data": "1"}
|
| 126 |
-
|
| 127 |
# --- GET route for EventSource (matches the React UI I gave you) ---
|
| 128 |
# GET
|
| 129 |
-
@api.get("/chat")
|
| 130 |
async def chat_get(
|
| 131 |
request: Request,
|
| 132 |
message: str = Query(...),
|
|
@@ -155,7 +111,7 @@ async def chat_get(
|
|
| 155 |
return EventSourceResponse(stream())
|
| 156 |
|
| 157 |
# POST
|
| 158 |
-
@api.post("/chat")
|
| 159 |
async def chat_post(request: Request):
|
| 160 |
body = await request.json()
|
| 161 |
message = body.get("message", "")
|
|
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
+
@api.get("api/oauth/google/start")
|
| 56 |
def oauth_start():
|
| 57 |
# optional CSRF protection
|
| 58 |
state = secrets.token_urlsafe(16)
|
|
|
|
| 65 |
# You can store `state` server-side if you validate it later
|
| 66 |
return RedirectResponse(url=auth_url)
|
| 67 |
|
| 68 |
+
@api.get("/api/oauth/google/callback")
|
| 69 |
def oauth_callback(request: Request):
|
| 70 |
# Exchange code for tokens
|
| 71 |
full_url = str(request.url) # includes ?code=...
|
|
|
|
| 76 |
TOKEN_FILE.write_text(creds.to_json())
|
| 77 |
return PlainTextResponse("Google Calendar connected. You can close this tab.")
|
| 78 |
|
| 79 |
+
@api.get("/api/health")
|
| 80 |
def health():
|
| 81 |
return {"ok": True}
|
| 82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
# --- GET route for EventSource (matches the React UI I gave you) ---
|
| 84 |
# GET
|
| 85 |
+
@api.get("/api/chat")
|
| 86 |
async def chat_get(
|
| 87 |
request: Request,
|
| 88 |
message: str = Query(...),
|
|
|
|
| 111 |
return EventSourceResponse(stream())
|
| 112 |
|
| 113 |
# POST
|
| 114 |
+
@api.post("api/chat")
|
| 115 |
async def chat_post(request: Request):
|
| 116 |
body = await request.json()
|
| 117 |
message = body.get("message", "")
|
backend/app.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from backend.api import api as app
|
ui/src/useChat.tsx
CHANGED
|
@@ -181,7 +181,7 @@ export function useChat() {
|
|
| 181 |
if (typeof window === "undefined") return; // SSR guard
|
| 182 |
|
| 183 |
// Start SSE
|
| 184 |
-
const url = new URL("/chat", window.location.origin);
|
| 185 |
url.searchParams.set("message", text);
|
| 186 |
url.searchParams.set("thread_id", thread_id);
|
| 187 |
|
|
|
|
| 181 |
if (typeof window === "undefined") return; // SSR guard
|
| 182 |
|
| 183 |
// Start SSE
|
| 184 |
+
const url = new URL("api/chat", window.location.origin);
|
| 185 |
url.searchParams.set("message", text);
|
| 186 |
url.searchParams.set("thread_id", thread_id);
|
| 187 |
|