108 lines
3.9 KiB
Python
108 lines
3.9 KiB
Python
"""
|
|
故事相关ORM模型
|
|
"""
|
|
from sqlalchemy import Column, Integer, String, Text, Boolean, TIMESTAMP, ForeignKey, Enum, JSON
|
|
from sqlalchemy.orm import relationship
|
|
from sqlalchemy.sql import func
|
|
from app.database import Base
|
|
import enum
|
|
|
|
|
|
class Story(Base):
|
|
"""故事主表"""
|
|
__tablename__ = "stories"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
title = Column(String(100), nullable=False)
|
|
cover_url = Column(String(255), default="")
|
|
description = Column(Text)
|
|
author_id = Column(Integer, default=0)
|
|
category = Column(String(50), nullable=False)
|
|
play_count = Column(Integer, default=0)
|
|
like_count = Column(Integer, default=0)
|
|
is_featured = Column(Boolean, default=False)
|
|
status = Column(Integer, default=1)
|
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
|
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
|
|
|
|
nodes = relationship("StoryNode", back_populates="story", cascade="all, delete-orphan")
|
|
|
|
|
|
class StoryNode(Base):
|
|
"""故事节点表"""
|
|
__tablename__ = "story_nodes"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
story_id = Column(Integer, ForeignKey("stories.id", ondelete="CASCADE"), nullable=False)
|
|
node_key = Column(String(50), nullable=False)
|
|
content = Column(Text, nullable=False)
|
|
speaker = Column(String(50), default="")
|
|
background_image = Column(String(255), default="")
|
|
character_image = Column(String(255), default="")
|
|
bgm = Column(String(255), default="")
|
|
is_ending = Column(Boolean, default=False)
|
|
ending_name = Column(String(100), default="")
|
|
ending_score = Column(Integer, default=0)
|
|
ending_type = Column(String(20), default="")
|
|
sort_order = Column(Integer, default=0)
|
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
|
|
|
story = relationship("Story", back_populates="nodes")
|
|
choices = relationship("StoryChoice", back_populates="node", cascade="all, delete-orphan")
|
|
|
|
|
|
class StoryChoice(Base):
|
|
"""故事选项表"""
|
|
__tablename__ = "story_choices"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
node_id = Column(Integer, ForeignKey("story_nodes.id", ondelete="CASCADE"), nullable=False)
|
|
story_id = Column(Integer, nullable=False)
|
|
text = Column(String(200), nullable=False)
|
|
next_node_key = Column(String(50), nullable=False)
|
|
sort_order = Column(Integer, default=0)
|
|
is_locked = Column(Boolean, default=False)
|
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
|
|
|
node = relationship("StoryNode", back_populates="choices")
|
|
|
|
|
|
class DraftStatus(enum.Enum):
|
|
"""草稿状态枚举"""
|
|
pending = "pending"
|
|
processing = "processing"
|
|
completed = "completed"
|
|
failed = "failed"
|
|
|
|
|
|
class StoryDraft(Base):
|
|
"""AI改写草稿表"""
|
|
__tablename__ = "story_drafts"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
|
story_id = Column(Integer, ForeignKey("stories.id", ondelete="CASCADE"), nullable=False)
|
|
title = Column(String(100), default="")
|
|
|
|
# 用户输入
|
|
path_history = Column(JSON, default=None) # 用户之前的选择路径
|
|
current_node_key = Column(String(50), default="")
|
|
current_content = Column(Text, default="")
|
|
user_prompt = Column(String(500), nullable=False)
|
|
|
|
# AI生成结果
|
|
ai_nodes = Column(JSON, default=None) # AI生成的新节点
|
|
entry_node_key = Column(String(50), default="")
|
|
tokens_used = Column(Integer, default=0)
|
|
|
|
# 状态
|
|
status = Column(Enum(DraftStatus), default=DraftStatus.pending)
|
|
error_message = Column(String(500), default="")
|
|
is_read = Column(Boolean, default=False) # 用户是否已查看
|
|
|
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
|
completed_at = Column(TIMESTAMP, default=None)
|
|
|
|
# 关联
|
|
story = relationship("Story")
|