Files
ai_game/server/app/models/story.py

108 lines
3.9 KiB
Python
Raw Normal View History

"""
故事相关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")