39 lines
1.6 KiB
Python
39 lines
1.6 KiB
Python
"""ORM model for user feedback on runs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlalchemy import Index, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from deerflow.persistence.base import Base
|
|
from deerflow.persistence.types import BeijingDateTime
|
|
|
|
|
|
class FeedbackRow(Base):
|
|
__tablename__ = "feedback"
|
|
|
|
# Prefix-unique instead of UniqueConstraint: a plain unique over three
|
|
# String(64) columns is (64+64+64)*4 = 768 bytes — one byte over MySQL's
|
|
# legacy 767-byte index limit (utf8mb4). Capping user_id's key part at 63
|
|
# chars (ids are 36-char UUIDs in practice) brings it to 764 bytes.
|
|
# mysql_length is ignored on SQLite/Postgres.
|
|
__table_args__ = (Index("uq_feedback_thread_run_user", "thread_id", "run_id", "user_id", unique=True, mysql_length={"user_id": 63}),)
|
|
|
|
feedback_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
run_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
thread_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
user_id: Mapped[str | None] = mapped_column(String(64), index=True)
|
|
message_id: Mapped[str | None] = mapped_column(String(64))
|
|
# message_id is an optional RunEventStore event identifier —
|
|
# allows feedback to target a specific message or the entire run
|
|
|
|
rating: Mapped[int] = mapped_column(nullable=False)
|
|
# +1 (thumbs-up) or -1 (thumbs-down)
|
|
|
|
comment: Mapped[str | None] = mapped_column(Text)
|
|
# Optional text feedback from the user
|
|
|
|
created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC))
|