Skip to content

Commit ec89517

Browse files
committed
character and conversation models with relationships to user, enabling character creation and conversation management. added message model for handling conversation messages.
1 parent df47210 commit ec89517

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

backend/app/models.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import uuid
2+
import datetime
3+
from enum import Enum
24

35
from pydantic import EmailStr
46
from sqlmodel import Field, Relationship, SQLModel
@@ -44,6 +46,12 @@ class User(UserBase, table=True):
4446
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
4547
hashed_password: str
4648
items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)
49+
created_characters: list["Character"] = Relationship(
50+
back_populates="creator", cascade_delete=True
51+
)
52+
conversations: list["Conversation"] = Relationship(
53+
back_populates="user", cascade_delete=True
54+
)
4755

4856

4957
# Properties to return via API, id is always required
@@ -111,3 +119,126 @@ class TokenPayload(SQLModel):
111119
class NewPassword(SQLModel):
112120
token: str
113121
new_password: str = Field(min_length=8, max_length=40)
122+
123+
124+
# Shared properties
125+
class CharacterBase(SQLModel):
126+
name: str = Field(index=True, max_length=100)
127+
description: str | None = Field(default=None, max_length=1000)
128+
image_url: str | None = Field(default=None, max_length=255)
129+
greeting_message: str | None = Field(default=None, max_length=1000)
130+
131+
132+
class CharacterStatus(str, Enum):
133+
PENDING = "pending"
134+
APPROVED = "approved"
135+
REJECTED = "rejected"
136+
137+
138+
# Properties to receive via API on creation (user submission)
139+
class CharacterCreate(CharacterBase):
140+
pass
141+
142+
143+
# Properties to receive via API on update (admin only)
144+
class CharacterUpdate(CharacterBase):
145+
name: str | None = Field(default=None, max_length=100)
146+
description: str | None = Field(default=None, max_length=1000)
147+
image_url: str | None = Field(default=None, max_length=255)
148+
greeting_message: str | None = Field(default=None, max_length=1000)
149+
status: CharacterStatus | None = None
150+
151+
152+
# Database model
153+
class Character(CharacterBase, table=True):
154+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
155+
status: CharacterStatus = Field(default=CharacterStatus.PENDING)
156+
creator_id: uuid.UUID = Field(foreign_key="user.id", nullable=False)
157+
158+
creator: User = Relationship(back_populates="created_characters")
159+
conversations: list["Conversation"] = Relationship(back_populates="character")
160+
161+
162+
# Properties to return via API
163+
class CharacterPublic(CharacterBase):
164+
id: uuid.UUID
165+
status: CharacterStatus
166+
creator_id: uuid.UUID
167+
168+
169+
class CharactersPublic(SQLModel):
170+
data: list[CharacterPublic]
171+
count: int
172+
173+
174+
# ---------------- Conversation Models ----------------
175+
176+
177+
class ConversationBase(SQLModel):
178+
pass # No shared fields initially, maybe add title later?
179+
180+
181+
class ConversationCreate(SQLModel):
182+
character_id: uuid.UUID
183+
184+
185+
# Database model
186+
class Conversation(ConversationBase, table=True):
187+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
188+
user_id: uuid.UUID = Field(foreign_key="user.id", nullable=False)
189+
character_id: uuid.UUID = Field(foreign_key="character.id", nullable=False)
190+
created_at: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
191+
192+
user: User = Relationship(back_populates="conversations")
193+
character: Character = Relationship(back_populates="conversations")
194+
messages: list["Message"] = Relationship(back_populates="conversation")
195+
196+
197+
class ConversationPublic(ConversationBase):
198+
id: uuid.UUID
199+
user_id: uuid.UUID
200+
character_id: uuid.UUID
201+
created_at: datetime.datetime
202+
203+
204+
class ConversationsPublic(SQLModel):
205+
data: list[ConversationPublic]
206+
count: int
207+
208+
209+
# ---------------- Message Models ----------------
210+
211+
212+
class MessageSender(str, Enum):
213+
USER = "user"
214+
AI = "ai"
215+
216+
217+
class MessageBase(SQLModel):
218+
content: str = Field(max_length=5000) # Limit message length
219+
220+
221+
class MessageCreate(MessageBase):
222+
pass # Content is the main input
223+
224+
225+
# Database model
226+
class Message(MessageBase, table=True):
227+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
228+
conversation_id: uuid.UUID = Field(foreign_key="conversation.id", nullable=False)
229+
sender: MessageSender
230+
timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
231+
232+
conversation: Conversation = Relationship(back_populates="messages")
233+
234+
235+
class MessagePublic(MessageBase):
236+
id: uuid.UUID
237+
conversation_id: uuid.UUID
238+
sender: MessageSender
239+
timestamp: datetime.datetime
240+
241+
242+
class MessagesPublic(SQLModel):
243+
data: list[MessagePublic]
244+
count: int

0 commit comments

Comments
 (0)