added RAG, Multiuser, TG bot
This commit is contained in:
+396
-299
@@ -1,299 +1,396 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, String, Text, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class ChatSession(Base):
|
||||
__tablename__ = "chat_sessions"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
title: Mapped[str] = mapped_column(String(255), default="Новый чат")
|
||||
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()
|
||||
)
|
||||
|
||||
messages: Mapped[list["Message"]] = relationship(
|
||||
back_populates="session", cascade="all, delete-orphan", order_by="Message.created_at"
|
||||
)
|
||||
|
||||
|
||||
class Message(Base):
|
||||
__tablename__ = "messages"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
session_id: Mapped[int] = mapped_column(ForeignKey("chat_sessions.id", ondelete="CASCADE"), index=True)
|
||||
role: Mapped[str] = mapped_column(String(32))
|
||||
content: Mapped[str] = mapped_column(Text, default="")
|
||||
tool_calls_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
reasoning_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
tool_call_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
session: Mapped["ChatSession"] = relationship(back_populates="messages")
|
||||
|
||||
|
||||
class PomodoroCycle(Base):
|
||||
__tablename__ = "pomodoro_cycles"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
work_duration_min: Mapped[int] = mapped_column(Integer, default=25)
|
||||
short_break_min: Mapped[int] = mapped_column(Integer, default=5)
|
||||
long_break_min: Mapped[int] = mapped_column(Integer, default=15)
|
||||
sessions_until_long_break: Mapped[int] = mapped_column(Integer, default=4)
|
||||
completed_work_sessions: Mapped[int] = mapped_column(Integer, default=0)
|
||||
task_note: Mapped[str] = mapped_column(Text, default="")
|
||||
auto_advance: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
chat_notify_seq: Mapped[int] = mapped_column(Integer, default=0)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class PomodoroSession(Base):
|
||||
__tablename__ = "pomodoro_sessions"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
status: Mapped[str] = mapped_column(String(32), default="idle")
|
||||
phase: Mapped[str] = mapped_column(String(32), default="work")
|
||||
duration_min: Mapped[int] = mapped_column(Integer, default=25)
|
||||
task_note: Mapped[str] = mapped_column(Text, default="")
|
||||
result: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
completed: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
completion_notified: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
paused_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
elapsed_seconds: Mapped[int] = mapped_column(Integer, default=0)
|
||||
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class TaigaProject(Base):
|
||||
__tablename__ = "taiga_projects"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
taiga_id: Mapped[int] = mapped_column(Integer, unique=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(255))
|
||||
slug: Mapped[str] = mapped_column(String(255), unique=True, index=True)
|
||||
synced_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class ProjectBinding(Base):
|
||||
__tablename__ = "project_bindings"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
taiga_slug: Mapped[str] = mapped_column(String(255), unique=True, index=True)
|
||||
gitea_owner: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_repo: Mapped[str] = mapped_column(String(255), default="")
|
||||
default_branch: Mapped[str] = mapped_column(String(64), default="main")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class UserProfile(Base):
|
||||
__tablename__ = "user_profile"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
data_json: Mapped[str] = mapped_column(Text, default="{}")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class MemoryFact(Base):
|
||||
__tablename__ = "memory_facts"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
category: Mapped[str] = mapped_column(String(64), default="fact", index=True)
|
||||
content: Mapped[str] = mapped_column(Text)
|
||||
source: Mapped[str] = mapped_column(String(32), default="user")
|
||||
session_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("chat_sessions.id", ondelete="SET NULL"), nullable=True, index=True
|
||||
)
|
||||
importance: Mapped[int] = mapped_column(Integer, default=3)
|
||||
active: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
||||
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 SessionSummary(Base):
|
||||
__tablename__ = "session_summaries"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
session_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("chat_sessions.id", ondelete="CASCADE"), unique=True, index=True
|
||||
)
|
||||
summary: Mapped[str] = mapped_column(Text, default="")
|
||||
message_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class FitnessProfile(Base):
|
||||
__tablename__ = "fitness_profiles"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
sex: Mapped[str] = mapped_column(String(16), default="male")
|
||||
age: Mapped[int] = mapped_column(Integer, default=30)
|
||||
height_cm: Mapped[float] = mapped_column(Float, default=170.0)
|
||||
weight_kg: Mapped[float] = mapped_column(Float, default=70.0)
|
||||
activity_level: Mapped[str] = mapped_column(String(32), default="moderate")
|
||||
goal: Mapped[str] = mapped_column(String(32), default="maintain")
|
||||
target_weight_kg: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
weekly_workouts: Mapped[int] = mapped_column(Integer, default=3)
|
||||
calorie_target: Mapped[float] = mapped_column(Float, default=2000.0)
|
||||
protein_g: Mapped[float] = mapped_column(Float, default=140.0)
|
||||
fat_g: Mapped[float] = mapped_column(Float, default=65.0)
|
||||
carbs_g: Mapped[float] = mapped_column(Float, default=200.0)
|
||||
water_l: Mapped[float] = mapped_column(Float, default=2.5)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class BodyMetric(Base):
|
||||
__tablename__ = "body_metrics"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
weight_kg: Mapped[float] = mapped_column(Float)
|
||||
body_fat_pct: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
chest_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
waist_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
|
||||
class FoodLog(Base):
|
||||
__tablename__ = "food_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
meal_type: Mapped[str] = mapped_column(String(32), default="snack")
|
||||
description: Mapped[str] = mapped_column(Text, default="")
|
||||
calories: Mapped[float] = mapped_column(Float, default=0)
|
||||
protein_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
fat_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
carbs_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
source: Mapped[str] = mapped_column(String(32), default="llm")
|
||||
estimated: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
|
||||
|
||||
class WaterLog(Base):
|
||||
__tablename__ = "water_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
amount_ml: Mapped[int] = mapped_column(Integer)
|
||||
|
||||
|
||||
class WorkoutLog(Base):
|
||||
__tablename__ = "workout_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
title: Mapped[str] = mapped_column(String(255), default="Тренировка")
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
duration_min: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
exercises_json: Mapped[str] = mapped_column(Text, default="[]")
|
||||
|
||||
|
||||
class FitnessReminder(Base):
|
||||
__tablename__ = "fitness_reminders"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
kind: Mapped[str] = mapped_column(String(32))
|
||||
hour: Mapped[int] = mapped_column(Integer, default=12)
|
||||
minute: Mapped[int] = mapped_column(Integer, default=0)
|
||||
interval_hours: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
last_fired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
|
||||
class ShoppingList(Base):
|
||||
__tablename__ = "shopping_lists"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(255), unique=True, index=True)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
||||
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()
|
||||
)
|
||||
|
||||
items: Mapped[list["ShoppingListItem"]] = relationship(
|
||||
back_populates="shopping_list",
|
||||
cascade="all, delete-orphan",
|
||||
order_by="ShoppingListItem.sort_order, ShoppingListItem.id",
|
||||
)
|
||||
|
||||
|
||||
class ShoppingListItem(Base):
|
||||
__tablename__ = "shopping_list_items"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
list_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("shopping_lists.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
text: Mapped[str] = mapped_column(String(500))
|
||||
quantity: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
unit: Mapped[str] = mapped_column(String(64), default="")
|
||||
checked: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
shopping_list: Mapped["ShoppingList"] = relationship(back_populates="items")
|
||||
|
||||
|
||||
class Reminder(Base):
|
||||
__tablename__ = "reminders"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
title: Mapped[str] = mapped_column(String(255))
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
due_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True)
|
||||
all_day: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
recurrence: Mapped[str] = mapped_column(String(16), default="none")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
||||
last_fired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
timezone: Mapped[str] = mapped_column(String(64), default="Europe/Moscow")
|
||||
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 AssistantState(Base):
|
||||
__tablename__ = "assistant_state"
|
||||
|
||||
key: Mapped[str] = mapped_column(String(128), primary_key=True)
|
||||
value: Mapped[str] = mapped_column(Text, default="")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class WorkItem(Base):
|
||||
__tablename__ = "work_items"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
taiga_slug: Mapped[str] = mapped_column(String(255), index=True)
|
||||
taiga_project_id: Mapped[int] = mapped_column(Integer)
|
||||
taiga_story_id: Mapped[int] = mapped_column(Integer)
|
||||
taiga_story_ref: Mapped[int] = mapped_column(Integer, index=True)
|
||||
gitea_owner: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_repo: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_issue_number: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
|
||||
suggested_branch: Mapped[str] = mapped_column(String(255), default="")
|
||||
raw_text: Mapped[str] = mapped_column(Text, default="")
|
||||
title: Mapped[str] = mapped_column(String(500), default="")
|
||||
status: Mapped[str] = mapped_column(String(32), default="open")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
closed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, String, Text, UniqueConstraint, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
username: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
||||
display_name: Mapped[str] = mapped_column(String(255), default="")
|
||||
api_token_hash: Mapped[str] = mapped_column(String(64), index=True)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class CharacterCard(Base):
|
||||
__tablename__ = "character_cards"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("users.id", ondelete="CASCADE"), unique=True, index=True
|
||||
)
|
||||
card_json: Mapped[str] = mapped_column(Text, default="{}")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class ChatSession(Base):
|
||||
__tablename__ = "chat_sessions"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
title: Mapped[str] = mapped_column(String(255), default="Новый чат")
|
||||
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()
|
||||
)
|
||||
|
||||
messages: Mapped[list["Message"]] = relationship(
|
||||
back_populates="session", cascade="all, delete-orphan", order_by="Message.created_at"
|
||||
)
|
||||
|
||||
|
||||
class Message(Base):
|
||||
__tablename__ = "messages"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
session_id: Mapped[int] = mapped_column(ForeignKey("chat_sessions.id", ondelete="CASCADE"), index=True)
|
||||
role: Mapped[str] = mapped_column(String(32))
|
||||
content: Mapped[str] = mapped_column(Text, default="")
|
||||
tool_calls_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
reasoning_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
tool_call_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
session: Mapped["ChatSession"] = relationship(back_populates="messages")
|
||||
|
||||
|
||||
class PomodoroCycle(Base):
|
||||
__tablename__ = "pomodoro_cycles"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
work_duration_min: Mapped[int] = mapped_column(Integer, default=25)
|
||||
short_break_min: Mapped[int] = mapped_column(Integer, default=5)
|
||||
long_break_min: Mapped[int] = mapped_column(Integer, default=15)
|
||||
sessions_until_long_break: Mapped[int] = mapped_column(Integer, default=4)
|
||||
completed_work_sessions: Mapped[int] = mapped_column(Integer, default=0)
|
||||
task_note: Mapped[str] = mapped_column(Text, default="")
|
||||
auto_advance: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
chat_notify_seq: Mapped[int] = mapped_column(Integer, default=0)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class PomodoroSession(Base):
|
||||
__tablename__ = "pomodoro_sessions"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
status: Mapped[str] = mapped_column(String(32), default="idle")
|
||||
phase: Mapped[str] = mapped_column(String(32), default="work")
|
||||
duration_min: Mapped[int] = mapped_column(Integer, default=25)
|
||||
task_note: Mapped[str] = mapped_column(Text, default="")
|
||||
result: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
completed: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
completion_notified: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
paused_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
elapsed_seconds: Mapped[int] = mapped_column(Integer, default=0)
|
||||
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class TaigaProject(Base):
|
||||
__tablename__ = "taiga_projects"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
taiga_id: Mapped[int] = mapped_column(Integer, unique=True, index=True)
|
||||
name: Mapped[str] = mapped_column(String(255))
|
||||
slug: Mapped[str] = mapped_column(String(255), unique=True, index=True)
|
||||
synced_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class ProjectBinding(Base):
|
||||
__tablename__ = "project_bindings"
|
||||
__table_args__ = (UniqueConstraint("user_id", "taiga_slug", name="uq_project_bindings_user_slug"),)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
taiga_slug: Mapped[str] = mapped_column(String(255), index=True)
|
||||
gitea_owner: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_repo: Mapped[str] = mapped_column(String(255), default="")
|
||||
default_branch: Mapped[str] = mapped_column(String(64), default="main")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class UserProfile(Base):
|
||||
__tablename__ = "user_profile"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
data_json: Mapped[str] = mapped_column(Text, default="{}")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class MemoryFact(Base):
|
||||
__tablename__ = "memory_facts"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
category: Mapped[str] = mapped_column(String(64), default="fact", index=True)
|
||||
content: Mapped[str] = mapped_column(Text)
|
||||
source: Mapped[str] = mapped_column(String(32), default="user")
|
||||
session_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("chat_sessions.id", ondelete="SET NULL"), nullable=True, index=True
|
||||
)
|
||||
importance: Mapped[int] = mapped_column(Integer, default=3)
|
||||
active: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
||||
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 SessionSummary(Base):
|
||||
__tablename__ = "session_summaries"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
session_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("chat_sessions.id", ondelete="CASCADE"), unique=True, index=True
|
||||
)
|
||||
summary: Mapped[str] = mapped_column(Text, default="")
|
||||
message_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class FitnessProfile(Base):
|
||||
__tablename__ = "fitness_profiles"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
sex: Mapped[str] = mapped_column(String(16), default="male")
|
||||
age: Mapped[int] = mapped_column(Integer, default=30)
|
||||
height_cm: Mapped[float] = mapped_column(Float, default=170.0)
|
||||
weight_kg: Mapped[float] = mapped_column(Float, default=70.0)
|
||||
activity_level: Mapped[str] = mapped_column(String(32), default="moderate")
|
||||
goal: Mapped[str] = mapped_column(String(32), default="maintain")
|
||||
target_weight_kg: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
weekly_workouts: Mapped[int] = mapped_column(Integer, default=3)
|
||||
baseline_steps: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
baseline_workout_kcal: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
calorie_target: Mapped[float] = mapped_column(Float, default=2000.0)
|
||||
protein_g: Mapped[float] = mapped_column(Float, default=140.0)
|
||||
fat_g: Mapped[float] = mapped_column(Float, default=65.0)
|
||||
carbs_g: Mapped[float] = mapped_column(Float, default=200.0)
|
||||
water_l: Mapped[float] = mapped_column(Float, default=2.5)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class BodyMetric(Base):
|
||||
__tablename__ = "body_metrics"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
weight_kg: Mapped[float] = mapped_column(Float)
|
||||
body_fat_pct: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
body_fat_method: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||||
chest_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
waist_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
neck_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
hip_cm: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
whr: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
lbm_kg: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
ffmi: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
|
||||
class FoodLog(Base):
|
||||
__tablename__ = "food_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
meal_type: Mapped[str] = mapped_column(String(32), default="snack")
|
||||
description: Mapped[str] = mapped_column(Text, default="")
|
||||
calories: Mapped[float] = mapped_column(Float, default=0)
|
||||
protein_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
fat_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
carbs_g: Mapped[float] = mapped_column(Float, default=0)
|
||||
source: Mapped[str] = mapped_column(String(32), default="llm")
|
||||
estimated: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
|
||||
|
||||
class StepLog(Base):
|
||||
__tablename__ = "step_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
steps: Mapped[int] = mapped_column(Integer, default=0)
|
||||
active_calories: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
source: Mapped[str] = mapped_column(String(32), default="manual")
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
|
||||
class WaterLog(Base):
|
||||
__tablename__ = "water_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
amount_ml: Mapped[int] = mapped_column(Integer)
|
||||
|
||||
|
||||
class WorkoutLog(Base):
|
||||
__tablename__ = "workout_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
logged_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
title: Mapped[str] = mapped_column(String(255), default="Тренировка")
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
duration_min: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
active_calories: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
total_calories: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
steps: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
exercises_json: Mapped[str] = mapped_column(Text, default="[]")
|
||||
|
||||
|
||||
class FitnessReminder(Base):
|
||||
__tablename__ = "fitness_reminders"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
kind: Mapped[str] = mapped_column(String(32))
|
||||
hour: Mapped[int] = mapped_column(Integer, default=12)
|
||||
minute: Mapped[int] = mapped_column(Integer, default=0)
|
||||
interval_hours: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
last_fired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
|
||||
class ShoppingList(Base):
|
||||
__tablename__ = "shopping_lists"
|
||||
__table_args__ = (UniqueConstraint("user_id", "name", name="uq_shopping_lists_user_name"),)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
name: Mapped[str] = mapped_column(String(255), index=True)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
||||
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()
|
||||
)
|
||||
|
||||
items: Mapped[list["ShoppingListItem"]] = relationship(
|
||||
back_populates="shopping_list",
|
||||
cascade="all, delete-orphan",
|
||||
order_by="ShoppingListItem.sort_order, ShoppingListItem.id",
|
||||
)
|
||||
|
||||
|
||||
class ShoppingListItem(Base):
|
||||
__tablename__ = "shopping_list_items"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
list_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("shopping_lists.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
text: Mapped[str] = mapped_column(String(500))
|
||||
quantity: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
unit: Mapped[str] = mapped_column(String(64), default="")
|
||||
checked: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
|
||||
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
shopping_list: Mapped["ShoppingList"] = relationship(back_populates="items")
|
||||
|
||||
|
||||
class Reminder(Base):
|
||||
__tablename__ = "reminders"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
title: Mapped[str] = mapped_column(String(255))
|
||||
notes: Mapped[str] = mapped_column(Text, default="")
|
||||
due_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True)
|
||||
all_day: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
recurrence: Mapped[str] = mapped_column(String(16), default="none")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
||||
last_fired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
timezone: Mapped[str] = mapped_column(String(64), default="Europe/Moscow")
|
||||
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 AssistantState(Base):
|
||||
__tablename__ = "assistant_state"
|
||||
|
||||
key: Mapped[str] = mapped_column(String(128), primary_key=True)
|
||||
value: Mapped[str] = mapped_column(Text, default="")
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class WorkItem(Base):
|
||||
__tablename__ = "work_items"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
taiga_slug: Mapped[str] = mapped_column(String(255), index=True)
|
||||
taiga_project_id: Mapped[int] = mapped_column(Integer)
|
||||
taiga_story_id: Mapped[int] = mapped_column(Integer)
|
||||
taiga_story_ref: Mapped[int] = mapped_column(Integer, index=True)
|
||||
gitea_owner: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_repo: Mapped[str] = mapped_column(String(255), default="")
|
||||
gitea_issue_number: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
|
||||
suggested_branch: Mapped[str] = mapped_column(String(255), default="")
|
||||
raw_text: Mapped[str] = mapped_column(Text, default="")
|
||||
title: Mapped[str] = mapped_column(String(500), default="")
|
||||
status: Mapped[str] = mapped_column(String(32), default="open")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
closed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
|
||||
class Document(Base):
|
||||
__tablename__ = "documents"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
title: Mapped[str] = mapped_column(String(255), default="")
|
||||
filename: Mapped[str] = mapped_column(String(255), default="")
|
||||
content_hash: Mapped[str] = mapped_column(String(64), default="", index=True)
|
||||
size_bytes: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
|
||||
chunks: Mapped[list["DocumentChunk"]] = relationship(
|
||||
back_populates="document",
|
||||
cascade="all, delete-orphan",
|
||||
order_by="DocumentChunk.chunk_index",
|
||||
)
|
||||
|
||||
|
||||
class DocumentChunk(Base):
|
||||
__tablename__ = "document_chunks"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
document_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("documents.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
chunk_index: Mapped[int] = mapped_column(Integer, default=0)
|
||||
content: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
document: Mapped["Document"] = relationship(back_populates="chunks")
|
||||
|
||||
Reference in New Issue
Block a user