Add conversation history management and API endpoints

- Introduce new database models for conversation sessions, messages, and artifacts to support conversation history tracking.
- Implement API routes for listing conversations and retrieving detailed conversation data, enhancing user interaction with historical records.
- Add a conversation recorder service to persist conversation messages in real-time without disrupting ongoing calls.
- Update the frontend to display conversation history, including filtering and sorting options, improving user experience.
- Enhance the pipeline to integrate conversation history recording seamlessly during interactions.
This commit is contained in:
Xin Wang
2026-07-10 16:25:06 +08:00
parent 5705726cfb
commit 059ad8162e
13 changed files with 1096 additions and 43 deletions

View File

@@ -9,7 +9,17 @@
from datetime import datetime
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, String, func
from sqlalchemy import (
JSON,
Boolean,
DateTime,
ForeignKey,
Integer,
String,
Text,
UniqueConstraint,
func,
)
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
@@ -187,3 +197,83 @@ class AssistantToolBinding(Base):
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
class ConversationSession(Base):
"""一次完整连接对应的对话会话;媒体文件以后作为 artifact 关联进来。"""
__tablename__ = "conversation_sessions"
id: Mapped[str] = mapped_column(String(40), primary_key=True)
assistant_id: Mapped[str | None] = mapped_column(
String(40),
ForeignKey("assistants.id", ondelete="SET NULL"),
nullable=True,
index=True,
)
assistant_name: Mapped[str] = mapped_column(String(128), default="")
channel: Mapped[str] = mapped_column(String(24), index=True)
runtime_mode: Mapped[str] = mapped_column(String(16), default="pipeline")
status: Mapped[str] = mapped_column(String(16), index=True, default="active")
message_count: Mapped[int] = mapped_column(Integer, default=0)
started_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), index=True
)
ended_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
extra: Mapped[dict] = mapped_column(JSONB, default=dict)
class ConversationMessage(Base):
"""会话中的有序消息;当前只写 text结构预留其他内容类型。"""
__tablename__ = "conversation_messages"
__table_args__ = (
UniqueConstraint(
"session_id", "sequence", name="uq_conversation_message_sequence"
),
)
id: Mapped[str] = mapped_column(String(40), primary_key=True)
session_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("conversation_sessions.id", ondelete="CASCADE"),
index=True,
)
sequence: Mapped[int] = mapped_column(Integer)
role: Mapped[str] = mapped_column(String(16))
content_type: Mapped[str] = mapped_column(String(16), default="text")
content: Mapped[str] = mapped_column(Text, default="")
occurred_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
extra: Mapped[dict] = mapped_column(JSONB, default=dict)
class ConversationArtifact(Base):
"""未来的音频、视频、图片等大对象索引;二进制本体不进入数据库。"""
__tablename__ = "conversation_artifacts"
id: Mapped[str] = mapped_column(String(40), primary_key=True)
session_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("conversation_sessions.id", ondelete="CASCADE"),
index=True,
)
message_id: Mapped[str | None] = mapped_column(
String(40),
ForeignKey("conversation_messages.id", ondelete="SET NULL"),
nullable=True,
index=True,
)
kind: Mapped[str] = mapped_column(String(16), index=True)
storage_uri: Mapped[str] = mapped_column(String(1024))
mime_type: Mapped[str] = mapped_column(String(128), default="")
size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True)
duration_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
extra: Mapped[dict] = mapped_column(JSONB, default=dict)