Aasher commited on
Commit
f6462a2
·
1 Parent(s): f45999f

feat(db): add chat and message models for conversation tracking

Browse files

Introduce 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.

Files changed (3) hide show
  1. .gitattributes +1 -0
  2. db/models/chat.py +22 -0
  3. 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")