Add backend api and engine
This commit is contained in:
165
api/app/models.py
Normal file
165
api/app/models.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
from sqlalchemy import String, Integer, DateTime, Text, Float, ForeignKey, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .db import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)
|
||||
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
class Voice(Base):
|
||||
__tablename__ = "voices"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
vendor: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
gender: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
language: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
description: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
voice_params: Mapped[dict] = mapped_column(JSON, default=dict)
|
||||
|
||||
|
||||
class Assistant(Base):
|
||||
__tablename__ = "assistants"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
call_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
opener: Mapped[str] = mapped_column(Text, default="")
|
||||
prompt: Mapped[str] = mapped_column(Text, default="")
|
||||
knowledge_base_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
language: Mapped[str] = mapped_column(String(16), default="zh")
|
||||
voice: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
speed: Mapped[float] = mapped_column(Float, default=1.0)
|
||||
hotwords: Mapped[dict] = mapped_column(JSON, default=list)
|
||||
tools: Mapped[dict] = mapped_column(JSON, default=list)
|
||||
interruption_sensitivity: Mapped[int] = mapped_column(Integer, default=500)
|
||||
config_mode: Mapped[str] = mapped_column(String(32), default="platform")
|
||||
api_url: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
||||
api_key: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
user = relationship("User")
|
||||
call_records = relationship("CallRecord", back_populates="assistant")
|
||||
|
||||
|
||||
class KnowledgeBase(Base):
|
||||
__tablename__ = "knowledge_bases"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, default="")
|
||||
embedding_model: Mapped[str] = mapped_column(String(64), default="text-embedding-3-small")
|
||||
chunk_size: Mapped[int] = mapped_column(Integer, default=500)
|
||||
chunk_overlap: Mapped[int] = mapped_column(Integer, default=50)
|
||||
doc_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
chunk_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
status: Mapped[str] = mapped_column(String(32), default="active")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
user = relationship("User")
|
||||
documents = relationship("KnowledgeDocument", back_populates="kb")
|
||||
|
||||
|
||||
class KnowledgeDocument(Base):
|
||||
__tablename__ = "knowledge_documents"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
kb_id: Mapped[str] = mapped_column(String(64), ForeignKey("knowledge_bases.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
size: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
file_type: Mapped[str] = mapped_column(String(32), default="txt")
|
||||
storage_url: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(32), default="pending") # pending/processing/completed/failed
|
||||
chunk_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
error_message: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
upload_date: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
processed_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
kb = relationship("KnowledgeBase", back_populates="documents")
|
||||
|
||||
|
||||
class Workflow(Base):
|
||||
__tablename__ = "workflows"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
node_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[str] = mapped_column(String(32), default="")
|
||||
updated_at: Mapped[str] = mapped_column(String(32), default="")
|
||||
global_prompt: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
nodes: Mapped[dict] = mapped_column(JSON, default=list)
|
||||
edges: Mapped[dict] = mapped_column(JSON, default=list)
|
||||
|
||||
user = relationship("User")
|
||||
|
||||
|
||||
class CallRecord(Base):
|
||||
__tablename__ = "call_records"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), index=True)
|
||||
assistant_id: Mapped[Optional[str]] = mapped_column(String(64), ForeignKey("assistants.id"), index=True)
|
||||
source: Mapped[str] = mapped_column(String(32), default="debug")
|
||||
status: Mapped[str] = mapped_column(String(32), default="connected")
|
||||
started_at: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
ended_at: Mapped[Optional[str]] = mapped_column(String(32), nullable=True)
|
||||
duration_seconds: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
cost: Mapped[float] = mapped_column(Float, default=0.0)
|
||||
call_metadata: Mapped[dict] = mapped_column(JSON, default=dict)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
user = relationship("User")
|
||||
assistant = relationship("Assistant", back_populates="call_records")
|
||||
transcripts = relationship("CallTranscript", back_populates="call_record")
|
||||
audio_segments = relationship("CallAudioSegment", back_populates="call_record")
|
||||
|
||||
|
||||
class CallTranscript(Base):
|
||||
__tablename__ = "call_transcripts"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
call_id: Mapped[str] = mapped_column(String(64), ForeignKey("call_records.id"), index=True)
|
||||
turn_index: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
speaker: Mapped[str] = mapped_column(String(16), nullable=False) # human/ai
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
confidence: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
||||
start_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
end_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
duration_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
emotion: Mapped[Optional[str]] = mapped_column(String(32), nullable=True)
|
||||
|
||||
call_record = relationship("CallRecord", back_populates="transcripts")
|
||||
|
||||
|
||||
class CallAudioSegment(Base):
|
||||
__tablename__ = "call_audio_segments"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
call_id: Mapped[str] = mapped_column(String(64), ForeignKey("call_records.id"), index=True)
|
||||
transcript_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("call_transcripts.id"), nullable=True)
|
||||
turn_index: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
audio_url: Mapped[str] = mapped_column(String(512), nullable=False)
|
||||
audio_format: Mapped[str] = mapped_column(String(16), default="mp3")
|
||||
file_size_bytes: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
start_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
end_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
duration_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
call_record = relationship("CallRecord", back_populates="audio_segments")
|
||||
Reference in New Issue
Block a user