From c1eb8bd51aa2d469ea8bb7c5c08468db6ec01018 Mon Sep 17 00:00:00 2001 From: extreme Date: Sat, 4 Apr 2026 09:59:54 +0800 Subject: [PATCH] [feat] Enhance SQL scripts: add conditional column creation and index checks for shots and shot_extracted_candidates --- backend/sql/001-init-prompt-template.sql | 12 +-- .../sql/002-add-shot-extracted-candidates.sql | 87 ++++++++++++++++--- deploy/compose/docker-compose.yml | 2 +- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/backend/sql/001-init-prompt-template.sql b/backend/sql/001-init-prompt-template.sql index 185ab43..a9c2b4a 100644 --- a/backend/sql/001-init-prompt-template.sql +++ b/backend/sql/001-init-prompt-template.sql @@ -1,21 +1,21 @@ BEGIN; SET NAMES utf8mb4; - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('1', 'actor_image_front', '演员正面图片提示词', '默认演员正面提示词', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高质量电影级{{ visual_style }}人像摄影,超详细专业演员写真:\n{{ description }}\n\n镜头方向:正面\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感浅景深,f/1.4大光圈,背景虚化自然明显\n- 专业商业人像摄影风格 + 当代电影剧照质感\n- 自然生动表情,富有故事感和角色沉浸感\n- 优秀构图,经典三分法或黄金分割构图\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}\n{%- if \"古装\" in style or \"古代\" in style -%}\nmodern clothing, modern background, contemporary elements\n{%- endif -%}', '[\"description\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-17 06:38:57', '2026-03-30 16:00:00', 1, 1); - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('2', 'actor_image_other', '演员侧面/后面图片提示词', '演员非正面视角', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高度一致的人物,身份保留。与参考图像中完全相同的人的肖像,100%身份一致性,相同的面部结构,相同的发型,相同的服装,相同的妆容,相同的年龄和表情基础。\n视角完全切换为:{{ view_angle }},从这个角度看到的同一人,正确的透视和轮廓,头部朝向自然符合该视角,无任何正面元素残留,无脸部扭曲\n演员姿态:站立挺直,中立姿势\n{{ extra_details }}\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感浅景深,f/1.4大光圈,背景虚化自然明显\n- 专业商业人像摄影风格 + 当代电影剧照质感\n- 自然生动表情,富有故事感和角色沉浸感\n- 优秀构图,经典三分法或黄金分割构图\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}\n{%- if \"古装\" in style or \"古代\" in style -%}\nmodern clothing, modern background, contemporary elements\n{%- endif -%}', '[\"view_angle\", \"extra_details\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-17 16:30:00', '2026-03-30 16:00:00', 1, 1); - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('3', 'character_image_front', '角色正面图片提示词', '角色正面图片提示词', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高度一致的人物,身份保留。与参考图像1中完全相同的人的肖像,100%身份一致性,相同的面部结构,相同的发型,相同的妆容,相同的年龄和表情基础。如果参考图像2存在,使用参考图像2的服装。\n演员姿态:站立挺直,中立姿势\n{{ extra_details }}\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感浅景深,f/1.4大光圈,背景虚化自然明显\n- 专业商业人像摄影风格 + 当代电影剧照质感\n- 自然生动表情,富有故事感和角色沉浸感\n- 优秀构图,经典三分法或黄金分割构图\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}\n{%- if \"古装\" in style or \"古代\" in style -%}\nmodern clothing, modern background, contemporary elements\n{%- endif -%}', '[\"extra_details\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-19 09:00:34', '2026-03-30 16:00:00', 0, 0); - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('4', 'prop_image_front', '道具图片提示词', '高质量道具特写', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高质量电影级{{ visual_style }}产品摄影 / 道具特写,超详细真实质感:\n{{ description }}\n镜头方向:{{ view }},经典产品/道具拍摄角度\n{{ extra_details }}\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感浅景深,f/1.4 或 f/2.8,背景虚化明显\n- 专业商业产品摄影风格 + 当代电影道具质感\n- 真实材质表现,金属反光/皮革纹理/玻璃折射/布料纤维清晰可见\n- 优秀构图,经典三分法或对称/中心式构图\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}', '[\"description\", \"view\", \"extra_details\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-17 16:30:00', '2026-03-30 16:00:00', 1, 1); - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('5', 'scene_image_front', '场景图片提示词', '高质量电影场景', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高质量电影级{{ visual_style }}场景画面,超详细环境氛围:\n{{ description }}\n镜头方向:{{ view }}\n画面主体位置:画面正中\n{{ extra_details }}\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感景深,f/2.8~f/5.6,视觉层次丰富\n- 专业电影场景摄影风格 + 当代剧照质感\n- 真实光影与氛围,光源方向明确,环境粒子/雾气/雨丝/光斑自然\n- 优秀构图,引导线、层次感强,前中后景分明\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}', '[\"description\", \"view\", \"extra_details\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-17 16:30:00', '2026-03-30 16:00:00', 1, 1); - INSERT INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) + INSERT IGNORE INTO `prompt_templates` (`id`, `category`, `name`, `preview`, `content`, `variables`, `created_at`, `updated_at`, `is_system`, `is_default`) VALUES ('6', 'costume_image_front', '服装图片提示词', '高质量服装呈现', '视觉风格:{{ visual_style }}\n画面风格:{{ style }}\n\n高质量电影级{{ visual_style }}服装特写 / 全身着装呈现,超详细布料质感:\n{{ description }}\n穿着方式:完整全身穿着\n{{ extra_details }}\n画面要求:\n- 超高细节,8k分辨率,极致锐度与纹理\n- 电影感浅景深或中景深,f/1.8~f/4,突出服装质感\n- 专业时尚/电影服装摄影风格 + 当代剧照质感\n- 真实布料纹理、车线、钮扣、金属配件、褶皱、磨损细节清晰可见\n- 优秀构图,服装为画面主体或占2/3以上面积\n- 完美贴合{{ visual_style }}视觉语言与{{ style }}整体氛围,风格高度一致\n\n负面提示(强烈负面):\nlow quality, worst quality, blurry, deformed, bad anatomy, bad hands, missing fingers, extra limbs, poorly drawn face, bad proportions, watermark, text, logo, signature, overexposed, underexposed, plastic skin, doll, lowres, jpeg artifacts, grainy\n{%- if \"动漫\" in visual_style or \"anime\" in visual_style.lower() -%}\nbad anime, deformed anime, low quality anime, flat color, flat shading, 3d render, cgi\n{%- else -%}\ncartoon, 3d render, cgi, illustration, painting, sketch, anime\n{%- endif -%}', '[\"description\", \"extra_details\", \"visual_style\", \"style\", \"base_negative\"]', '2026-03-17 16:30:00', '2026-03-30 16:00:00', 1, 1); COMMIT; diff --git a/backend/sql/002-add-shot-extracted-candidates.sql b/backend/sql/002-add-shot-extracted-candidates.sql index 980b630..2556dd2 100644 --- a/backend/sql/002-add-shot-extracted-candidates.sql +++ b/backend/sql/002-add-shot-extracted-candidates.sql @@ -6,13 +6,39 @@ BEGIN; -ALTER TABLE shots - ADD COLUMN skip_extraction BOOLEAN NOT NULL DEFAULT 0; +SET @skip_extraction_exists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shots' + AND COLUMN_NAME = 'skip_extraction' +); +SET @sql = IF( + @skip_extraction_exists = 0, + 'ALTER TABLE shots ADD COLUMN skip_extraction BOOLEAN NOT NULL DEFAULT 0', + 'SELECT 1' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; -ALTER TABLE shots - ADD COLUMN last_extracted_at DATETIME NULL; +SET @last_extracted_at_exists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shots' + AND COLUMN_NAME = 'last_extracted_at' +); +SET @sql = IF( + @last_extracted_at_exists = 0, + 'ALTER TABLE shots ADD COLUMN last_extracted_at DATETIME NULL', + 'SELECT 1' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; -CREATE TABLE shot_extracted_candidates ( +CREATE TABLE IF NOT EXISTS shot_extracted_candidates ( id INTEGER PRIMARY KEY AUTO_INCREMENT, shot_id VARCHAR(64) NOT NULL, candidate_type VARCHAR(32) NOT NULL, @@ -34,13 +60,52 @@ CREATE TABLE shot_extracted_candidates ( CHECK (candidate_status IN ('pending', 'linked', 'ignored')) ); -CREATE INDEX ix_shot_extracted_candidates_shot_id - ON shot_extracted_candidates (shot_id); +SET @shot_id_index_exists = ( + SELECT COUNT(*) + FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shot_extracted_candidates' + AND INDEX_NAME = 'ix_shot_extracted_candidates_shot_id' +); +SET @sql = IF( + @shot_id_index_exists = 0, + 'CREATE INDEX ix_shot_extracted_candidates_shot_id ON shot_extracted_candidates (shot_id)', + 'SELECT 1' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; -CREATE INDEX ix_shot_extracted_candidates_status - ON shot_extracted_candidates (candidate_status); +SET @status_index_exists = ( + SELECT COUNT(*) + FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shot_extracted_candidates' + AND INDEX_NAME = 'ix_shot_extracted_candidates_status' +); +SET @sql = IF( + @status_index_exists = 0, + 'CREATE INDEX ix_shot_extracted_candidates_status ON shot_extracted_candidates (candidate_status)', + 'SELECT 1' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; -CREATE INDEX ix_shot_extracted_candidates_type - ON shot_extracted_candidates (candidate_type); +SET @type_index_exists = ( + SELECT COUNT(*) + FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shot_extracted_candidates' + AND INDEX_NAME = 'ix_shot_extracted_candidates_type' +); +SET @sql = IF( + @type_index_exists = 0, + 'CREATE INDEX ix_shot_extracted_candidates_type ON shot_extracted_candidates (candidate_type)', + 'SELECT 1' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; COMMIT; diff --git a/deploy/compose/docker-compose.yml b/deploy/compose/docker-compose.yml index 117571e..240cada 100644 --- a/deploy/compose/docker-compose.yml +++ b/deploy/compose/docker-compose.yml @@ -69,7 +69,7 @@ services: [ "bash", "-lc", - "set -e; for f in $(find /sql -maxdepth 1 -type f -name '*.sql' | sort); do echo \"[mysql-init-sql] applying $f\"; mysql --default-character-set=utf8mb4 -h mysql -u\"$MYSQL_USER\" -p\"$MYSQL_PASSWORD\" \"$MYSQL_DATABASE\" < \"$f\"; done", + "set -e; find /sql -maxdepth 1 -type f -name '*.sql' | sort | while IFS= read -r f; do echo \"[mysql-init-sql] applying $$f\"; mysql --default-character-set=utf8mb4 -h mysql -u\"$$MYSQL_USER\" -p\"$$MYSQL_PASSWORD\" \"$$MYSQL_DATABASE\" < \"$$f\"; done", ] restart: "no"