feat(db): add chat and message models for conversation tracking
Browse filesIntroduce SQLModel-based Chat and Message models to store conversation history. The Chat model tracks user conversations while the Message model stores individual messages with metadata including role, content, answer, and tool-related fields.
- .gitattributes +1 -0
- db/models/chat.py +22 -0
- db/models/message.py +33 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
db/models/chat.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from sqlmodel import Field, Relationship, SQLModel
|
| 4 |
+
from typing import TYPE_CHECKING, list
|
| 5 |
+
|
| 6 |
+
if TYPE_CHECKING:
|
| 7 |
+
from .message import Message
|
| 8 |
+
|
| 9 |
+
class Chat(SQLModel, table=True):
|
| 10 |
+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
|
| 11 |
+
user_id: uuid.UUID = Field(index=True)
|
| 12 |
+
title: str = Field(default="New Chat", max_length=100)
|
| 13 |
+
created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
| 14 |
+
updated_at: datetime = Field(
|
| 15 |
+
default_factory=datetime.utcnow,
|
| 16 |
+
nullable=False,
|
| 17 |
+
sa_column_kwargs={"onupdate": datetime.utcnow}
|
| 18 |
+
)
|
| 19 |
+
messages: list["Message"] = Relationship(
|
| 20 |
+
back_populates="chat",
|
| 21 |
+
sa_relationship_kwargs={"cascade": "all, delete-orphan"}
|
| 22 |
+
)
|
db/models/message.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from typing import Optional, Literal, Any, TYPE_CHECKING
|
| 4 |
+
from sqlmodel import Field, Relationship, SQLModel, JSON, Column
|
| 5 |
+
|
| 6 |
+
if TYPE_CHECKING:
|
| 7 |
+
from .chat import Chat
|
| 8 |
+
|
| 9 |
+
MessageRole = Literal["user", "assistant", "tool"]
|
| 10 |
+
|
| 11 |
+
class Message(SQLModel, table=True):
|
| 12 |
+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
|
| 13 |
+
chat_id: uuid.UUID = Field(foreign_key="chat.id", index=True)
|
| 14 |
+
role: MessageRole = Field(nullable=False)
|
| 15 |
+
|
| 16 |
+
# Stores the RAW, full text content.
|
| 17 |
+
# e.g., "The answer is... Links: [http://...]"
|
| 18 |
+
content: Optional[str] = Field(default=None, sa_column_kwargs={"longtext": True})
|
| 19 |
+
|
| 20 |
+
# Stores the CLEAN, parsed answer for display on the frontend.
|
| 21 |
+
# Populated only for the final AI message of a turn.
|
| 22 |
+
answer: Optional[str] = Field(default=None, sa_column_kwargs={"longtext": True})
|
| 23 |
+
|
| 24 |
+
# Stores the parsed source links for the frontend.
|
| 25 |
+
links: Optional[list[str]] = Field(default=None, sa_column=Column(JSON))
|
| 26 |
+
|
| 27 |
+
# Fields for tool-calling content
|
| 28 |
+
tool_calls: Optional[list[dict[str, Any]]] = Field(default=None, sa_column=Column(JSON))
|
| 29 |
+
tool_call_id: Optional[str] = Field(default=None, index=True)
|
| 30 |
+
|
| 31 |
+
created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
| 32 |
+
|
| 33 |
+
chat: Optional["Chat"] = Relationship(back_populates="messages")
|