Spaces:
Restarting
Restarting
| """Author RAG Chatbot SaaS β Chatbot API Schemas.""" | |
| from pydantic import BaseModel, EmailStr, Field | |
| class ChatRequest(BaseModel): | |
| """Incoming chat message from the widget.""" | |
| session_id: str | |
| message: str = Field(..., min_length=1, max_length=2000) | |
| selected_book_id: str | None = None | |
| ask_all_books: bool = False | |
| class LinkItem(BaseModel): | |
| label: str | |
| url: str | |
| type: str | |
| icon: str | |
| class BookSelectorItem(BaseModel): | |
| id: str | |
| title: str | |
| tagline: str | None | |
| cover_url: str | None | |
| class ChatResponse(BaseModel): | |
| """Response from one chat turn.""" | |
| text: str | |
| links: list[LinkItem] = [] | |
| has_links: bool = False | |
| book_selector: list[BookSelectorItem] | None = None | |
| session_id: str | |
| intent: str = "question" | |
| follow_ups: list[str] = [] | |
| class BookInfo(BaseModel): | |
| id: str | |
| title: str | |
| tagline: str | None | |
| cover_path: str | None | |
| ai_summary: str | None = None | |
| purchase_url: str | None = None | |
| class FarewellRequest(BaseModel): | |
| session_id: str | |
| selected_book_id: str | None = None | |
| class SessionInitRequest(BaseModel): | |
| """Optional body for session/init β carries the visitor_uid from widget localStorage. | |
| The widget sends the visitor_uid it stored on the previous visit. | |
| If absent or null, the server generates a new one (first visit). | |
| HF Spaces note: Using request body instead of cookies because | |
| the widget runs inside an iframe (third-party context) where | |
| cookies are blocked by Safari ITP and Firefox ETP. | |
| """ | |
| visitor_uid: str | None = Field( | |
| default=None, | |
| min_length=36, | |
| max_length=36, | |
| description="UUID previously returned by session/init and stored in widget localStorage.", | |
| ) | |
| visitor_name: str | None = Field( | |
| default=None, | |
| min_length=1, | |
| max_length=100, | |
| description="Visitor display name collected before first chat.", | |
| ) | |
| visitor_email: EmailStr | None = Field( | |
| default=None, | |
| description="Visitor email collected before first chat.", | |
| ) | |
| class WidgetAppearanceResponse(BaseModel): | |
| """Subscription-authenticated widget chrome (theme/position/auto-open). | |
| Used before chat opens so the bubble matches Widget Config without | |
| creating a session (profile gate may block session/init). | |
| """ | |
| bot_name: str | |
| widget_theme: str | |
| widget_position: str | |
| widget_auto_open_delay: int = 0 | |
| require_visitor_profile: bool = True | |
| class SessionInitResponse(BaseModel): | |
| """Response from session initialization.""" | |
| session_id: str | |
| bot_name: str | |
| welcome_message: str | |
| widget_theme: str | |
| widget_position: str = "bottom-right" | |
| widget_auto_open_delay: int = 0 | |
| books: list[BookInfo] | |
| show_book_selector: bool | |
| visitor_uid: str | |
| require_visitor_profile: bool = True | |
| profile_complete: bool = True | |
| visitor_name: str | None = None | |
| visitor_email: str | None = None | |
| remove_branding: bool = False | |
| custom_widget_css: str | None = None | |
| # ββ Phase 7: Polling Streaming ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class StreamStartResponse(BaseModel): | |
| """Returned immediately when a streaming job is queued. | |
| Phase 7: Replaces SSE (blocked by nginx). Widget polls /poll/{job_id} | |
| until status='done', then renders the full response. | |
| """ | |
| job_id: str | |
| status: str = "queued" | |
| class PollResponse(BaseModel): | |
| """Returned on each poll of /poll/{job_id}. | |
| status: 'pending' | 'done' | 'error' | |
| result: only present when status='done' | |
| error: only present when status='error' | |
| """ | |
| job_id: str | |
| status: str | |
| result: ChatResponse | None = None | |
| error: str | None = None | |
| # ββ Visitor Interaction Schemas (Phase 6B for chat.py) βββββββββββββββββββββββ | |
| class TrackClickRequest(BaseModel): | |
| """Track purchase/preview link click.""" | |
| session_id: str | None = None | |
| book_id: str | None = None | |
| link_type: str = "unknown" | |
| class FeedbackRequest(BaseModel): | |
| """Thumbs up/down on a bot message.""" | |
| session_id: str | None = None | |
| message_index: int | None = Field(None, ge=0) | |
| reaction: str = Field(..., pattern=r"^(up|down)$") | |
| class RateSessionRequest(BaseModel): | |
| """Star rating for a chat session.""" | |
| session_id: str | None = None | |
| rating: int = Field(..., ge=1, le=5) | |