From ec1c98592c1a862d72c43d32ba812ea7d377f3ae Mon Sep 17 00:00:00 2001 From: Fantix King Date: Tue, 23 Jun 2026 11:39:49 -0400 Subject: [PATCH] [websockets/fastapi-ai-chat] switch to use latest services --- websockets/fastapi-ai-chat/README.md | 5 ++-- websockets/fastapi-ai-chat/backend/main.py | 12 ++++---- .../fastapi-ai-chat/frontend/app/page.js | 4 +-- websockets/fastapi-ai-chat/vercel.json | 28 ++++++++++++++----- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/websockets/fastapi-ai-chat/README.md b/websockets/fastapi-ai-chat/README.md index 47d601beeb..1c4d315b03 100644 --- a/websockets/fastapi-ai-chat/README.md +++ b/websockets/fastapi-ai-chat/README.md @@ -1,13 +1,12 @@ # FastAPI AI Chat with WebSocket -A real-time AI chat application using **Next.js** (frontend), **FastAPI** (backend), **WebSocket** for streaming, and the [Python AI SDK](https://github.com/vercel-labs/ai-python) for LLM integration. Deployed on Vercel using [experimental services](https://vercel.com/docs/functions/experimental-services). +A real-time AI chat application using **Next.js** (frontend), **FastAPI** (backend), **WebSocket** for streaming, and the [Python AI SDK](https://github.com/vercel-labs/ai-python) for LLM integration. Deployed on Vercel using [Services](https://vercel.com/docs/services). ## How It Works - The **frontend** is a Next.js single-page app with a chat UI that connects to the backend via WebSocket. - The **backend** is a FastAPI server that accepts WebSocket connections, streams LLM responses using the Python AI SDK, and sends text deltas back to the client in real time. -- On Vercel, the frontend and backend run as separate services routed by path prefix (`/` and `/svc/api`). -- Python ASGI apps handle WebSocket upgrades natively on Vercel — no `experimental_upgradeWebSocket` workaround needed. +- On Vercel, the frontend and backend run as separate services routed by path prefix (`/` and `/api`). ## How to Use diff --git a/websockets/fastapi-ai-chat/backend/main.py b/websockets/fastapi-ai-chat/backend/main.py index c474a87a21..36b0d1e78e 100644 --- a/websockets/fastapi-ai-chat/backend/main.py +++ b/websockets/fastapi-ai-chat/backend/main.py @@ -1,8 +1,6 @@ import os -import fastapi - -import ai +import ai, fastapi app = fastapi.FastAPI() @@ -15,13 +13,15 @@ "system": ai.system_message, } +api = fastapi.APIRouter(prefix="/api") + -@app.get("/") +@api.get("/") async def health(): return {"status": "ok"} -@app.websocket("/ws") +@api.websocket("/ws") async def websocket_endpoint(websocket: fastapi.WebSocket): await websocket.accept() try: @@ -47,3 +47,5 @@ async def websocket_endpoint(websocket: fastapi.WebSocket): ) except fastapi.WebSocketDisconnect: pass + +app.include_router(api) diff --git a/websockets/fastapi-ai-chat/frontend/app/page.js b/websockets/fastapi-ai-chat/frontend/app/page.js index bd7eda6232..8e1d34d676 100644 --- a/websockets/fastapi-ai-chat/frontend/app/page.js +++ b/websockets/fastapi-ai-chat/frontend/app/page.js @@ -2,8 +2,6 @@ import { useState, useEffect, useRef } from "react"; -const BACKEND = process.env.NEXT_PUBLIC_BACKEND_URL || "/svc/api"; - export default function Chat() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); @@ -25,7 +23,7 @@ export default function Chat() { if (cancelled) return; const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; - const wsUrl = `${protocol}//${window.location.host}${BACKEND}/ws`; + const wsUrl = `${protocol}//${window.location.host}/api/ws`; setStatus("connecting"); const ws = new WebSocket(wsUrl); diff --git a/websockets/fastapi-ai-chat/vercel.json b/websockets/fastapi-ai-chat/vercel.json index 0eef6bd2ae..64e5e88e72 100644 --- a/websockets/fastapi-ai-chat/vercel.json +++ b/websockets/fastapi-ai-chat/vercel.json @@ -1,14 +1,28 @@ { - "experimentalServices": { + "rewrites": [ + { + "source": "/api/:path*", + "destination": { + "type": "service", + "service": "backend" + } + }, + { + "source": "/(.*)", + "destination": { + "type": "service", + "service": "frontend" + } + } + ], + "services": { "frontend": { - "framework": "nextjs", - "entrypoint": "frontend", - "routePrefix": "/" + "root": "frontend", + "framework": "nextjs" }, "backend": { - "framework": "fastapi", - "entrypoint": "backend/main.py", - "routePrefix": "/svc/api" + "root": "backend", + "framework": "fastapi" } } }