@@ -0,0 +1,616 @@
""" 初始化SQLite数据库
Revision ID: fbeb1038c728
Revises:
Create Date: 2025-12-26 13:22:53.151546
"""
from typing import Sequence , Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision : str = ' fbeb1038c728 '
down_revision : Union [ str , None ] = None
branch_labels : Union [ str , Sequence [ str ] , None ] = None
depends_on : Union [ str , Sequence [ str ] , None ] = None
def upgrade ( ) - > None :
# ### commands auto generated by Alembic - please adjust! ###
op . create_table ( ' batch_generation_tasks ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 项目ID ' ) ,
sa . Column ( ' user_id ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' start_chapter_number ' , sa . Integer ( ) , nullable = False , comment = ' 起始章节序号 ' ) ,
sa . Column ( ' chapter_count ' , sa . Integer ( ) , nullable = False , comment = ' 生成章节数量 ' ) ,
sa . Column ( ' chapter_ids ' , sa . JSON ( ) , nullable = False , comment = ' 待生成的章节ID列表 ' ) ,
sa . Column ( ' style_id ' , sa . Integer ( ) , nullable = True , comment = ' 使用的写作风格ID ' ) ,
sa . Column ( ' target_word_count ' , sa . Integer ( ) , nullable = True , comment = ' 目标字数 ' ) ,
sa . Column ( ' enable_analysis ' , sa . Boolean ( ) , nullable = True , comment = ' 是否启用同步分析 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 任务状态: pending/running/completed/failed/cancelled ' ) ,
sa . Column ( ' total_chapters ' , sa . Integer ( ) , nullable = True , comment = ' 总章节数 ' ) ,
sa . Column ( ' completed_chapters ' , sa . Integer ( ) , nullable = True , comment = ' 已完成章节数 ' ) ,
sa . Column ( ' failed_chapters ' , sa . JSON ( ) , nullable = True , comment = ' 失败的章节信息列表 ' ) ,
sa . Column ( ' current_chapter_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 当前正在生成的章节ID ' ) ,
sa . Column ( ' current_chapter_number ' , sa . Integer ( ) , nullable = True , comment = ' 当前正在生成的章节序号 ' ) ,
sa . Column ( ' current_retry_count ' , sa . Integer ( ) , nullable = True , comment = ' 当前章节重试次数 ' ) ,
sa . Column ( ' max_retries ' , sa . Integer ( ) , nullable = True , comment = ' 最大重试次数 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' started_at ' , sa . DateTime ( ) , nullable = True , comment = ' 开始时间 ' ) ,
sa . Column ( ' completed_at ' , sa . DateTime ( ) , nullable = True , comment = ' 完成时间 ' ) ,
sa . Column ( ' error_message ' , sa . String ( length = 500 ) , nullable = True , comment = ' 错误信息 ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' mcp_plugins ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 50 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' plugin_name ' , sa . String ( length = 100 ) , nullable = False , comment = ' 插件名称(唯一标识) ' ) ,
sa . Column ( ' display_name ' , sa . String ( length = 200 ) , nullable = False , comment = ' 显示名称 ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 插件描述 ' ) ,
sa . Column ( ' plugin_type ' , sa . String ( length = 50 ) , nullable = True , comment = ' 插件类型:http/stdio ' ) ,
sa . Column ( ' server_url ' , sa . String ( length = 500 ) , nullable = True , comment = ' 服务器URL( HTTP类型) ' ) ,
sa . Column ( ' command ' , sa . String ( length = 500 ) , nullable = True , comment = ' 启动命令(stdio类型) ' ) ,
sa . Column ( ' args ' , sa . JSON ( ) , nullable = True , comment = ' 命令参数(stdio类型) ' ) ,
sa . Column ( ' env ' , sa . JSON ( ) , nullable = True , comment = ' 环境变量 ' ) ,
sa . Column ( ' headers ' , sa . JSON ( ) , nullable = True , comment = ' HTTP请求头 ' ) ,
sa . Column ( ' config ' , sa . JSON ( ) , nullable = True , comment = ' 插件特定配置(JSON) ' ) ,
sa . Column ( ' tools ' , sa . JSON ( ) , nullable = True , comment = ' 提供的工具列表 ' ) ,
sa . Column ( ' enabled ' , sa . Boolean ( ) , nullable = True , comment = ' 是否启用 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 50 ) , nullable = True , comment = ' 状态:active/inactive/error ' ) ,
sa . Column ( ' last_error ' , sa . Text ( ) , nullable = True , comment = ' 最后错误信息 ' ) ,
sa . Column ( ' last_test_at ' , sa . DateTime ( ) , nullable = True , comment = ' 最后测试时间 ' ) ,
sa . Column ( ' category ' , sa . String ( length = 100 ) , nullable = True , comment = ' 分类 ' ) ,
sa . Column ( ' sort_order ' , sa . Integer ( ) , nullable = True , comment = ' 排序顺序 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' mcp_plugins ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_user_enabled ' , [ ' user_id ' , ' enabled ' ] , unique = False )
batch_op . create_index ( ' idx_user_plugin ' , [ ' user_id ' , ' plugin_name ' ] , unique = True )
batch_op . create_index ( batch_op . f ( ' ix_mcp_plugins_user_id ' ) , [ ' user_id ' ] , unique = False )
op . create_table ( ' projects ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' title ' , sa . String ( length = 200 ) , nullable = False , comment = ' 项目标题 ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 项目简介 ' ) ,
sa . Column ( ' theme ' , sa . Text ( ) , nullable = True , comment = ' 主题 ' ) ,
sa . Column ( ' genre ' , sa . String ( length = 50 ) , nullable = True , comment = ' 小说类型 ' ) ,
sa . Column ( ' target_words ' , sa . Integer ( ) , nullable = True , comment = ' 目标字数 ' ) ,
sa . Column ( ' current_words ' , sa . Integer ( ) , nullable = True , comment = ' 当前字数 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 创作状态 ' ) ,
sa . Column ( ' wizard_status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 向导完成状态: incomplete/completed ' ) ,
sa . Column ( ' wizard_step ' , sa . Integer ( ) , nullable = True , comment = ' 向导当前步骤: 0-4 ' ) ,
sa . Column ( ' outline_mode ' , sa . String ( length = 20 ) , nullable = False , comment = ' 大纲章节模式: one-to-one(传统模式) 或 one-to-many(细化模式) ' ) ,
sa . Column ( ' world_time_period ' , sa . Text ( ) , nullable = True , comment = ' 时间背景 ' ) ,
sa . Column ( ' world_location ' , sa . Text ( ) , nullable = True , comment = ' 地理位置 ' ) ,
sa . Column ( ' world_atmosphere ' , sa . Text ( ) , nullable = True , comment = ' 氛围基调 ' ) ,
sa . Column ( ' world_rules ' , sa . Text ( ) , nullable = True , comment = ' 世界规则 ' ) ,
sa . Column ( ' chapter_count ' , sa . Integer ( ) , nullable = True , comment = ' 章节数量 ' ) ,
sa . Column ( ' narrative_perspective ' , sa . String ( length = 50 ) , nullable = True , comment = ' 叙事视角:first_person/third_person/omniscient ' ) ,
sa . Column ( ' character_count ' , sa . Integer ( ) , nullable = True , comment = ' 角色数量 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . CheckConstraint ( " outline_mode IN ( ' one-to-one ' , ' one-to-many ' ) " , name = ' check_outline_mode ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' projects ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_projects_user_id ' ) , [ ' user_id ' ] , unique = False )
op . create_table ( ' prompt_templates ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 50 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' template_key ' , sa . String ( length = 100 ) , nullable = False , comment = ' 模板键名 ' ) ,
sa . Column ( ' template_name ' , sa . String ( length = 200 ) , nullable = False , comment = ' 模板显示名称 ' ) ,
sa . Column ( ' template_content ' , sa . Text ( ) , nullable = False , comment = ' 模板内容 ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 模板描述 ' ) ,
sa . Column ( ' category ' , sa . String ( length = 50 ) , nullable = True , comment = ' 模板分类 ' ) ,
sa . Column ( ' parameters ' , sa . Text ( ) , nullable = True , comment = ' 模板参数定义(JSON) ' ) ,
sa . Column ( ' is_active ' , sa . Boolean ( ) , nullable = True , comment = ' 是否启用 ' ) ,
sa . Column ( ' is_system_default ' , sa . Boolean ( ) , nullable = True , comment = ' 是否为系统默认模板 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' prompt_templates ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_user_template ' , [ ' user_id ' , ' template_key ' ] , unique = True )
batch_op . create_index ( batch_op . f ( ' ix_prompt_templates_user_id ' ) , [ ' user_id ' ] , unique = False )
op . create_table ( ' relationship_types ' ,
sa . Column ( ' id ' , sa . Integer ( ) , autoincrement = True , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 50 ) , nullable = False , comment = ' 关系名称 ' ) ,
sa . Column ( ' category ' , sa . String ( length = 20 ) , nullable = False , comment = ' 分类:family/social/hostile/professional ' ) ,
sa . Column ( ' reverse_name ' , sa . String ( length = 50 ) , nullable = True , comment = ' 反向关系名称 ' ) ,
sa . Column ( ' intimacy_range ' , sa . String ( length = 20 ) , nullable = True , comment = ' 亲密度范围:high/medium/low ' ) ,
sa . Column ( ' icon ' , sa . String ( length = 50 ) , nullable = True , comment = ' 图标标识 ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 关系描述 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' relationship_types ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_relationship_types_id ' ) , [ ' id ' ] , unique = False )
op . create_table ( ' settings ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 50 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' api_provider ' , sa . String ( length = 50 ) , nullable = True , comment = ' API提供商 ' ) ,
sa . Column ( ' api_key ' , sa . String ( length = 500 ) , nullable = True , comment = ' API密钥 ' ) ,
sa . Column ( ' api_base_url ' , sa . String ( length = 500 ) , nullable = True , comment = ' 自定义API地址 ' ) ,
sa . Column ( ' llm_model ' , sa . String ( length = 100 ) , nullable = True , comment = ' 模型名称 ' ) ,
sa . Column ( ' temperature ' , sa . Float ( ) , nullable = True , comment = ' 温度参数 ' ) ,
sa . Column ( ' max_tokens ' , sa . Integer ( ) , nullable = True , comment = ' 最大token数 ' ) ,
sa . Column ( ' preferences ' , sa . Text ( ) , nullable = True , comment = ' 其他偏好设置(JSON) ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' settings ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_user_id ' , [ ' user_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_settings_user_id ' ) , [ ' user_id ' ] , unique = True )
op . create_table ( ' user_passwords ' ,
sa . Column ( ' user_id ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' username ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户名 ' ) ,
sa . Column ( ' password_hash ' , sa . String ( length = 64 ) , nullable = False , comment = ' 密码哈希(SHA256) ' ) ,
sa . Column ( ' has_custom_password ' , sa . Boolean ( ) , nullable = True , comment = ' 是否为自定义密码 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . PrimaryKeyConstraint ( ' user_id ' )
)
with op . batch_alter_table ( ' user_passwords ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_user_passwords_user_id ' ) , [ ' user_id ' ] , unique = False )
op . create_table ( ' users ' ,
sa . Column ( ' user_id ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户ID,格式:linuxdo_ {id} 或 local_ {id} ' ) ,
sa . Column ( ' username ' , sa . String ( length = 100 ) , nullable = False , comment = ' 用户名 ' ) ,
sa . Column ( ' display_name ' , sa . String ( length = 200 ) , nullable = False , comment = ' 显示名称 ' ) ,
sa . Column ( ' avatar_url ' , sa . String ( length = 500 ) , nullable = True , comment = ' 头像URL ' ) ,
sa . Column ( ' trust_level ' , sa . Integer ( ) , nullable = True , comment = ' 信任等级(仅用于显示) ' ) ,
sa . Column ( ' is_admin ' , sa . Boolean ( ) , nullable = True , comment = ' 是否为管理员 ' ) ,
sa . Column ( ' linuxdo_id ' , sa . String ( length = 100 ) , nullable = False , comment = ' LinuxDO用户ID或本地用户ID ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' last_login ' , sa . DateTime ( timezone = True ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 最后登录时间 ' ) ,
sa . PrimaryKeyConstraint ( ' user_id ' )
)
with op . batch_alter_table ( ' users ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_users_linuxdo_id ' ) , [ ' linuxdo_id ' ] , unique = True )
batch_op . create_index ( batch_op . f ( ' ix_users_user_id ' ) , [ ' user_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_users_username ' ) , [ ' username ' ] , unique = False )
op . create_table ( ' careers ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 100 ) , nullable = False , comment = ' 职业名称 ' ) ,
sa . Column ( ' type ' , sa . String ( length = 20 ) , nullable = False , comment = ' 职业类型: main(主职业)/sub(副职业) ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 职业描述 ' ) ,
sa . Column ( ' category ' , sa . String ( length = 50 ) , nullable = True , comment = ' 职业分类(如:战斗系、生产系、辅助系) ' ) ,
sa . Column ( ' stages ' , sa . Text ( ) , nullable = False , comment = " 职业阶段列表(JSON): [ { level:1, name: ' ' , description: ' ' }, ...] " ) ,
sa . Column ( ' max_stage ' , sa . Integer ( ) , nullable = False , comment = ' 最大阶段数 ' ) ,
sa . Column ( ' requirements ' , sa . Text ( ) , nullable = True , comment = ' 职业要求/限制 ' ) ,
sa . Column ( ' special_abilities ' , sa . Text ( ) , nullable = True , comment = ' 特殊能力描述 ' ) ,
sa . Column ( ' worldview_rules ' , sa . Text ( ) , nullable = True , comment = ' 世界观规则关联 ' ) ,
sa . Column ( ' attribute_bonuses ' , sa . Text ( ) , nullable = True , comment = " 属性加成(JSON): { strength: ' +10 % ' , intelligence: ' +5 % ' } " ) ,
sa . Column ( ' source ' , sa . String ( length = 20 ) , nullable = True , comment = ' 来源: ai/manual ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' careers ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_project_id ' , [ ' project_id ' ] , unique = False )
batch_op . create_index ( ' idx_type ' , [ ' type ' ] , unique = False )
op . create_table ( ' outlines ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' title ' , sa . String ( length = 200 ) , nullable = False , comment = ' 大纲标题 ' ) ,
sa . Column ( ' content ' , sa . Text ( ) , nullable = True , comment = ' 大纲内容 ' ) ,
sa . Column ( ' structure ' , sa . Text ( ) , nullable = True , comment = ' 结构化大纲数据(JSON) ' ) ,
sa . Column ( ' order_index ' , sa . Integer ( ) , nullable = True , comment = ' 排序序号 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' writing_styles ' ,
sa . Column ( ' id ' , sa . Integer ( ) , autoincrement = True , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 255 ) , nullable = True , comment = ' 所属用户ID(NULL表示全局预设风格) ' ) ,
sa . Column ( ' name ' , sa . String ( length = 100 ) , nullable = False , comment = ' 风格名称 ' ) ,
sa . Column ( ' style_type ' , sa . String ( length = 50 ) , nullable = False , comment = ' 风格类型:preset/custom ' ) ,
sa . Column ( ' preset_id ' , sa . String ( length = 50 ) , nullable = True , comment = ' 预设风格ID: natural/classical/modern等 ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 风格描述 ' ) ,
sa . Column ( ' prompt_content ' , sa . Text ( ) , nullable = False , comment = ' 风格提示词内容 ' ) ,
sa . Column ( ' order_index ' , sa . Integer ( ) , nullable = True , comment = ' 排序序号 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' user_id ' ] , [ ' users.user_id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' chapters ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' chapter_number ' , sa . Integer ( ) , nullable = False , comment = ' 章节序号 ' ) ,
sa . Column ( ' title ' , sa . String ( length = 200 ) , nullable = False , comment = ' 章节标题 ' ) ,
sa . Column ( ' content ' , sa . Text ( ) , nullable = True , comment = ' 章节内容 ' ) ,
sa . Column ( ' summary ' , sa . Text ( ) , nullable = True , comment = ' 章节摘要 ' ) ,
sa . Column ( ' word_count ' , sa . Integer ( ) , nullable = True , comment = ' 字数统计 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 章节状态 ' ) ,
sa . Column ( ' outline_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 关联的大纲ID ' ) ,
sa . Column ( ' sub_index ' , sa . Integer ( ) , nullable = True , comment = ' 大纲下的子章节序号 ' ) ,
sa . Column ( ' expansion_plan ' , sa . Text ( ) , nullable = True , comment = ' 展开规划详情(JSON): 包含key_events, character_focus, emotional_tone等 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' outline_id ' ] , [ ' outlines.id ' ] , ondelete = ' SET NULL ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' characters ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 100 ) , nullable = False , comment = ' 角色/组织名称 ' ) ,
sa . Column ( ' age ' , sa . String ( length = 50 ) , nullable = True , comment = ' 年龄 ' ) ,
sa . Column ( ' gender ' , sa . String ( length = 50 ) , nullable = True , comment = ' 性别 ' ) ,
sa . Column ( ' is_organization ' , sa . Boolean ( ) , nullable = True , comment = ' 是否为组织 ' ) ,
sa . Column ( ' role_type ' , sa . String ( length = 50 ) , nullable = True , comment = ' 角色类型 ' ) ,
sa . Column ( ' personality ' , sa . Text ( ) , nullable = True , comment = ' 性格特点/组织特性 ' ) ,
sa . Column ( ' background ' , sa . Text ( ) , nullable = True , comment = ' 背景故事 ' ) ,
sa . Column ( ' appearance ' , sa . Text ( ) , nullable = True , comment = ' 外貌描述 ' ) ,
sa . Column ( ' relationships ' , sa . Text ( ) , nullable = True , comment = ' 人物关系(JSON) ' ) ,
sa . Column ( ' organization_type ' , sa . String ( length = 100 ) , nullable = True , comment = ' 组织类型 ' ) ,
sa . Column ( ' organization_purpose ' , sa . String ( length = 500 ) , nullable = True , comment = ' 组织目的 ' ) ,
sa . Column ( ' organization_members ' , sa . Text ( ) , nullable = True , comment = ' 组织成员(JSON) ' ) ,
sa . Column ( ' main_career_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 主职业ID ' ) ,
sa . Column ( ' main_career_stage ' , sa . Integer ( ) , nullable = True , comment = ' 主职业当前阶段 ' ) ,
sa . Column ( ' sub_careers ' , sa . Text ( ) , nullable = True , comment = ' 副职业列表(JSON): [ { " career_id " : " xxx " , " stage " : 3}, ...] ' ) ,
sa . Column ( ' avatar_url ' , sa . String ( length = 500 ) , nullable = True , comment = ' 头像URL ' ) ,
sa . Column ( ' traits ' , sa . Text ( ) , nullable = True , comment = ' 特征标签(JSON) ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' main_career_id ' ] , [ ' careers.id ' ] , ondelete = ' SET NULL ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' project_default_styles ' ,
sa . Column ( ' id ' , sa . Integer ( ) , autoincrement = True , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 项目ID ' ) ,
sa . Column ( ' style_id ' , sa . Integer ( ) , nullable = False , comment = ' 风格ID ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' style_id ' ] , [ ' writing_styles.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' ) ,
sa . UniqueConstraint ( ' project_id ' , name = ' uix_project_default_style ' )
)
op . create_table ( ' analysis_tasks ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 任务ID ' ) ,
sa . Column ( ' chapter_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 章节ID ' ) ,
sa . Column ( ' user_id ' , sa . String ( length = 50 ) , nullable = False , comment = ' 用户ID ' ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 项目ID ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = False , comment = ' 任务状态: pending/running/completed/failed ' ) ,
sa . Column ( ' progress ' , sa . Integer ( ) , nullable = True , comment = ' 进度 0-100 ' ) ,
sa . Column ( ' error_message ' , sa . Text ( ) , nullable = True , comment = ' 错误信息 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' started_at ' , sa . DateTime ( ) , nullable = True , comment = ' 开始执行时间 ' ) ,
sa . Column ( ' completed_at ' , sa . DateTime ( ) , nullable = True , comment = ' 完成时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' chapter_id ' ] , [ ' chapters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' analysis_tasks ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_chapter_id_created ' , [ ' chapter_id ' , ' created_at ' ] , unique = False )
batch_op . create_index ( ' idx_status ' , [ ' status ' ] , unique = False )
op . create_table ( ' character_careers ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' character_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' career_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' career_type ' , sa . String ( length = 20 ) , nullable = False , comment = ' main(主职业)/sub(副职业) ' ) ,
sa . Column ( ' current_stage ' , sa . Integer ( ) , nullable = False , comment = ' 当前阶段(对应职业中的数值) ' ) ,
sa . Column ( ' stage_progress ' , sa . Integer ( ) , nullable = True , comment = ' 阶段内进度(0-100) ' ) ,
sa . Column ( ' started_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 开始修炼时间(小说时间线) ' ) ,
sa . Column ( ' reached_current_stage_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 到达当前阶段时间 ' ) ,
sa . Column ( ' notes ' , sa . Text ( ) , nullable = True , comment = ' 备注(如:修炼心得、特殊事件) ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' career_id ' ] , [ ' careers.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' character_id ' ] , [ ' characters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' character_careers ' , schema = None ) as batch_op :
batch_op . create_index ( ' idx_career_type ' , [ ' career_type ' ] , unique = False )
batch_op . create_index ( ' idx_character_career ' , [ ' character_id ' , ' career_id ' ] , unique = True )
batch_op . create_index ( ' idx_character_id ' , [ ' character_id ' ] , unique = False )
op . create_table ( ' character_relationships ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 关系ID ' ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 项目ID ' ) ,
sa . Column ( ' character_from_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 角色A的ID ' ) ,
sa . Column ( ' character_to_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 角色B的ID ' ) ,
sa . Column ( ' relationship_type_id ' , sa . Integer ( ) , nullable = True , comment = ' 关系类型ID ' ) ,
sa . Column ( ' relationship_name ' , sa . String ( length = 100 ) , nullable = True , comment = ' 自定义关系名称 ' ) ,
sa . Column ( ' intimacy_level ' , sa . Integer ( ) , nullable = True , comment = ' 亲密度:-100到100 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 状态:active/broken/past/complicated ' ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 关系详细描述 ' ) ,
sa . Column ( ' started_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 关系开始时间(故事时间) ' ) ,
sa . Column ( ' ended_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 关系结束时间(故事时间) ' ) ,
sa . Column ( ' source ' , sa . String ( length = 20 ) , nullable = True , comment = ' 来源:ai/manual/imported ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' character_from_id ' ] , [ ' characters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' character_to_id ' ] , [ ' characters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' relationship_type_id ' ] , [ ' relationship_types.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' character_relationships ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_character_relationships_character_from_id ' ) , [ ' character_from_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_character_relationships_character_to_id ' ) , [ ' character_to_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_character_relationships_project_id ' ) , [ ' project_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_character_relationships_relationship_type_id ' ) , [ ' relationship_type_id ' ] , unique = False )
op . create_table ( ' generation_history ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' chapter_id ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' prompt ' , sa . Text ( ) , nullable = True , comment = ' 使用的提示词 ' ) ,
sa . Column ( ' generated_content ' , sa . Text ( ) , nullable = True , comment = ' 生成的内容 ' ) ,
sa . Column ( ' model ' , sa . String ( length = 50 ) , nullable = True , comment = ' 使用的模型 ' ) ,
sa . Column ( ' tokens_used ' , sa . Integer ( ) , nullable = True , comment = ' 消耗的token数 ' ) ,
sa . Column ( ' generation_time ' , sa . Float ( ) , nullable = True , comment = ' 生成耗时(秒) ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' chapter_id ' ] , [ ' chapters.id ' ] , ondelete = ' SET NULL ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' organizations ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 组织ID ' ) ,
sa . Column ( ' character_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 关联的角色ID ' ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 项目ID ' ) ,
sa . Column ( ' parent_org_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 父组织ID ' ) ,
sa . Column ( ' level ' , sa . Integer ( ) , nullable = True , comment = ' 组织层级 ' ) ,
sa . Column ( ' power_level ' , sa . Integer ( ) , nullable = True , comment = ' 势力等级:0-100 ' ) ,
sa . Column ( ' member_count ' , sa . Integer ( ) , nullable = True , comment = ' 成员数量 ' ) ,
sa . Column ( ' location ' , sa . Text ( ) , nullable = True , comment = ' 所在地 ' ) ,
sa . Column ( ' motto ' , sa . String ( length = 200 ) , nullable = True , comment = ' 宗旨/口号 ' ) ,
sa . Column ( ' color ' , sa . String ( length = 100 ) , nullable = True , comment = ' 代表颜色 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' character_id ' ] , [ ' characters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' parent_org_id ' ] , [ ' organizations.id ' ] , ondelete = ' SET NULL ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' ) ,
sa . UniqueConstraint ( ' character_id ' )
)
with op . batch_alter_table ( ' organizations ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_organizations_project_id ' ) , [ ' project_id ' ] , unique = False )
op . create_table ( ' plot_analysis ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' chapter_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' plot_stage ' , sa . String ( length = 50 ) , nullable = True , comment = ' 剧情阶段: 开端/发展/高潮/结局/过渡 ' ) ,
sa . Column ( ' conflict_level ' , sa . Integer ( ) , nullable = True , comment = ' 冲突强度 1-10 ' ) ,
sa . Column ( ' conflict_types ' , sa . JSON ( ) , nullable = True , comment = " 冲突类型列表: [ ' 人与人 ' , ' 人与己 ' , ' 人与环境 ' ] " ) ,
sa . Column ( ' emotional_tone ' , sa . String ( length = 100 ) , nullable = True , comment = ' 主导情感: 紧张/温馨/悲伤/激昂/平静 ' ) ,
sa . Column ( ' emotional_intensity ' , sa . Float ( ) , nullable = True , comment = ' 情感强度 0.0-1.0 ' ) ,
sa . Column ( ' emotional_curve ' , sa . JSON ( ) , nullable = True , comment = ' 情感曲线: { start: 0.3, middle: 0.7, end: 0.5} ' ) ,
sa . Column ( ' hooks ' , sa . JSON ( ) , nullable = True , comment = ' 钩子列表 - 吸引读者的元素: [ \n { \n " type " : " 悬念|情感|冲突|认知 " , \n " content " : " 具体内容 " , \n " strength " : 8, \n " position " : " 开头|中段|结尾 " \n } \n ] ' ) ,
sa . Column ( ' hooks_count ' , sa . Integer ( ) , nullable = True , comment = ' 钩子数量 ' ) ,
sa . Column ( ' hooks_avg_strength ' , sa . Float ( ) , nullable = True , comment = ' 钩子平均强度 ' ) ,
sa . Column ( ' foreshadows ' , sa . JSON ( ) , nullable = True , comment = ' 伏笔列表: [ \n { \n " content " : " 伏笔内容 " , \n " type " : " planted|resolved " , \n " strength " : 7, \n " subtlety " : 8, \n " reference_chapter " : 3 \n } \n ] ' ) ,
sa . Column ( ' foreshadows_planted ' , sa . Integer ( ) , nullable = True , comment = ' 本章埋下的伏笔数量 ' ) ,
sa . Column ( ' foreshadows_resolved ' , sa . Integer ( ) , nullable = True , comment = ' 本章回收的伏笔数量 ' ) ,
sa . Column ( ' plot_points ' , sa . JSON ( ) , nullable = True , comment = ' 情节点列表: [ \n { \n " content " : " 情节点描述 " , \n " importance " : 0.9, \n " type " : " revelation|conflict|resolution|transition " , \n " impact " : " 对故事的影响描述 " \n } \n ] ' ) ,
sa . Column ( ' plot_points_count ' , sa . Integer ( ) , nullable = True , comment = ' 情节点数量 ' ) ,
sa . Column ( ' character_states ' , sa . JSON ( ) , nullable = True , comment = ' 角色状态变化: [ \n { \n " character_id " : " xxx " , \n " character_name " : " 张三 " , \n " state_before " : " 犹豫不决 " , \n " state_after " : " 坚定信念 " , \n " psychological_change " : " 内心描述 " , \n " key_event " : " 触发事件 " , \n " relationship_changes " : { " 李四 " : " 关系变化 " } \n } \n ] ' ) ,
sa . Column ( ' scenes ' , sa . JSON ( ) , nullable = True , comment = " 场景列表: [ { location: ' 地点 ' , atmosphere: ' 氛围 ' , duration: ' 时长 ' }] " ) ,
sa . Column ( ' pacing ' , sa . String ( length = 50 ) , nullable = True , comment = ' 节奏: slow|moderate|fast|varied ' ) ,
sa . Column ( ' overall_quality_score ' , sa . Float ( ) , nullable = True , comment = ' 整体质量评分 0.0-10.0 ' ) ,
sa . Column ( ' pacing_score ' , sa . Float ( ) , nullable = True , comment = ' 节奏评分 0.0-10.0 ' ) ,
sa . Column ( ' engagement_score ' , sa . Float ( ) , nullable = True , comment = ' 吸引力评分 0.0-10.0 ' ) ,
sa . Column ( ' coherence_score ' , sa . Float ( ) , nullable = True , comment = ' 连贯性评分 0.0-10.0 ' ) ,
sa . Column ( ' analysis_report ' , sa . Text ( ) , nullable = True , comment = ' 完整的文字分析报告 ' ) ,
sa . Column ( ' suggestions ' , sa . JSON ( ) , nullable = True , comment = " 改进建议列表: [ ' 建议1 ' , ' 建议2 ' ] " ) ,
sa . Column ( ' word_count ' , sa . Integer ( ) , nullable = True , comment = ' 章节字数 ' ) ,
sa . Column ( ' dialogue_ratio ' , sa . Float ( ) , nullable = True , comment = ' 对话占比 0.0-1.0 ' ) ,
sa . Column ( ' description_ratio ' , sa . Float ( ) , nullable = True , comment = ' 描写占比 0.0-1.0 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 分析时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' chapter_id ' ] , [ ' chapters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' plot_analysis ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_plot_analysis_chapter_id ' ) , [ ' chapter_id ' ] , unique = True )
batch_op . create_index ( batch_op . f ( ' ix_plot_analysis_project_id ' ) , [ ' project_id ' ] , unique = False )
op . create_table ( ' regeneration_tasks ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' chapter_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' analysis_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 关联的分析结果ID ' ) ,
sa . Column ( ' user_id ' , sa . String ( length = 50 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' modification_instructions ' , sa . Text ( ) , nullable = False , comment = ' 综合修改指令 ' ) ,
sa . Column ( ' original_suggestions ' , sa . JSON ( ) , nullable = True , comment = ' 来自分析的原始建议列表 ' ) ,
sa . Column ( ' selected_suggestion_indices ' , sa . JSON ( ) , nullable = True , comment = ' 用户选择的建议索引 ' ) ,
sa . Column ( ' custom_instructions ' , sa . Text ( ) , nullable = True , comment = ' 用户自定义修改意见 ' ) ,
sa . Column ( ' style_id ' , sa . Integer ( ) , nullable = True , comment = ' 写作风格ID ' ) ,
sa . Column ( ' target_word_count ' , sa . Integer ( ) , nullable = True , comment = ' 目标字数 ' ) ,
sa . Column ( ' focus_areas ' , sa . JSON ( ) , nullable = True , comment = ' 重点优化方向 ' ) ,
sa . Column ( ' preserve_elements ' , sa . JSON ( ) , nullable = True , comment = ' 需要保留的元素配置 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' pending/running/completed/failed ' ) ,
sa . Column ( ' progress ' , sa . Integer ( ) , nullable = True , comment = ' 进度 0-100 ' ) ,
sa . Column ( ' error_message ' , sa . Text ( ) , nullable = True ) ,
sa . Column ( ' original_content ' , sa . Text ( ) , nullable = True , comment = ' 原始章节内容快照 ' ) ,
sa . Column ( ' original_word_count ' , sa . Integer ( ) , nullable = True , comment = ' 原始字数 ' ) ,
sa . Column ( ' regenerated_content ' , sa . Text ( ) , nullable = True , comment = ' 重新生成的内容 ' ) ,
sa . Column ( ' regenerated_word_count ' , sa . Integer ( ) , nullable = True , comment = ' 新内容字数 ' ) ,
sa . Column ( ' version_number ' , sa . Integer ( ) , nullable = True , comment = ' 版本号 ' ) ,
sa . Column ( ' version_note ' , sa . String ( length = 500 ) , nullable = True , comment = ' 版本说明 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True ) ,
sa . Column ( ' started_at ' , sa . DateTime ( ) , nullable = True ) ,
sa . Column ( ' completed_at ' , sa . DateTime ( ) , nullable = True ) ,
sa . ForeignKeyConstraint ( [ ' chapter_id ' ] , [ ' chapters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' regeneration_tasks ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_regeneration_tasks_chapter_id ' ) , [ ' chapter_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_regeneration_tasks_project_id ' ) , [ ' project_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_regeneration_tasks_user_id ' ) , [ ' user_id ' ] , unique = False )
op . create_table ( ' story_memories ' ,
sa . Column ( ' id ' , sa . String ( length = 100 ) , nullable = False ) ,
sa . Column ( ' project_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' chapter_id ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' memory_type ' , sa . String ( length = 50 ) , nullable = False , comment = ' \n 记忆类型: \n - plot_point: 情节点 \n - character_event: 角色事件 \n - world_detail: 世界观细节 \n - hook: 钩子(悬念/冲突) \n - foreshadow: 伏笔 \n - dialogue: 重要对话 \n - scene: 场景描写 \n ' ) ,
sa . Column ( ' title ' , sa . String ( length = 200 ) , nullable = True , comment = ' 记忆标题/简述 ' ) ,
sa . Column ( ' content ' , sa . Text ( ) , nullable = False , comment = ' 记忆内容摘要(100-500字) ' ) ,
sa . Column ( ' full_context ' , sa . Text ( ) , nullable = True , comment = ' 完整上下文(可选,用于详细记录) ' ) ,
sa . Column ( ' related_characters ' , sa . JSON ( ) , nullable = True , comment = " 涉及角色ID列表: [ ' char_id_1 ' , ' char_id_2 ' ] " ) ,
sa . Column ( ' related_locations ' , sa . JSON ( ) , nullable = True , comment = " 涉及地点列表: [ ' 地点1 ' , ' 地点2 ' ] " ) ,
sa . Column ( ' tags ' , sa . JSON ( ) , nullable = True , comment = " 标签列表: [ ' 悬念 ' , ' 转折 ' , ' 伏笔 ' , ' 高潮 ' ] " ) ,
sa . Column ( ' importance_score ' , sa . Float ( ) , nullable = True , comment = ' 重要性评分 0.0-1.0 ' ) ,
sa . Column ( ' story_timeline ' , sa . Integer ( ) , nullable = False , comment = ' 故事时间线位置(章节序号) ' ) ,
sa . Column ( ' chapter_position ' , sa . Integer ( ) , nullable = True , comment = ' 章节内位置(字符位置) ' ) ,
sa . Column ( ' text_length ' , sa . Integer ( ) , nullable = True , comment = ' 文本长度(字符数) ' ) ,
sa . Column ( ' is_foreshadow ' , sa . Integer ( ) , nullable = True , comment = ' 伏笔状态: 0=普通记忆, 1=已埋下伏笔, 2=伏笔已回收 ' ) ,
sa . Column ( ' foreshadow_resolved_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 伏笔回收的章节ID ' ) ,
sa . Column ( ' foreshadow_strength ' , sa . Float ( ) , nullable = True , comment = ' 伏笔强度 0.0-1.0 ' ) ,
sa . Column ( ' vector_id ' , sa . String ( length = 100 ) , nullable = True , comment = ' 向量数据库中的唯一ID ' ) ,
sa . Column ( ' embedding_model ' , sa . String ( length = 100 ) , nullable = True , comment = ' 使用的embedding模型 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' chapter_id ' ] , [ ' chapters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' foreshadow_resolved_at ' ] , [ ' chapters.id ' ] , ondelete = ' SET NULL ' ) ,
sa . ForeignKeyConstraint ( [ ' project_id ' ] , [ ' projects.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' ) ,
sa . UniqueConstraint ( ' vector_id ' )
)
with op . batch_alter_table ( ' story_memories ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_story_memories_chapter_id ' ) , [ ' chapter_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_story_memories_memory_type ' ) , [ ' memory_type ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_story_memories_project_id ' ) , [ ' project_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_story_memories_story_timeline ' ) , [ ' story_timeline ' ] , unique = False )
op . create_table ( ' organization_members ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 成员关系ID ' ) ,
sa . Column ( ' organization_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 组织ID ' ) ,
sa . Column ( ' character_id ' , sa . String ( length = 36 ) , nullable = False , comment = ' 角色ID ' ) ,
sa . Column ( ' position ' , sa . String ( length = 100 ) , nullable = False , comment = ' 职位名称 ' ) ,
sa . Column ( ' rank ' , sa . Integer ( ) , nullable = True , comment = ' 职位等级 ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = True , comment = ' 状态:active/retired/expelled/deceased ' ) ,
sa . Column ( ' joined_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 加入时间(故事时间) ' ) ,
sa . Column ( ' left_at ' , sa . String ( length = 100 ) , nullable = True , comment = ' 离开时间(故事时间) ' ) ,
sa . Column ( ' loyalty ' , sa . Integer ( ) , nullable = True , comment = ' 忠诚度:0-100 ' ) ,
sa . Column ( ' contribution ' , sa . Integer ( ) , nullable = True , comment = ' 贡献度:0-100 ' ) ,
sa . Column ( ' source ' , sa . String ( length = 20 ) , nullable = True , comment = ' 来源:ai/manual ' ) ,
sa . Column ( ' notes ' , sa . Text ( ) , nullable = True , comment = ' 备注 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 创建时间 ' ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( ) , server_default = sa . text ( ' (CURRENT_TIMESTAMP) ' ) , nullable = True , comment = ' 更新时间 ' ) ,
sa . ForeignKeyConstraint ( [ ' character_id ' ] , [ ' characters.id ' ] , ondelete = ' CASCADE ' ) ,
sa . ForeignKeyConstraint ( [ ' organization_id ' ] , [ ' organizations.id ' ] , ondelete = ' CASCADE ' ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
with op . batch_alter_table ( ' organization_members ' , schema = None ) as batch_op :
batch_op . create_index ( batch_op . f ( ' ix_organization_members_character_id ' ) , [ ' character_id ' ] , unique = False )
batch_op . create_index ( batch_op . f ( ' ix_organization_members_organization_id ' ) , [ ' organization_id ' ] , unique = False )
# ### end Alembic commands ###
def downgrade ( ) - > None :
# ### commands auto generated by Alembic - please adjust! ###
with op . batch_alter_table ( ' organization_members ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_organization_members_organization_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_organization_members_character_id ' ) )
op . drop_table ( ' organization_members ' )
with op . batch_alter_table ( ' story_memories ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_story_memories_story_timeline ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_story_memories_project_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_story_memories_memory_type ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_story_memories_chapter_id ' ) )
op . drop_table ( ' story_memories ' )
with op . batch_alter_table ( ' regeneration_tasks ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_regeneration_tasks_user_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_regeneration_tasks_project_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_regeneration_tasks_chapter_id ' ) )
op . drop_table ( ' regeneration_tasks ' )
with op . batch_alter_table ( ' plot_analysis ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_plot_analysis_project_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_plot_analysis_chapter_id ' ) )
op . drop_table ( ' plot_analysis ' )
with op . batch_alter_table ( ' organizations ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_organizations_project_id ' ) )
op . drop_table ( ' organizations ' )
op . drop_table ( ' generation_history ' )
with op . batch_alter_table ( ' character_relationships ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_character_relationships_relationship_type_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_character_relationships_project_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_character_relationships_character_to_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_character_relationships_character_from_id ' ) )
op . drop_table ( ' character_relationships ' )
with op . batch_alter_table ( ' character_careers ' , schema = None ) as batch_op :
batch_op . drop_index ( ' idx_character_id ' )
batch_op . drop_index ( ' idx_character_career ' )
batch_op . drop_index ( ' idx_career_type ' )
op . drop_table ( ' character_careers ' )
with op . batch_alter_table ( ' analysis_tasks ' , schema = None ) as batch_op :
batch_op . drop_index ( ' idx_status ' )
batch_op . drop_index ( ' idx_chapter_id_created ' )
op . drop_table ( ' analysis_tasks ' )
op . drop_table ( ' project_default_styles ' )
op . drop_table ( ' characters ' )
op . drop_table ( ' chapters ' )
op . drop_table ( ' writing_styles ' )
op . drop_table ( ' outlines ' )
with op . batch_alter_table ( ' careers ' , schema = None ) as batch_op :
batch_op . drop_index ( ' idx_type ' )
batch_op . drop_index ( ' idx_project_id ' )
op . drop_table ( ' careers ' )
with op . batch_alter_table ( ' users ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_users_username ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_users_user_id ' ) )
batch_op . drop_index ( batch_op . f ( ' ix_users_linuxdo_id ' ) )
op . drop_table ( ' users ' )
with op . batch_alter_table ( ' user_passwords ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_user_passwords_user_id ' ) )
op . drop_table ( ' user_passwords ' )
with op . batch_alter_table ( ' settings ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_settings_user_id ' ) )
batch_op . drop_index ( ' idx_user_id ' )
op . drop_table ( ' settings ' )
with op . batch_alter_table ( ' relationship_types ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_relationship_types_id ' ) )
op . drop_table ( ' relationship_types ' )
with op . batch_alter_table ( ' prompt_templates ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_prompt_templates_user_id ' ) )
batch_op . drop_index ( ' idx_user_template ' )
op . drop_table ( ' prompt_templates ' )
with op . batch_alter_table ( ' projects ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_projects_user_id ' ) )
op . drop_table ( ' projects ' )
with op . batch_alter_table ( ' mcp_plugins ' , schema = None ) as batch_op :
batch_op . drop_index ( batch_op . f ( ' ix_mcp_plugins_user_id ' ) )
batch_op . drop_index ( ' idx_user_plugin ' )
batch_op . drop_index ( ' idx_user_enabled ' )
op . drop_table ( ' mcp_plugins ' )
op . drop_table ( ' batch_generation_tasks ' )
# ### end Alembic commands ###