Files
life-echo/api/app/features/conversation/models.py

83 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from sqlalchemy import (
JSON,
Boolean,
Column,
DateTime,
ForeignKey,
Integer,
String,
Text,
)
from sqlalchemy.orm import relationship
from app.core.db import Base, utc_now
class Conversation(Base):
__tablename__ = "conversations"
id = Column(String, primary_key=True)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
started_at = Column(DateTime(timezone=True), default=utc_now)
last_message_at = Column(DateTime(timezone=True), nullable=True)
ended_at = Column(DateTime(timezone=True), nullable=True)
duration_seconds = Column(Integer, default=0)
summary = Column(Text, nullable=True)
status = Column(String, default="active")
current_topic = Column(String, nullable=True)
conversation_stage = Column(String, nullable=True)
deleted_at = Column(DateTime(timezone=True), nullable=True)
user = relationship("User", back_populates="conversations")
segments = relationship(
"Segment", back_populates="conversation", cascade="all, delete-orphan"
)
messages = relationship(
"ConversationMessage",
back_populates="conversation",
cascade="all, delete-orphan",
)
class Segment(Base):
__tablename__ = "segments"
id = Column(String, primary_key=True)
conversation_id = Column(String, ForeignKey("conversations.id"), nullable=False)
audio_url = Column(String, nullable=True)
# 用户输入正文:语音 ASR 结果或键盘输入(历史列名 transcript_text
user_input_text = Column(Text, nullable=False)
audio_duration_seconds = Column(Integer, nullable=True)
created_at = Column(DateTime(timezone=True), default=utc_now)
processed = Column(Boolean, default=False)
# Phase 1 分类结果(回忆录 chapter 类目);非空表示 Phase 1 已完成
topic_category = Column(String, nullable=True)
# Phase 2 已消费该段并完成叙事落库
narrated = Column(Boolean, default=False, server_default="false")
# Phase 1 判定无需进故事管线(无 slots 且 LLM 判 none
skip_narrative = Column(Boolean, default=False, server_default="false")
agent_response = Column(Text, nullable=True)
tts_audio_urls = Column(JSON, nullable=True)
conversation = relationship("Conversation", back_populates="segments")
class ConversationMessage(Base):
"""durable turn log aligned with Redis history shape (canonical chat source of truth)."""
__tablename__ = "conversation_messages"
id = Column(String, primary_key=True)
conversation_id = Column(String, ForeignKey("conversations.id"), nullable=False)
role = Column(String, nullable=False) # human / ai
content = Column(Text, nullable=False)
message_type = Column(String, nullable=False, default="text")
voice_session_id = Column(String, nullable=True)
duration_seconds = Column(Integer, nullable=True)
tts_audio_urls = Column(JSON, nullable=True)
segment_id = Column(String, ForeignKey("segments.id"), nullable=True)
created_at = Column(DateTime(timezone=True), default=utc_now)
conversation = relationship("Conversation", back_populates="messages")
segment = relationship("Segment", foreign_keys=[segment_id])