feature: 新增伏笔管理系统,支持可视化追踪、AI智能关联回收及章节生成时的伏笔提醒
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""添加伏笔管理表
|
||||
|
||||
Revision ID: 951919659e0f
|
||||
Revises: 7899f8d4d839
|
||||
Create Date: 2026-01-19 10:05:40.794044
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '951919659e0f'
|
||||
down_revision: Union[str, None] = '7899f8d4d839'
|
||||
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('foreshadows',
|
||||
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=False, comment='伏笔详细内容/描述'),
|
||||
sa.Column('hint_text', sa.Text(), nullable=True, comment='埋伏笔时的暗示文本(原文摘录或概述)'),
|
||||
sa.Column('resolution_text', sa.Text(), nullable=True, comment='回收伏笔时的揭示文本(原文摘录或概述)'),
|
||||
sa.Column('source_type', sa.String(length=20), nullable=True, comment='来源类型: analysis=分析提取, manual=手动添加'),
|
||||
sa.Column('source_memory_id', sa.String(length=100), nullable=True, comment='来源记忆ID(如从分析结果同步)'),
|
||||
sa.Column('source_analysis_id', sa.String(length=36), nullable=True, comment='来源分析任务ID'),
|
||||
sa.Column('plant_chapter_id', sa.String(length=36), nullable=True, comment='埋入章节ID'),
|
||||
sa.Column('plant_chapter_number', sa.Integer(), nullable=True, comment='埋入章节号(冗余存储便于查询)'),
|
||||
sa.Column('target_resolve_chapter_id', sa.String(length=36), nullable=True, comment='计划回收章节ID'),
|
||||
sa.Column('target_resolve_chapter_number', sa.Integer(), nullable=True, comment='计划回收章节号'),
|
||||
sa.Column('actual_resolve_chapter_id', sa.String(length=36), nullable=True, comment='实际回收章节ID'),
|
||||
sa.Column('actual_resolve_chapter_number', sa.Integer(), nullable=True, comment='实际回收章节号'),
|
||||
sa.Column('status', sa.String(length=20), nullable=True, comment='\n 伏笔状态:\n - pending: 待埋入(已规划但未写入章节)\n - planted: 已埋入(已在章节中埋下)\n - resolved: 已回收(已在章节中回收)\n - partially_resolved: 部分回收(长线伏笔可能分多次回收)\n - abandoned: 已废弃(决定不再使用此伏笔)\n '),
|
||||
sa.Column('is_long_term', sa.Boolean(), nullable=True, comment='是否长线伏笔(跨多章的重要伏笔)'),
|
||||
sa.Column('importance', sa.Float(), nullable=True, comment='重要性评分 0.0-1.0'),
|
||||
sa.Column('strength', sa.Integer(), nullable=True, comment='伏笔强度 1-10(影响读者多强烈)'),
|
||||
sa.Column('subtlety', sa.Integer(), nullable=True, comment='隐藏度 1-10(越高越隐蔽)'),
|
||||
sa.Column('urgency', sa.Integer(), nullable=True, comment='紧急度: 0=不紧急, 1=需关注, 2=急需回收'),
|
||||
sa.Column('related_characters', sa.JSON(), nullable=True, comment="关联角色名列表: ['角色1', '角色2']"),
|
||||
sa.Column('related_foreshadow_ids', sa.JSON(), nullable=True, comment='关联的其他伏笔ID列表(伏笔链)'),
|
||||
sa.Column('tags', sa.JSON(), nullable=True, comment="标签列表: ['身世', '悬念', '反转']"),
|
||||
sa.Column('category', sa.String(length=50), nullable=True, comment='分类: identity(身世), mystery(悬念), item(物品), relationship(关系), event(事件)'),
|
||||
sa.Column('notes', sa.Text(), nullable=True, comment='创作备注(仅作者可见)'),
|
||||
sa.Column('resolution_notes', sa.Text(), nullable=True, comment='回收方式说明'),
|
||||
sa.Column('auto_remind', sa.Boolean(), nullable=True, comment='是否在章节生成时自动提醒'),
|
||||
sa.Column('remind_before_chapters', sa.Integer(), nullable=True, comment='提前几章开始提醒回收'),
|
||||
sa.Column('include_in_context', 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.Column('planted_at', sa.DateTime(), nullable=True, comment='埋入时间'),
|
||||
sa.Column('resolved_at', sa.DateTime(), nullable=True, comment='回收时间'),
|
||||
sa.ForeignKeyConstraint(['actual_resolve_chapter_id'], ['chapters.id'], ondelete='SET NULL'),
|
||||
sa.ForeignKeyConstraint(['plant_chapter_id'], ['chapters.id'], ondelete='SET NULL'),
|
||||
sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['target_resolve_chapter_id'], ['chapters.id'], ondelete='SET NULL'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
with op.batch_alter_table('foreshadows', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_foreshadows_project_id'), ['project_id'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_foreshadows_status'), ['status'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('foreshadows', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_foreshadows_status'))
|
||||
batch_op.drop_index(batch_op.f('ix_foreshadows_project_id'))
|
||||
|
||||
op.drop_table('foreshadows')
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user