from __future__ import annotations import json from fastapi import FastAPI from sqlalchemy import select from services.shared.core import new_id, utc_now_iso from services.shared.db import get_session from services.shared.models import HealthResponse, WebchatMessageIn, WebchatMessageOut from services.shared.sql_init import init_sql_schema from services.shared.sql_models import Interaction, InteractionTimeline, WebchatMessageRow app = FastAPI(title="webchat-adapter-service", version="2.0.0") init_sql_schema() def _to_out(row: WebchatMessageRow) -> WebchatMessageOut: return WebchatMessageOut( message_id=row.message_id, session_id=row.session_id, text=row.text, visitor_name=row.visitor_name, customer_external_id=row.customer_external_id, queue_id=row.queue_id, priority=row.priority, payload=json.loads(row.payload_json or "{}"), interaction_id=row.interaction_id, created_at=row.created_at, ) def _interaction_subject(payload: WebchatMessageIn) -> str: subject = str(payload.payload.get("subject", "")).strip() if subject: return subject[:120] text = payload.text.strip() if len(text) <= 120: return text return f"{text[:117]}..." def _create_interaction(session, payload: WebchatMessageIn, created_at: str) -> str: interaction_id = new_id("int") session.add( Interaction( interaction_id=interaction_id, channel="webchat", subject=_interaction_subject(payload), customer_id=payload.customer_external_id, queue_id=payload.queue_id or "q_webchat", priority=payload.priority, status="new", assigned_to=None, created_at=created_at, updated_at=created_at, ) ) session.add( InteractionTimeline( interaction_id=interaction_id, timestamp=created_at, action="interaction.created", metadata_json=json.dumps({"channel": "webchat"}, ensure_ascii=False), ) ) session.add( InteractionTimeline( interaction_id=interaction_id, timestamp=created_at, action="webchat.message_received", metadata_json=json.dumps({"session_id": payload.session_id}, ensure_ascii=False), ) ) return interaction_id @app.get("/health", response_model=HealthResponse) def health() -> HealthResponse: return HealthResponse(status="ok", service="webchat-adapter-service", version="v2") @app.post("/integrations/webchat/messages", response_model=WebchatMessageOut) def create_message(payload: WebchatMessageIn) -> WebchatMessageOut: session = get_session() try: created_at = utc_now_iso() interaction_id = _create_interaction(session, payload, created_at) row = WebchatMessageRow( message_id=new_id("wcm"), session_id=payload.session_id, text=payload.text, visitor_name=payload.visitor_name, customer_external_id=payload.customer_external_id, interaction_id=interaction_id, queue_id=payload.queue_id or "q_webchat", priority=payload.priority, payload_json=json.dumps(payload.payload, ensure_ascii=False), created_at=created_at, ) session.add(row) session.commit() session.refresh(row) return _to_out(row) finally: session.close() @app.get("/integrations/webchat/messages", response_model=list[WebchatMessageOut]) def list_messages(session_id: str | None = None, limit: int = 100) -> list[WebchatMessageOut]: session = get_session() try: stmt = select(WebchatMessageRow).order_by(WebchatMessageRow.id.desc()) if session_id: stmt = stmt.where(WebchatMessageRow.session_id == session_id) rows = session.execute(stmt.limit(max(limit, 1))).scalars().all() return [_to_out(row) for row in reversed(rows)] finally: session.close()