Spaces:
Running
Running
| """Author RAG — Widget Token API. | |
| Routes (per implementation plan): | |
| GET /api/widget/token?slug={author_slug}&domain={domain} | |
| GET /api/widget/{author_slug} — Serves embeddable widget HTML | |
| RULE: Token must be verified on every widget chat request. | |
| """ | |
| from pathlib import Path | |
| from fastapi import APIRouter, HTTPException, Query | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from app.core.security import sign_widget_token, verify_widget_token | |
| router = APIRouter() | |
| WIDGET_HTML = Path(__file__).resolve().parent.parent.parent / "static" / "addon.html" | |
| async def get_widget_token( | |
| slug: str = Query(..., description="Author slug"), | |
| domain: str = Query(..., description="Author's website domain"), | |
| ): | |
| """Generate a signed HMAC widget token for embedding. | |
| The token encodes the author slug and allowed domain. | |
| Embed via: <script src=".../static/widget.js" data-token="TOKEN"> | |
| """ | |
| token = sign_widget_token(slug, domain) | |
| return {"token": token, "author_slug": slug, "domain": domain} | |
| async def get_widget_page(author_slug: str): | |
| """Serve the embeddable widget HTML page for an author.""" | |
| if not WIDGET_HTML.is_file(): | |
| raise HTTPException(404, "Widget not found") | |
| return FileResponse( | |
| WIDGET_HTML, | |
| headers={ | |
| "Cache-Control": "no-cache, no-store, must-revalidate", | |
| }, | |
| ) | |