Terminal / api /conversations.py
Pulka
feat(sync): backend 2026-06-16 — telegram router + telemetry + B10/B11
6787641 verified
Raw
History Blame Contribute Delete
4.24 kB
"""backend/api/conversations.py — Conversations + Messages CRUD (S354)."""
import json, logging
from .state import safe_json_dumps
from typing import Optional, Any
from fastapi import APIRouter, Body, HTTPException
from pydantic import BaseModel
from .state import sb
router = APIRouter()
_logger = logging.getLogger("conversations")
class ConversationIn(BaseModel):
id: str
title: str = 'Nuova conversazione'
created_at: int
updated_at: int
class MessageIn(BaseModel):
id: str
conversation_id: str
role: str
content: str
created_at: int
error: Optional[bool] = False
steps: Optional[Any] = None
agent_status: Optional[str] = None
# ── Conversations ──────────────────────────────────────────────────────────────
@router.get('/api/conversations')
async def list_conversations():
try:
data = sb().table('conversations').select('*').order('updated_at', desc=True).execute()
return {'conversations': data.data}
except Exception as exc:
_logger.warning("list_conversations: %s", exc)
# S750-GAP-I: Supabase non configurato o irraggiungibile → lista vuota invece di 500
return {'conversations': [], '_error': str(exc)[:120]}
@router.post('/api/conversations')
async def upsert_conversation(conv: ConversationIn):
try:
data = sb().table('conversations').upsert(conv.model_dump()).execute()
return {'conversation': data.data[0] if data.data else conv.model_dump()}
except Exception as exc:
_logger.warning("upsert_conversation %s: %s", conv.id, exc)
return {'conversation': conv.model_dump(), '_error': str(exc)[:120]}
@router.put('/api/conversations/{conv_id}')
async def update_conversation(conv_id: str, body: dict = Body(...)):
body['id'] = conv_id
try:
data = sb().table('conversations').upsert(body).execute()
return {'conversation': data.data[0] if data.data else body}
except Exception as exc:
_logger.warning("update_conversation %s: %s", conv_id, exc)
return {'conversation': body, '_error': str(exc)[:120]}
@router.delete('/api/conversations/{conv_id}')
async def delete_conversation(conv_id: str):
try:
sb().table('messages').delete().eq('conversation_id', conv_id).execute()
sb().table('conversations').delete().eq('id', conv_id).execute()
except Exception as exc:
_logger.warning("delete_conversation %s: %s", conv_id, exc)
return {'deleted': conv_id}
# ── Messages ───────────────────────────────────────────────────────────────────
@router.get('/api/conversations/{conv_id}/messages')
async def list_messages(conv_id: str):
try:
data = sb().table('messages').select('*').eq('conversation_id', conv_id).order('created_at').execute()
return {'messages': data.data}
except Exception as exc:
_logger.warning("list_messages %s: %s", conv_id, exc)
return {'messages': [], '_error': str(exc)[:120]}
@router.post('/api/conversations/{conv_id}/messages')
async def upsert_messages(conv_id: str, body: dict = Body(...)):
msgs = body.get('messages', [])
if not msgs:
return {'upserted': 0}
for m in msgs:
m['conversation_id'] = conv_id
if 'steps' in m and m['steps'] is not None:
m['steps'] = safe_json_dumps(m['steps']) if not isinstance(m['steps'], str) else m['steps']
try:
data = sb().table('messages').upsert(msgs).execute()
return {'upserted': len(data.data)}
except Exception as exc:
_logger.warning("upsert_messages %s: %s", conv_id, exc)
return {'upserted': 0, '_error': str(exc)[:120]}
@router.delete('/api/conversations/{conv_id}/messages')
async def clear_messages(conv_id: str):
try:
sb().table('messages').delete().eq('conversation_id', conv_id).execute()
except Exception as exc:
_logger.warning("clear_messages %s: %s", conv_id, exc)
return {'cleared': conv_id}