Files
ai-video-fullstack/backend/db/models.py
Xin Wang 01c563a3e7 Add turn configuration support for assistants
- Introduce a new `turnConfig` field in `AssistantConfig` and `Assistant` models to manage user interaction settings.
- Implement `TurnConfig`, `BargeInConfig`, `VadConfig`, and `TurnDetectionConfig` schemas to define turn management strategies.
- Update the backend to handle turn configuration in the database and during assistant operations.
- Enhance frontend components with a `TurnConfigEditor` for configuring turn settings, including VAD and barge-in strategies.
- Modify existing pages to integrate turn configuration, improving user experience and interaction capabilities.
2026-07-12 11:08:19 +08:00

281 lines
11 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.
"""数据表定义(SQLAlchemy 2.0)。
模型注册表由接口定义驱动:
- InterfaceDefinition:具体接入协议及其动态表单字段
- ModelResource:模型配置与鉴权值
- AssistantModelBinding:助手按能力选择模型资源
"""
from datetime import datetime
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
class Base(DeclarativeBase):
pass
class InterfaceDefinition(Base):
"""具体接入协议,例如 xfyun-tts 与 xfyun-super-tts。"""
__tablename__ = "interface_definitions"
interface_type: Mapped[str] = mapped_column(String(64), primary_key=True)
name: Mapped[str] = mapped_column(String(128))
capability: Mapped[str] = mapped_column(String(16), index=True)
field_schema: Mapped[dict] = mapped_column(JSONB, default=dict)
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
version: Mapped[int] = mapped_column(default=1)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class ModelResource(Base):
"""统一模型资源:接口类型决定能力、鉴权字段和调用参数。"""
__tablename__ = "model_resources"
id: Mapped[str] = mapped_column(String(40), primary_key=True)
name: Mapped[str] = mapped_column(String(128), default="")
capability: Mapped[str] = mapped_column(String(16), index=True)
interface_type: Mapped[str] = mapped_column(
String(64),
ForeignKey("interface_definitions.interface_type", ondelete="RESTRICT"),
index=True,
)
values: Mapped[dict] = mapped_column(JSONB, default=dict)
secrets: Mapped[dict] = mapped_column(JSONB, default=dict)
support_image_input: Mapped[bool] = mapped_column(Boolean, default=False)
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
is_default: Mapped[bool] = mapped_column(Boolean, default=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class KnowledgeBase(Base):
"""知识库注册表。本身引用一个 Embedding 模型资源。
文档/分块(pgvector)是 KB 内部实现,这里先不展开;助手侧只认 knowledge_base_id。
"""
__tablename__ = "knowledge_bases"
id: Mapped[str] = mapped_column(String(40), primary_key=True) # kb_xxx
name: Mapped[str] = mapped_column(String(128))
description: Mapped[str] = mapped_column(String(2048), default="")
embedding_model_resource_id: Mapped[str | None] = mapped_column(
String(40),
ForeignKey("model_resources.id", ondelete="SET NULL"),
index=True,
nullable=True,
)
status: Mapped[str] = mapped_column(String(16), default="active") # active|archived
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class Assistant(Base):
"""助手(单表,无版本化)。type 为可变普通列,5 种类型共用此表。
模型/KB 以 FK 引用注册表;类型专属字段塞进 config(JSON)。
"""
__tablename__ = "assistants"
id: Mapped[str] = mapped_column(String(40), primary_key=True) # asst_xxx
name: Mapped[str] = mapped_column(String(128))
# prompt|workflow|dify|fastgpt|opencode;创建后可改
type: Mapped[str] = mapped_column(String(16), index=True, default="prompt")
runtime_mode: Mapped[str] = mapped_column(String(16), default="pipeline")
greeting: Mapped[str] = mapped_column(String(2048), default="")
enable_interrupt: Mapped[bool] = mapped_column(Boolean, default=True)
turn_config: Mapped[dict] = mapped_column(JSON, default=dict)
vision_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
vision_model_resource_id: Mapped[str | None] = mapped_column(
String(40),
ForeignKey("model_resources.id", ondelete="SET NULL"),
nullable=True,
)
# KB 引用:被引用时禁止删 KB(RESTRICT),无默认兜底
knowledge_base_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("knowledge_bases.id", ondelete="RESTRICT"), nullable=True
)
# ---- 瘦类型专属字段(真列,稀疏:按 type 用其中几列) ----
prompt: Mapped[str] = mapped_column(String(8192), default="") # prompt / opencode
api_url: Mapped[str] = mapped_column(String(512), default="") # dify / fastgpt / opencode
api_key: Mapped[str] = mapped_column(String(512), default="") # dify / fastgpt / opencode(打码/哨兵)
app_id: Mapped[str] = mapped_column(String(128), default="") # fastgpt
# workflow 专属:图(nodes/edges)。要版本化时再迁出到 assistant_workflow 表
graph: Mapped[dict] = mapped_column(JSON, default=dict)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class AssistantModelBinding(Base):
"""助手按能力绑定统一模型资源config 可覆盖资源默认 options。"""
__tablename__ = "assistant_model_bindings"
assistant_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("assistants.id", ondelete="CASCADE"),
primary_key=True,
)
capability: Mapped[str] = mapped_column(String(16), primary_key=True)
model_resource_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("model_resources.id", ondelete="RESTRICT"),
index=True,
)
config: Mapped[dict] = mapped_column(JSONB, default=dict)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class Tool(Base):
"""Reusable LLM tool definition; supported types are executed at runtime."""
__tablename__ = "tools"
id: Mapped[str] = mapped_column(String(40), primary_key=True)
name: Mapped[str] = mapped_column(String(128))
function_name: Mapped[str] = mapped_column(String(64), unique=True, index=True)
type: Mapped[str] = mapped_column(String(24), index=True)
description: Mapped[str] = mapped_column(String(2048), default="")
definition: Mapped[dict] = mapped_column(JSONB, default=dict)
secrets: Mapped[dict] = mapped_column(JSONB, default=dict)
status: Mapped[str] = mapped_column(String(16), index=True, default="active")
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class AssistantToolBinding(Base):
"""Prompt assistant to reusable tool many-to-many binding."""
__tablename__ = "assistant_tool_bindings"
assistant_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("assistants.id", ondelete="CASCADE"),
primary_key=True,
)
tool_id: Mapped[str] = mapped_column(
String(40),
ForeignKey("tools.id", ondelete="RESTRICT"),
primary_key=True,
index=True,
)
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)