feat: expand novel IP and production workflows
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
CREATE TABLE `character_design_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`version_no` INTEGER NOT NULL,
|
||||
`prompt_text` TEXT NULL,
|
||||
`negative_prompt` TEXT NULL,
|
||||
`image_asset_id` BIGINT NULL,
|
||||
`notes` TEXT NULL,
|
||||
`source` VARCHAR(50) NOT NULL DEFAULT 'workshop',
|
||||
`is_final` BOOLEAN NOT NULL DEFAULT false,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `character_design_versions_character_id_version_no_key`(`character_id`, `version_no`),
|
||||
INDEX `character_design_versions_project_id_character_id_idx`(`project_id`, `character_id`),
|
||||
INDEX `character_design_versions_character_id_is_final_idx`(`character_id`, `is_final`),
|
||||
INDEX `character_design_versions_image_asset_id_idx`(`image_asset_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `character_states` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`state_code` VARCHAR(80) NOT NULL,
|
||||
`display_name` VARCHAR(120) NULL,
|
||||
`description` TEXT NULL,
|
||||
`wardrobe_rules` TEXT NULL,
|
||||
`emotion_rules` TEXT NULL,
|
||||
`prompt_suffix` TEXT NULL,
|
||||
`negative_rules` TEXT NULL,
|
||||
`reference_asset_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `character_states_character_id_state_code_key`(`character_id`, `state_code`),
|
||||
INDEX `character_states_project_id_character_id_idx`(`project_id`, `character_id`),
|
||||
INDEX `character_states_status_idx`(`status`),
|
||||
INDEX `character_states_reference_asset_id_idx`(`reference_asset_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,51 @@
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'VideoProvider',
|
||||
'volcengine_seedance_20_fast',
|
||||
'火山方舟 Seedance 2.0 Fast 图生视频',
|
||||
'real',
|
||||
'doubao-seedance-2.0-fast',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"SEEDANCE_VIDEO","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":300000,"create_endpoint":"/videos/generations","task_endpoint_template":"/videos/generations/{task_id}","poll_interval_ms":10000,"max_poll_attempts":150,"image_field":"image","prompt_field":"prompt","model_field":"model","duration_field":"duration","resolution_field":"resolution","aspect_ratio_field":"ratio","duration":5,"resolution":"720p","aspect_ratio":"9:16","extra_body_json":{"watermark":false,"audio":false},"supports_reference_image":true,"supports_start_end_frame":true,"supports_audio":true,"supports_lipsync":true,"supports_character_reference":true,"note":"默认禁用。Seedance 2.0 Fast 适合先做快速小样;模型 ID 和字段请以火山方舟控制台实际开通为准。"}',
|
||||
false,
|
||||
77,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0,"currency":"CNY","max_cost_per_call":0,"daily_cost_limit":0,"estimated_seconds":5,"note":"Seedance 2.0 Fast 价格按火山方舟实际账单回填;启用前请设置单次和每日成本上限。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'volcengine_seedance_20',
|
||||
'火山方舟 Seedance 2.0 图生视频',
|
||||
'real',
|
||||
'doubao-seedance-2.0',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"SEEDANCE_VIDEO","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":300000,"create_endpoint":"/videos/generations","task_endpoint_template":"/videos/generations/{task_id}","poll_interval_ms":10000,"max_poll_attempts":180,"image_field":"image","prompt_field":"prompt","model_field":"model","duration_field":"duration","resolution_field":"resolution","aspect_ratio_field":"ratio","duration":5,"resolution":"720p","aspect_ratio":"9:16","extra_body_json":{"watermark":false,"audio":false},"supports_reference_image":true,"supports_start_end_frame":true,"supports_audio":true,"supports_lipsync":true,"supports_character_reference":true,"note":"默认禁用。质量优先的 Seedance 2.0 配置;正式调用前先用单镜头验证请求字段、返回结构和账单。"}',
|
||||
false,
|
||||
76,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0,"currency":"CNY","max_cost_per_call":0,"daily_cost_limit":0,"estimated_seconds":5,"note":"Seedance 2.0 价格按火山方舟实际账单回填;启用前请设置单次和每日成本上限。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`updated_at` = NOW(3);
|
||||
|
||||
UPDATE `system_configs`
|
||||
SET
|
||||
`config_value` = JSON_SET(
|
||||
`config_value`,
|
||||
'$."live_action_video"."zh-CN"."normal"."fallback_chain"',
|
||||
JSON_ARRAY('minimax_hailuo_23_fast', 'volcengine_seedance_20_fast', 'volcengine_seedance_20', 'jimeng_seedance', 'mock-video'),
|
||||
'$."live_action_video"."zh-CN"."premium"."fallback_chain"',
|
||||
JSON_ARRAY('kling-image-to-video', 'volcengine_seedance_20', 'minimax_hailuo_23_fast', 'volcengine_seedance_20_fast', 'jimeng_seedance', 'mock-video')
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `config_key` = 'ai.router.v1'
|
||||
AND JSON_TYPE(`config_value`) = 'OBJECT';
|
||||
@@ -0,0 +1,105 @@
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'TextProvider',
|
||||
'volcengine-doubao-seed20-pro-text',
|
||||
'Volcengine Doubao Seed 2.0 Pro Text',
|
||||
'real',
|
||||
'doubao-seed-2-0-pro-260215',
|
||||
'{"driver":"openai_compatible_chat","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","chat_endpoint":"/chat/completions","timeout_ms":120000,"max_tokens":3200,"temperature":0.7,"instructions":"你是中文短剧总编剧,负责高质量剧情策划、世界观、人设、分集大纲和可拍摄脚本。输出结构清晰、冲突强、方便继续生成分镜。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":60,"concurrency":3}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":1200,"note":"真实费用以后续账单或 usage 元数据核算;默认禁用,启用前请填写成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'volcengine-doubao-seed20-lite-text',
|
||||
'Volcengine Doubao Seed 2.0 Lite Text',
|
||||
'real',
|
||||
'doubao-seed-2-0-lite-260215',
|
||||
'{"driver":"openai_compatible_chat","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","chat_endpoint":"/chat/completions","timeout_ms":90000,"max_tokens":2400,"temperature":0.7,"instructions":"你是中文短剧生产助手,适合高频改写、分镜描述、标题钩子和运营文案。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":60,"concurrency":3}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":1200,"note":"真实费用以后续账单或 usage 元数据核算;默认禁用,启用前请填写成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'NovelProvider',
|
||||
'volcengine-doubao-seed20-pro-novel',
|
||||
'Volcengine Doubao Seed 2.0 Pro Novel',
|
||||
'real',
|
||||
'doubao-seed-2-0-pro-260215',
|
||||
'{"driver":"openai_compatible_chat","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","chat_endpoint":"/chat/completions","timeout_ms":150000,"max_tokens":5000,"temperature":0.7,"instructions":"你是中文网文与短剧改编主笔,擅长长上下文改编、人物弧光、爽点节奏和连续剧集结构。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":30,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":1200,"note":"真实费用以后续账单或 usage 元数据核算;默认禁用,启用前请填写成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'ImageProvider',
|
||||
'volcengine-seedream-50-image',
|
||||
'Volcengine Seedream 5.0 Image',
|
||||
'real',
|
||||
'doubao-seedream-5-0-260128',
|
||||
'{"driver":"configurable_image_generation","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":600000,"create_endpoint":"/images/generations","size":"1440x2560","output_format":"png","response_format":"b64_json","aspect_ratio":"9:16","extra_body_json":{"watermark":false},"note":"默认禁用。用于角色定妆、场景概念图、分镜关键帧;启用前先单图验证返回格式和账单。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":20,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":800,"note":"图片费用按供应商账单核算;默认禁用,启用前请填写单次/每日成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'ImageProvider',
|
||||
'volcengine-seedream-50-lite-image',
|
||||
'Volcengine Seedream 5.0 Lite Image',
|
||||
'real',
|
||||
'doubao-seedream-5-0-lite-260128',
|
||||
'{"driver":"configurable_image_generation","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":600000,"create_endpoint":"/images/generations","size":"1440x2560","output_format":"png","response_format":"b64_json","aspect_ratio":"9:16","extra_body_json":{"watermark":false},"note":"默认禁用。用于低成本高频角色草图、分镜草图和运营配图。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":20,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":800,"note":"图片费用按供应商账单核算;默认禁用,启用前请填写单次/每日成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'ImageProvider',
|
||||
'volcengine-seedream-45-image',
|
||||
'Volcengine Seedream 4.5 Image',
|
||||
'real',
|
||||
'doubao-seedream-4-5-251128',
|
||||
'{"driver":"configurable_image_generation","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":600000,"create_endpoint":"/images/generations","size":"1440x2560","output_format":"png","response_format":"b64_json","aspect_ratio":"9:16","extra_body_json":{"watermark":false},"note":"默认禁用。作为 Seedream 5.0 不可用时的图片生成 fallback。"}',
|
||||
false,
|
||||
30,
|
||||
'{"rpm":20,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","estimated_output_chars":800,"note":"图片费用按供应商账单核算;默认禁用,启用前请填写单次/每日成本阈值。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`updated_at` = NOW(3);
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`model_name` = CASE
|
||||
WHEN `provider_code` = 'volcengine_seedance_20' THEN 'doubao-seedance-2-0-260128'
|
||||
WHEN `provider_code` = 'volcengine_seedance_20_fast' THEN 'doubao-seedance-2-0-fast-260128'
|
||||
ELSE `model_name`
|
||||
END,
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN ('volcengine_seedance_20', 'volcengine_seedance_20_fast');
|
||||
@@ -0,0 +1,164 @@
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt54-text',
|
||||
'OpenAI GPT-5.4 Text',
|
||||
'real',
|
||||
'gpt-5.4',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":90000,"max_output_tokens":1800,"instructions":"你是中文漫剧创作助手,适合剧情策划、脚本润色、分镜提示词优化和复杂改写。"}',
|
||||
false,
|
||||
58,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt54-mini-text',
|
||||
'OpenAI GPT-5.4 Mini Text',
|
||||
'real',
|
||||
'gpt-5.4-mini',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":60000,"max_output_tokens":1600,"instructions":"你是中文短剧生产助手,适合高频、低延迟的分镜草稿、标题、简介和运营文案。"}',
|
||||
false,
|
||||
57,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt54-nano-text',
|
||||
'OpenAI GPT-5.4 Nano Text',
|
||||
'real',
|
||||
'gpt-5.4-nano',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":45000,"max_output_tokens":1200,"instructions":"你是中文短剧轻量助手,适合分类、短提示词改写、标题和低成本批处理。"}',
|
||||
false,
|
||||
56,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt5-text',
|
||||
'OpenAI GPT-5 Text',
|
||||
'real',
|
||||
'gpt-5',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":90000,"max_output_tokens":1800,"instructions":"你是中文漫剧创作助手,用于和 GPT-5.4/5.5 做质量、成本、稳定性对比。"}',
|
||||
false,
|
||||
55,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt41-text',
|
||||
'OpenAI GPT-4.1 Text',
|
||||
'real',
|
||||
'gpt-4.1',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":60000,"max_output_tokens":1600,"instructions":"你是中文漫剧创作助手,用于非推理模型基线测试、脚本润色和结构化输出。"}',
|
||||
false,
|
||||
54,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'TextProvider',
|
||||
'openai-gpt41-mini-text',
|
||||
'OpenAI GPT-4.1 Mini Text',
|
||||
'real',
|
||||
'gpt-4.1-mini',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":45000,"max_output_tokens":1200,"instructions":"你是中文短剧轻量助手,用于低成本文案、分镜草稿和结构化摘要。"}',
|
||||
false,
|
||||
53,
|
||||
'{"rpm":60,"concurrency":4}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'NovelProvider',
|
||||
'openai-gpt54-novel',
|
||||
'OpenAI GPT-5.4 Novel',
|
||||
'real',
|
||||
'gpt-5.4',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":150000,"max_output_tokens":5000,"instructions":"你是中文网文和短剧改编主笔,擅长长上下文改编、分集大纲、角色弧光和连续剧结构。"}',
|
||||
false,
|
||||
58,
|
||||
'{"rpm":30,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'NovelProvider',
|
||||
'openai-gpt54-mini-novel',
|
||||
'OpenAI GPT-5.4 Mini Novel',
|
||||
'real',
|
||||
'gpt-5.4-mini',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":120000,"max_output_tokens":3600,"instructions":"你是中文网文改编助手,适合低成本生成章节摘要、分集计划和脚本草稿。"}',
|
||||
false,
|
||||
57,
|
||||
'{"rpm":30,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'NovelProvider',
|
||||
'openai-gpt5-novel',
|
||||
'OpenAI GPT-5 Novel',
|
||||
'real',
|
||||
'gpt-5',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":150000,"max_output_tokens":4200,"instructions":"你是中文网文和短剧改编主笔,用于和 GPT-5.4/5.5 做长文改编对比。"}',
|
||||
false,
|
||||
55,
|
||||
'{"rpm":30,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'NovelProvider',
|
||||
'openai-gpt41-novel',
|
||||
'OpenAI GPT-4.1 Novel',
|
||||
'real',
|
||||
'gpt-4.1',
|
||||
'{"driver":"openai_responses","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":120000,"max_output_tokens":3200,"instructions":"你是中文网文改编助手,用于非推理模型基线测试和长文本结构化整理。"}',
|
||||
false,
|
||||
54,
|
||||
'{"rpm":30,"concurrency":2}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"真实费用以后续账单或 usage 元数据核算;默认禁用,用于后台多模型测试。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'openai-sora-2-pro-video',
|
||||
'OpenAI Sora 2 Pro Video',
|
||||
'real',
|
||||
'sora-2-pro',
|
||||
'{"driver":"openai_video_generation","api_key_env":"OPENAI_API_KEY","base_url":"https://api.openai.com/v1","base_url_env":"OPENAI_BASE_URL","timeout_ms":60000,"create_endpoint":"/videos","status_endpoint_template":"/videos/{video_id}","content_endpoint_template":"/videos/{video_id}/content","poll_interval_ms":10000,"max_poll_attempts":90,"size":"1280x720","seconds":"8"}',
|
||||
false,
|
||||
45,
|
||||
'{"rpm":3,"concurrency":1}',
|
||||
'{"flat_cost":0,"unit":"provider_usage_metadata","note":"Sora Pro 费用较高;默认禁用,启用前必须设置单次和每日成本上限。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`updated_at` = NOW(3);
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_SET(
|
||||
`config_json`,
|
||||
'$.body_style', 'volcengine_content_generation',
|
||||
'$.create_endpoint', '/contents/generations/tasks',
|
||||
'$.task_endpoint_template', '/contents/generations/tasks/{task_id}'
|
||||
)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN ('volcengine_seedance_20_fast', 'volcengine_seedance_20', 'jimeng_seedance');
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_REMOVE(
|
||||
`config_json`,
|
||||
'$.image_field',
|
||||
'$.prompt_field',
|
||||
'$.model_field',
|
||||
'$.duration_field',
|
||||
'$.resolution_field',
|
||||
'$.aspect_ratio_field'
|
||||
)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN ('volcengine_seedance_20_fast', 'volcengine_seedance_20', 'jimeng_seedance');
|
||||
@@ -0,0 +1,11 @@
|
||||
UPDATE `provider_configs`
|
||||
SET `cost_rule_json` = JSON_SET(
|
||||
`cost_rule_json`,
|
||||
'$.price_per_second', 0.9936,
|
||||
'$.currency', 'CNY',
|
||||
'$.max_cost_per_call', 20,
|
||||
'$.daily_cost_limit', 500,
|
||||
'$.note', '按火山方舟公开价格估算:720p、24fps、无视频输入约 46 元/百万 token,即约 0.9936 元/秒;最终以账单为准。'
|
||||
)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN ('volcengine_seedance_20_fast', 'volcengine_seedance_20');
|
||||
@@ -0,0 +1,10 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_SET(COALESCE(`config_json`, JSON_OBJECT()), '$.size', '1440x2560'),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'ImageProvider'
|
||||
AND `provider_code` IN (
|
||||
'volcengine-seedream-50-image',
|
||||
'volcengine-seedream-50-lite-image',
|
||||
'volcengine-seedream-45-image'
|
||||
);
|
||||
@@ -0,0 +1,10 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_SET(COALESCE(`config_json`, JSON_OBJECT()), '$.timeout_ms', 600000),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'ImageProvider'
|
||||
AND `provider_code` IN (
|
||||
'volcengine-seedream-50-image',
|
||||
'volcengine-seedream-50-lite-image',
|
||||
'volcengine-seedream-45-image'
|
||||
);
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `novel_chapters`
|
||||
ADD COLUMN `volume_no` INT NULL AFTER `novel_source_id`,
|
||||
ADD COLUMN `volume_title` VARCHAR(255) NULL AFTER `volume_no`;
|
||||
|
||||
CREATE INDEX `novel_chapters_novel_source_id_volume_no_idx`
|
||||
ON `novel_chapters`(`novel_source_id`, `volume_no`);
|
||||
@@ -0,0 +1,44 @@
|
||||
CREATE TABLE `novel_reading_progress` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NOT NULL,
|
||||
`chapter_id` BIGINT NOT NULL,
|
||||
`page_index` INT NOT NULL DEFAULT 0,
|
||||
`page_count` INT NOT NULL DEFAULT 1,
|
||||
`progress_percent` DECIMAL(6, 3) NULL,
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `novel_reading_progress_user_id_novel_source_id_key` (`user_id`, `novel_source_id`),
|
||||
KEY `novel_reading_progress_user_id_updated_at_idx` (`user_id`, `updated_at`),
|
||||
KEY `novel_reading_progress_novel_source_id_idx` (`novel_source_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_bookmarks` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NOT NULL,
|
||||
`chapter_id` BIGINT NOT NULL,
|
||||
`page_index` INT NOT NULL DEFAULT 0,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`note_text` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `novel_bookmarks_user_id_novel_source_id_created_at_idx` (`user_id`, `novel_source_id`, `created_at`),
|
||||
KEY `novel_bookmarks_chapter_id_idx` (`chapter_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_annotations` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NOT NULL,
|
||||
`chapter_id` BIGINT NOT NULL,
|
||||
`page_index` INT NOT NULL DEFAULT 0,
|
||||
`selected_text` TEXT NOT NULL,
|
||||
`note_text` TEXT NULL,
|
||||
`color` VARCHAR(30) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `novel_annotations_user_id_novel_source_id_created_at_idx` (`user_id`, `novel_source_id`, `created_at`),
|
||||
KEY `novel_annotations_chapter_id_idx` (`chapter_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,187 @@
|
||||
CREATE TABLE `novel_generation_plans` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`novel_scale` VARCHAR(30) NOT NULL DEFAULT 'medium',
|
||||
`target_words` INT NULL,
|
||||
`target_chapters` INT NULL,
|
||||
`genre` VARCHAR(100) NULL,
|
||||
`style_code` VARCHAR(100) NULL,
|
||||
`brief_json` JSON NULL,
|
||||
`ip_bible_json` JSON NULL,
|
||||
`volume_plan_json` JSON NULL,
|
||||
`pipeline_config_json` JSON NULL,
|
||||
`quality_threshold_json` JSON NULL,
|
||||
`automation_level` VARCHAR(20) NOT NULL DEFAULT 'L1',
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`current_chapter_no` INT NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `npg_project_status_idx` (`project_id`, `status`),
|
||||
KEY `npg_source_idx` (`novel_source_id`),
|
||||
KEY `npg_user_status_idx` (`user_id`, `status`),
|
||||
KEY `npg_scale_level_idx` (`novel_scale`, `automation_level`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_chapter_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`novel_chapter_id` BIGINT NULL,
|
||||
`chapter_no` INT NOT NULL,
|
||||
`version_no` INT NOT NULL,
|
||||
`version_type` VARCHAR(50) NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`content_text` LONGTEXT NULL,
|
||||
`content_json` JSON NULL,
|
||||
`source_agent` VARCHAR(100) NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ncv_source_chapter_version_type_key` (`novel_source_id`, `chapter_no`, `version_no`, `version_type`),
|
||||
KEY `ncv_project_chapter_idx` (`project_id`, `chapter_no`),
|
||||
KEY `ncv_chapter_idx` (`novel_chapter_id`),
|
||||
KEY `ncv_agent_idx` (`source_agent`),
|
||||
KEY `ncv_status_idx` (`status`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_context_memories` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`chapter_no` INT NULL,
|
||||
`memory_type` VARCHAR(80) NOT NULL,
|
||||
`memory_text` LONGTEXT NULL,
|
||||
`memory_json` JSON NULL,
|
||||
`importance_level` INT NOT NULL DEFAULT 0,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ncm_project_type_idx` (`project_id`, `memory_type`),
|
||||
KEY `ncm_source_chapter_idx` (`novel_source_id`, `chapter_no`),
|
||||
KEY `ncm_type_status_idx` (`memory_type`, `status`),
|
||||
KEY `ncm_importance_idx` (`importance_level`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_quality_reports` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`novel_chapter_id` BIGINT NULL,
|
||||
`chapter_no` INT NULL,
|
||||
`report_type` VARCHAR(50) NOT NULL,
|
||||
`total_score` DECIMAL(5, 2) NULL,
|
||||
`score_json` JSON NULL,
|
||||
`problems_json` JSON NULL,
|
||||
`suggestions_json` JSON NULL,
|
||||
`pass_status` BOOLEAN NOT NULL DEFAULT false,
|
||||
`rewrite_required` BOOLEAN NOT NULL DEFAULT false,
|
||||
`source_agent` VARCHAR(100) NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `nqr_project_chapter_idx` (`project_id`, `chapter_no`),
|
||||
KEY `nqr_source_chapter_idx` (`novel_source_id`, `chapter_no`),
|
||||
KEY `nqr_chapter_idx` (`novel_chapter_id`),
|
||||
KEY `nqr_pass_idx` (`pass_status`),
|
||||
KEY `nqr_agent_idx` (`source_agent`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_version_snapshots` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NOT NULL,
|
||||
`version_no` INT NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`snapshot_scope` VARCHAR(50) NOT NULL,
|
||||
`chapter_start` INT NULL,
|
||||
`chapter_end` INT NULL,
|
||||
`source_hash` VARCHAR(128) NULL,
|
||||
`snapshot_text` LONGTEXT NULL,
|
||||
`snapshot_json` JSON NULL,
|
||||
`created_for` VARCHAR(50) NULL,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `nvs_source_version_key` (`novel_source_id`, `version_no`),
|
||||
KEY `nvs_project_idx` (`project_id`),
|
||||
KEY `nvs_for_idx` (`created_for`),
|
||||
KEY `nvs_range_idx` (`chapter_start`, `chapter_end`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `novel_derivative_jobs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NOT NULL,
|
||||
`snapshot_id` BIGINT NULL,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`derivative_type` VARCHAR(50) NOT NULL,
|
||||
`target_project_id` BIGINT NULL,
|
||||
`target_ref_id` BIGINT NULL,
|
||||
`chapter_start` INT NULL,
|
||||
`chapter_end` INT NULL,
|
||||
`config_json` JSON NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`progress_json` JSON NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ndj_project_type_idx` (`project_id`, `derivative_type`),
|
||||
KEY `ndj_source_status_idx` (`novel_source_id`, `status`),
|
||||
KEY `ndj_snapshot_idx` (`snapshot_id`),
|
||||
KEY `ndj_user_status_idx` (`user_id`, `status`),
|
||||
KEY `ndj_target_project_idx` (`target_project_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `agent_prompts` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`agent_name` VARCHAR(100) NOT NULL,
|
||||
`version` INT NOT NULL DEFAULT 1,
|
||||
`provider_type` VARCHAR(80) NOT NULL DEFAULT 'NovelProvider',
|
||||
`default_provider_code` VARCHAR(100) NULL,
|
||||
`system_prompt` LONGTEXT NOT NULL,
|
||||
`user_prompt_template` LONGTEXT NOT NULL,
|
||||
`output_schema_json` JSON NULL,
|
||||
`temperature` DECIMAL(4, 2) NULL,
|
||||
`max_output_tokens` INT NULL,
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT true,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ap_name_version_key` (`agent_name`, `version`),
|
||||
KEY `ap_name_active_idx` (`agent_name`, `is_active`),
|
||||
KEY `ap_provider_type_idx` (`provider_type`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `agent_runs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`chapter_no` INT NULL,
|
||||
`agent_name` VARCHAR(100) NOT NULL,
|
||||
`prompt_version` INT NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`provider_log_id` BIGINT NULL,
|
||||
`input_json` JSON NULL,
|
||||
`output_json` JSON NULL,
|
||||
`output_text` LONGTEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'running',
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`error_code` VARCHAR(100) NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`started_at` DATETIME(3) NULL,
|
||||
`finished_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ar_project_agent_idx` (`project_id`, `agent_name`),
|
||||
KEY `ar_source_chapter_idx` (`novel_source_id`, `chapter_no`),
|
||||
KEY `ar_status_created_idx` (`status`, `created_at`),
|
||||
KEY `ar_provider_log_idx` (`provider_log_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,13 @@
|
||||
ALTER TABLE `novel_sources`
|
||||
ADD COLUMN `ai_provider_code` VARCHAR(100) NULL,
|
||||
ADD COLUMN `ai_model_name` VARCHAR(160) NULL,
|
||||
ADD COLUMN `ai_cost_estimate` DECIMAL(12, 4) NULL,
|
||||
ADD COLUMN `ai_cost_actual` DECIMAL(12, 4) NULL,
|
||||
ADD INDEX `ns_ai_provider_idx` (`ai_provider_code`);
|
||||
|
||||
ALTER TABLE `novel_chapters`
|
||||
ADD COLUMN `ai_provider_code` VARCHAR(100) NULL,
|
||||
ADD COLUMN `ai_model_name` VARCHAR(160) NULL,
|
||||
ADD COLUMN `ai_cost_estimate` DECIMAL(12, 4) NULL,
|
||||
ADD COLUMN `ai_cost_actual` DECIMAL(12, 4) NULL,
|
||||
ADD INDEX `nc_ai_provider_idx` (`ai_provider_code`);
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE `novel_sources`
|
||||
ADD COLUMN `design_json` JSON NULL AFTER `parse_report`,
|
||||
ADD COLUMN `volume_plan_json` JSON NULL AFTER `design_json`;
|
||||
|
||||
ALTER TABLE `novel_chapters`
|
||||
ADD COLUMN `outline_json` JSON NULL AFTER `visual_summary`,
|
||||
ADD COLUMN `analysis_json` JSON NULL AFTER `outline_json`;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `story_bibles`
|
||||
MODIFY `tone` TEXT NULL;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `story_bibles`
|
||||
ADD COLUMN `production_bible_json` JSON NULL,
|
||||
ADD COLUMN `quality_report_json` JSON NULL;
|
||||
@@ -0,0 +1,35 @@
|
||||
CREATE TABLE `character_extraction_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`story_bible_id` BIGINT NULL,
|
||||
`provider_log_id` BIGINT NULL,
|
||||
`source_type` VARCHAR(50) NOT NULL,
|
||||
`source_label` VARCHAR(120) NULL,
|
||||
`prompt_category` VARCHAR(100) NULL,
|
||||
`prompt_version` VARCHAR(80) NULL,
|
||||
`prompt_text` LONGTEXT NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`raw_text` LONGTEXT NULL,
|
||||
`role_pool_plan_json` JSON NULL,
|
||||
`characters_json` JSON NULL,
|
||||
`quality_score` INT NULL,
|
||||
`review_comment` TEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE INDEX `character_extraction_versions_project_id_status_idx`
|
||||
ON `character_extraction_versions`(`project_id`, `status`);
|
||||
|
||||
CREATE INDEX `character_extraction_versions_story_bible_id_idx`
|
||||
ON `character_extraction_versions`(`story_bible_id`);
|
||||
|
||||
CREATE INDEX `character_extraction_versions_provider_log_id_idx`
|
||||
ON `character_extraction_versions`(`provider_log_id`);
|
||||
|
||||
CREATE INDEX `character_extraction_versions_source_type_idx`
|
||||
ON `character_extraction_versions`(`source_type`);
|
||||
@@ -0,0 +1,58 @@
|
||||
ALTER TABLE `characters`
|
||||
ADD COLUMN `global_character_look_version_id` BIGINT NULL,
|
||||
ADD COLUMN `global_character_asset_id` BIGINT NULL,
|
||||
ADD COLUMN `inherit_voice_from_global` BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN `inherit_digital_human_from_global` BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD INDEX `characters_global_character_look_version_id_idx` (`global_character_look_version_id`),
|
||||
ADD INDEX `characters_global_character_asset_id_idx` (`global_character_asset_id`);
|
||||
|
||||
CREATE TABLE `global_character_look_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`global_character_id` BIGINT NOT NULL,
|
||||
`version_name` VARCHAR(160) NOT NULL,
|
||||
`style_type` VARCHAR(80) NULL,
|
||||
`appearance_desc` TEXT NULL,
|
||||
`hair_desc` TEXT NULL,
|
||||
`makeup_desc` TEXT NULL,
|
||||
`body_desc` TEXT NULL,
|
||||
`costume_rules` TEXT NULL,
|
||||
`color_palette` TEXT NULL,
|
||||
`key_props` TEXT NULL,
|
||||
`negative_rules` TEXT NULL,
|
||||
`main_anchor_asset_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'candidate',
|
||||
`quality_score` DECIMAL(5,2) NULL,
|
||||
`reviewer_comment` TEXT NULL,
|
||||
`source_project_id` BIGINT NULL,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `global_character_look_versions_global_character_id_status_idx` (`global_character_id`, `status`),
|
||||
INDEX `global_character_look_versions_main_anchor_asset_id_idx` (`main_anchor_asset_id`),
|
||||
INDEX `global_character_look_versions_source_project_id_idx` (`source_project_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `global_character_assets`
|
||||
ADD COLUMN `look_version_id` BIGINT NULL,
|
||||
ADD COLUMN `source_type` VARCHAR(50) NOT NULL DEFAULT 'upload',
|
||||
ADD COLUMN `source_label` VARCHAR(160) NULL,
|
||||
ADD COLUMN `negative_prompt` TEXT NULL,
|
||||
ADD COLUMN `model_name` VARCHAR(160) NULL,
|
||||
ADD COLUMN `seed` VARCHAR(100) NULL,
|
||||
ADD COLUMN `resolution` VARCHAR(50) NULL,
|
||||
ADD COLUMN `aspect_ratio` VARCHAR(50) NULL,
|
||||
ADD COLUMN `cost_estimate` DECIMAL(12,4) NULL,
|
||||
ADD COLUMN `cost_actual` DECIMAL(12,4) NULL,
|
||||
ADD COLUMN `quality_score` DECIMAL(5,2) NULL,
|
||||
ADD COLUMN `consistency_score` DECIMAL(5,2) NULL,
|
||||
ADD COLUMN `face_similarity_score` DECIMAL(5,2) NULL,
|
||||
ADD COLUMN `license_status` VARCHAR(50) NOT NULL DEFAULT 'internal_test',
|
||||
ADD COLUMN `commercial_allowed` BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN `review_status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
ADD COLUMN `reviewer_note` TEXT NULL,
|
||||
ADD COLUMN `usage_count` INT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN `metadata_json` JSON NULL,
|
||||
ADD INDEX `global_character_assets_look_version_id_idx` (`look_version_id`),
|
||||
ADD INDEX `global_character_assets_source_type_idx` (`source_type`),
|
||||
ADD INDEX `global_character_assets_review_status_idx` (`review_status`);
|
||||
@@ -0,0 +1,100 @@
|
||||
ALTER TABLE `characters`
|
||||
ADD COLUMN `story_character_id` BIGINT NULL,
|
||||
ADD INDEX `characters_story_character_id_idx` (`story_character_id`);
|
||||
|
||||
CREATE TABLE `story_characters` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`story_bible_id` BIGINT NULL,
|
||||
`global_character_id` BIGINT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`alias_names` JSON NULL,
|
||||
`role_type` VARCHAR(50) NOT NULL DEFAULT 'supporting',
|
||||
`identity_desc` TEXT NULL,
|
||||
`background_desc` TEXT NULL,
|
||||
`personality_desc` TEXT NULL,
|
||||
`relationship_json` JSON NULL,
|
||||
`character_arc` TEXT NULL,
|
||||
`world_role_desc` TEXT NULL,
|
||||
`negative_rules` TEXT NULL,
|
||||
`source_type` VARCHAR(50) NOT NULL DEFAULT 'character_extraction',
|
||||
`source_version_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `story_characters_project_id_status_idx` (`project_id`, `status`),
|
||||
INDEX `story_characters_novel_source_id_idx` (`novel_source_id`),
|
||||
INDEX `story_characters_story_bible_id_idx` (`story_bible_id`),
|
||||
INDEX `story_characters_global_character_id_idx` (`global_character_id`),
|
||||
INDEX `story_characters_source_type_idx` (`source_type`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `video_clips`
|
||||
ADD COLUMN `engine_version` VARCHAR(80) NULL,
|
||||
ADD COLUMN `asset_lock_json` JSON NULL,
|
||||
ADD COLUMN `motion_control_json` JSON NULL,
|
||||
ADD COLUMN `camera_control_json` JSON NULL,
|
||||
ADD COLUMN `composer_usage_json` JSON NULL,
|
||||
ADD INDEX `video_clips_engine_version_idx` (`engine_version`);
|
||||
|
||||
CREATE TABLE `project_pipeline_configs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`ip_isolation_enabled` BOOLEAN NOT NULL DEFAULT true,
|
||||
`video_engine_enabled` BOOLEAN NOT NULL DEFAULT true,
|
||||
`scene_composer_enabled` BOOLEAN NOT NULL DEFAULT false,
|
||||
`default_generation_mode` VARCHAR(50) NOT NULL DEFAULT 'single_model',
|
||||
`video_engine_version` VARCHAR(80) NOT NULL DEFAULT 'video_engine_v1',
|
||||
`scene_composer_version` VARCHAR(80) NOT NULL DEFAULT 'scene_composer_v1_reserved',
|
||||
`ip_rules_json` JSON NULL,
|
||||
`video_engine_config_json` JSON NULL,
|
||||
`scene_composer_config_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `project_pipeline_configs_project_id_key` (`project_id`),
|
||||
INDEX `project_pipeline_configs_scene_composer_enabled_idx` (`scene_composer_enabled`),
|
||||
INDEX `project_pipeline_configs_default_generation_mode_idx` (`default_generation_mode`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO `project_pipeline_configs` (
|
||||
`project_id`,
|
||||
`ip_isolation_enabled`,
|
||||
`video_engine_enabled`,
|
||||
`scene_composer_enabled`,
|
||||
`default_generation_mode`,
|
||||
`video_engine_version`,
|
||||
`scene_composer_version`,
|
||||
`ip_rules_json`,
|
||||
`video_engine_config_json`,
|
||||
`scene_composer_config_json`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
'single_model',
|
||||
'video_engine_v1',
|
||||
'scene_composer_v1_reserved',
|
||||
JSON_OBJECT(
|
||||
'character_ip_policy', 'clean_reusable_assets_only',
|
||||
'story_character_policy', 'story_bible_and_relationships_only',
|
||||
'project_character_policy', 'project_look_anchor_scene_state_only',
|
||||
'forbidden_ip_fields', JSON_ARRAY('episode_plot', 'shot_state', 'project_costume', 'scene_action')
|
||||
),
|
||||
JSON_OBJECT(
|
||||
'mode', 'single_model_first',
|
||||
'candidate_count_default', 1,
|
||||
'multi_model_compare_default_enabled', false,
|
||||
'requires_human_clip_selection', true
|
||||
),
|
||||
JSON_OBJECT(
|
||||
'enabled', false,
|
||||
'reserved_stage', 'phase_5',
|
||||
'notes', 'Scene Composer is recorded for future automatic ordering/emotion/transition logic. Current production keeps human clip selection and FFmpeg render.'
|
||||
)
|
||||
FROM `projects`
|
||||
ON DUPLICATE KEY UPDATE `updated_at` = CURRENT_TIMESTAMP(3);
|
||||
@@ -0,0 +1,34 @@
|
||||
CREATE TABLE `character_prompt_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NULL,
|
||||
`character_id` BIGINT NULL,
|
||||
`global_character_id` BIGINT NULL,
|
||||
`look_version_id` BIGINT NULL,
|
||||
`version_no` INTEGER NOT NULL,
|
||||
`layer_code` VARCHAR(80) NOT NULL DEFAULT 'main_anchor',
|
||||
`channel` VARCHAR(80) NOT NULL DEFAULT 'chatgpt_web',
|
||||
`title` VARCHAR(160) NULL,
|
||||
`source_type` VARCHAR(80) NOT NULL DEFAULT 'system_refresh',
|
||||
`source_label` VARCHAR(160) NULL,
|
||||
`prompt_engine_version` VARCHAR(80) NULL,
|
||||
`prompt_text` LONGTEXT NOT NULL,
|
||||
`negative_prompt` LONGTEXT NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`usage_note` TEXT NULL,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`review_comment` TEXT NULL,
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT false,
|
||||
`metadata_json` JSON NULL,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `cpv_character_version_key` (`character_id`, `version_no`),
|
||||
UNIQUE INDEX `cpv_global_version_key` (`global_character_id`, `version_no`),
|
||||
INDEX `cpv_project_idx` (`project_id`),
|
||||
INDEX `cpv_character_layer_channel_idx` (`character_id`, `layer_code`, `channel`),
|
||||
INDEX `cpv_global_layer_channel_idx` (`global_character_id`, `layer_code`, `channel`),
|
||||
INDEX `cpv_look_version_idx` (`look_version_id`),
|
||||
INDEX `cpv_active_status_idx` (`is_active`, `status`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,60 @@
|
||||
CREATE TABLE `character_prompt_reviews` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`task_id` BIGINT NULL,
|
||||
`character_id` BIGINT NULL,
|
||||
`global_character_id` BIGINT NULL,
|
||||
`prompt_version_id` BIGINT NULL,
|
||||
`layer_code` VARCHAR(80) NOT NULL,
|
||||
`image_type` VARCHAR(80) NULL,
|
||||
`review_round` INTEGER NOT NULL DEFAULT 1,
|
||||
`review_mode` VARCHAR(80) NOT NULL DEFAULT 'api_preflight',
|
||||
`prompt_engine_version` VARCHAR(80) NULL,
|
||||
`threshold_score` DECIMAL(5, 2) NOT NULL DEFAULT 92.00,
|
||||
`score` DECIMAL(5, 2) NULL,
|
||||
`passed` BOOLEAN NOT NULL DEFAULT false,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`source_prompt` LONGTEXT NULL,
|
||||
`optimized_prompt` LONGTEXT NULL,
|
||||
`negative_prompt` LONGTEXT NULL,
|
||||
`issues_json` JSON NULL,
|
||||
`suggestions_json` JSON NULL,
|
||||
`reusable_rules_json` JSON NULL,
|
||||
`quality_gate_json` JSON NULL,
|
||||
`provider_log_id` BIGINT NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`raw_text` LONGTEXT NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `cpr_project_created_idx` (`project_id`, `created_at`),
|
||||
INDEX `cpr_task_idx` (`task_id`),
|
||||
INDEX `cpr_character_layer_idx` (`character_id`, `layer_code`),
|
||||
INDEX `cpr_global_layer_idx` (`global_character_id`, `layer_code`),
|
||||
INDEX `cpr_prompt_version_idx` (`prompt_version_id`),
|
||||
INDEX `cpr_layer_passed_idx` (`layer_code`, `passed`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `character_prompt_optimization_lessons` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`scope_type` VARCHAR(50) NOT NULL DEFAULT 'global',
|
||||
`layer_code` VARCHAR(80) NOT NULL,
|
||||
`lesson_type` VARCHAR(80) NOT NULL DEFAULT 'prompt_rule',
|
||||
`title` VARCHAR(160) NULL,
|
||||
`rule_text` TEXT NOT NULL,
|
||||
`prompt_engine_version` VARCHAR(80) NULL,
|
||||
`source_review_id` BIGINT NULL,
|
||||
`source_character_id` BIGINT NULL,
|
||||
`source_prompt_version_id` BIGINT NULL,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`usage_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`metadata_json` JSON NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `cpol_scope_layer_status_idx` (`scope_type`, `layer_code`, `status`),
|
||||
INDEX `cpol_review_idx` (`source_review_id`),
|
||||
INDEX `cpol_character_idx` (`source_character_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
CREATE TABLE `user_model_preferences` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`scope_key` VARCHAR(120) NOT NULL DEFAULT 'global',
|
||||
`project_id` BIGINT NULL,
|
||||
`preference_key` VARCHAR(120) NOT NULL,
|
||||
`text_provider_code` VARCHAR(100) NULL,
|
||||
`image_provider_code` VARCHAR(100) NULL,
|
||||
`video_provider_code` VARCHAR(100) NULL,
|
||||
`voice_provider_code` VARCHAR(100) NULL,
|
||||
`metadata_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `ump_user_scope_key_unique` (`user_id`, `scope_key`, `preference_key`),
|
||||
INDEX `ump_user_scope_idx` (`user_id`, `scope_key`),
|
||||
INDEX `ump_project_idx` (`project_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `project_visual_assets` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`asset_id` BIGINT NULL,
|
||||
`asset_kind` VARCHAR(50) NOT NULL,
|
||||
`asset_type` VARCHAR(80) NOT NULL,
|
||||
`name` VARCHAR(160) NOT NULL,
|
||||
`label` VARCHAR(160) NULL,
|
||||
`ownership_type` VARCHAR(50) NOT NULL DEFAULT 'shared_story',
|
||||
`owner_character_id` BIGINT NULL,
|
||||
`source_type` VARCHAR(80) NOT NULL DEFAULT 'manual',
|
||||
`source_label` VARCHAR(160) NULL,
|
||||
`prompt_text` LONGTEXT NULL,
|
||||
`negative_prompt` LONGTEXT NULL,
|
||||
`usage_tags_json` JSON NULL,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`is_primary` BOOLEAN NOT NULL DEFAULT false,
|
||||
`metadata_json` JSON NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `pva_project_kind_status_idx` (`project_id`, `asset_kind`, `status`),
|
||||
INDEX `pva_project_type_idx` (`project_id`, `asset_type`),
|
||||
INDEX `pva_owner_character_idx` (`owner_character_id`),
|
||||
INDEX `pva_asset_idx` (`asset_id`),
|
||||
INDEX `pva_user_kind_idx` (`user_id`, `asset_kind`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,20 @@
|
||||
ALTER TABLE `project_visual_assets`
|
||||
ADD COLUMN `aliases_json` JSON NULL,
|
||||
ADD COLUMN `allowed_roles_json` JSON NULL,
|
||||
ADD COLUMN `detected_from` VARCHAR(160) NULL,
|
||||
ADD COLUMN `importance` INT NOT NULL DEFAULT 50,
|
||||
ADD COLUMN `visual_lock` LONGTEXT NULL,
|
||||
ADD COLUMN `key_objects_json` JSON NULL,
|
||||
ADD COLUMN `prompt_block` LONGTEXT NULL,
|
||||
ADD COLUMN `anchor_prompt` LONGTEXT NULL,
|
||||
ADD COLUMN `reference_images_json` JSON NULL,
|
||||
ADD COLUMN `anchor_images_json` JSON NULL,
|
||||
ADD COLUMN `render_variants_json` JSON NULL,
|
||||
ADD COLUMN `linked_assets_json` JSON NULL,
|
||||
ADD COLUMN `reuse_rule` LONGTEXT NULL,
|
||||
ADD COLUMN `story_scope` VARCHAR(120) NULL,
|
||||
ADD COLUMN `version_note` LONGTEXT NULL,
|
||||
ADD COLUMN `notes` LONGTEXT NULL;
|
||||
|
||||
CREATE INDEX `pva_project_ownership_idx` ON `project_visual_assets`(`project_id`, `ownership_type`);
|
||||
CREATE INDEX `pva_project_status_importance_idx` ON `project_visual_assets`(`project_id`, `status`, `importance`);
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE `assets`
|
||||
ADD COLUMN `display_name` VARCHAR(255) NULL,
|
||||
ADD COLUMN `selection_status` VARCHAR(30) NOT NULL DEFAULT 'candidate',
|
||||
ADD COLUMN `selection_note` TEXT NULL,
|
||||
ADD COLUMN `metadata_json` JSON NULL;
|
||||
|
||||
CREATE INDEX `assets_project_id_selection_status_idx` ON `assets`(`project_id`, `selection_status`);
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE `storyboard_shots`
|
||||
ADD COLUMN `transition_to_next` VARCHAR(50) NULL,
|
||||
ADD COLUMN `transition_to_next_duration` DECIMAL(5, 2) NULL,
|
||||
ADD COLUMN `transition_to_next_reason` TEXT NULL;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
ALTER TABLE `character_images`
|
||||
ADD COLUMN `prompt_quality_score` DECIMAL(5, 2) NULL AFTER `is_anchor`;
|
||||
|
||||
UPDATE `character_images`
|
||||
SET `prompt_quality_score` = `quality_score`,
|
||||
`quality_score` = NULL
|
||||
WHERE `quality_score` IS NOT NULL;
|
||||
|
||||
CREATE TABLE `character_image_quality_reviews` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`character_image_id` BIGINT NOT NULL,
|
||||
`asset_id` BIGINT NOT NULL,
|
||||
`image_type` VARCHAR(80) NOT NULL,
|
||||
`review_round` INTEGER NOT NULL DEFAULT 1,
|
||||
`review_mode` VARCHAR(80) NOT NULL DEFAULT 'post_generation_visual',
|
||||
`threshold_score` DECIMAL(5, 2) NOT NULL DEFAULT 96.00,
|
||||
`score` DECIMAL(5, 2) NULL,
|
||||
`grade` VARCHAR(20) NULL,
|
||||
`passed` BOOLEAN NOT NULL DEFAULT false,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`dimensions_json` JSON NULL,
|
||||
`strengths_json` JSON NULL,
|
||||
`issues_json` JSON NULL,
|
||||
`improvement_rules_json` JSON NULL,
|
||||
`character_observations_json` JSON NULL,
|
||||
`quality_gate_json` JSON NULL,
|
||||
`provider_log_id` BIGINT NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`raw_text` LONGTEXT NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `ciqr_project_created_idx` (`project_id`, `created_at`),
|
||||
INDEX `ciqr_character_type_idx` (`character_id`, `image_type`),
|
||||
INDEX `ciqr_image_round_idx` (`character_image_id`, `review_round`),
|
||||
INDEX `ciqr_asset_idx` (`asset_id`),
|
||||
INDEX `ciqr_type_passed_idx` (`image_type`, `passed`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,79 @@
|
||||
ALTER TABLE `projects`
|
||||
ADD COLUMN `engine_version` VARCHAR(50) NOT NULL DEFAULT 'legacy_v1',
|
||||
ADD COLUMN `production_lifecycle` VARCHAR(80) NOT NULL DEFAULT 'legacy_snapshot';
|
||||
|
||||
CREATE INDEX `project_engine_lifecycle_idx`
|
||||
ON `projects`(`engine_version`, `production_lifecycle`);
|
||||
|
||||
CREATE TABLE `production_contracts` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`contract_type` VARCHAR(50) NOT NULL,
|
||||
`schema_version` VARCHAR(80) NOT NULL,
|
||||
`version` INTEGER NOT NULL,
|
||||
`scope_key` VARCHAR(100) NOT NULL DEFAULT 'project',
|
||||
`parent_contract_id` BIGINT NULL,
|
||||
`source_snapshot_id` VARCHAR(160) NULL,
|
||||
`input_hash` VARCHAR(64) NOT NULL,
|
||||
`input_snapshot_json` JSON NULL,
|
||||
`payload_json` JSON NOT NULL,
|
||||
`source_refs_json` JSON NULL,
|
||||
`quality_result_json` JSON NULL,
|
||||
`reviewer_delta_json` JSON NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`downstream_status` VARCHAR(50) NOT NULL DEFAULT 'blocked',
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`confirmed_at` DATETIME(3) NULL,
|
||||
`released_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `pc_project_type_scope_version_key`(`project_id`, `contract_type`, `scope_key`, `version`),
|
||||
INDEX `pc_project_type_status_idx`(`project_id`, `contract_type`, `status`),
|
||||
INDEX `pc_parent_idx`(`parent_contract_id`),
|
||||
INDEX `pc_input_hash_idx`(`input_hash`),
|
||||
INDEX `pc_downstream_status_idx`(`downstream_status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `production_source_snapshots` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`snapshot_version` INTEGER NOT NULL,
|
||||
`source_type` VARCHAR(50) NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`content_hash` VARCHAR(64) NOT NULL,
|
||||
`content_text` LONGTEXT NOT NULL,
|
||||
`chapter_manifest_json` JSON NULL,
|
||||
`metadata_json` JSON NULL,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
UNIQUE INDEX `pss_project_version_key`(`project_id`, `snapshot_version`),
|
||||
INDEX `pss_project_source_idx`(`project_id`, `novel_source_id`),
|
||||
INDEX `pss_content_hash_idx`(`content_hash`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `production_contract_reviews` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`contract_id` BIGINT NOT NULL,
|
||||
`reviewer_type` VARCHAR(80) NOT NULL,
|
||||
`reviewer_version` VARCHAR(80) NOT NULL,
|
||||
`review_no` INTEGER NOT NULL,
|
||||
`passed` BOOLEAN NOT NULL DEFAULT false,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`issues_json` JSON NULL,
|
||||
`delta_json` JSON NULL,
|
||||
`provider_log_id` BIGINT NULL,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
UNIQUE INDEX `pcr_contract_reviewer_no_key`(`contract_id`, `reviewer_type`, `review_no`),
|
||||
INDEX `pcr_project_reviewer_idx`(`project_id`, `reviewer_type`),
|
||||
INDEX `pcr_contract_passed_idx`(`contract_id`, `passed`),
|
||||
INDEX `pcr_provider_log_idx`(`provider_log_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,213 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`display_name` = CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN '可灵 v3 Omni 原生音频 720P 视频'
|
||||
ELSE '可灵 v3 Omni 原生音频 1080P 视频'
|
||||
END,
|
||||
`config_json` = JSON_REMOVE(
|
||||
JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.driver', 'kling_omni_video',
|
||||
'$.auth_type', 'bearer',
|
||||
'$.api_key_env', 'KLING_API_KEY',
|
||||
'$.base_url', 'https://api-singapore.klingai.com',
|
||||
'$.timeout_ms', 600000,
|
||||
'$.create_endpoint', '/v1/videos/omni-video',
|
||||
'$.task_endpoint_template', '/v1/videos/omni-video/{task_id}',
|
||||
'$.poll_interval_ms', 10000,
|
||||
'$.max_poll_attempts', 120,
|
||||
'$.model_field', 'model_name',
|
||||
'$.prompt_field', 'prompt',
|
||||
'$.duration_field', 'duration',
|
||||
'$.aspect_ratio_field', 'aspect_ratio',
|
||||
'$.mode_field', 'mode',
|
||||
'$.aspect_ratio', '9:16',
|
||||
'$.mode', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN 'std'
|
||||
ELSE 'pro'
|
||||
END,
|
||||
'$.resolution', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN '720p'
|
||||
ELSE '1080p'
|
||||
END,
|
||||
'$.duration', 5,
|
||||
'$.allowed_modes', JSON_ARRAY('std', 'pro', '4k'),
|
||||
'$.allowed_resolutions', JSON_ARRAY('720p', '1080p', '4k'),
|
||||
'$.allowed_durations', JSON_ARRAY(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
'$.max_prompt_length', 2500,
|
||||
'$.max_multi_prompt_length', 512,
|
||||
'$.max_multi_shots', 6,
|
||||
'$.max_image_inputs', 7,
|
||||
'$.web_max_image_inputs', 7,
|
||||
'$.max_reference_images', 6,
|
||||
'$.reference_image_limit', 6,
|
||||
'$.max_image_inputs_without_video', 7,
|
||||
'$.max_image_inputs_with_video', 4,
|
||||
'$.max_video_inputs', 1,
|
||||
'$.max_elements_with_start_end_frames', 3,
|
||||
'$.input_image_formats', JSON_ARRAY('jpg', 'jpeg', 'png'),
|
||||
'$.input_image_mime_types', JSON_ARRAY('image/jpeg', 'image/png'),
|
||||
'$.input_image_max_mb', 10,
|
||||
'$.input_image_min_dimension', 300,
|
||||
'$.input_image_min_aspect_ratio', 0.4,
|
||||
'$.input_image_max_aspect_ratio', 2.5,
|
||||
'$.video_input_formats', JSON_ARRAY('mp4', 'mov'),
|
||||
'$.video_input_min_seconds', 3,
|
||||
'$.video_input_max_seconds', 15.5,
|
||||
'$.video_input_max_mb', 200,
|
||||
'$.video_input_min_fps', 24,
|
||||
'$.video_input_max_fps', 60,
|
||||
'$.video_input_min_dimension', 700,
|
||||
'$.video_input_max_dimension', 4553,
|
||||
'$.video_input_max_area', 8294400,
|
||||
'$.video_modes', JSON_ARRAY('text_to_video', 'first_frame', 'start_end_frame', 'multi_image_reference', 'video_reference'),
|
||||
'$.extra_body_json', JSON_OBJECT('sound', 'on', 'watermark_info', JSON_OBJECT('enabled', false)),
|
||||
'$.supports_4k', true,
|
||||
'$.supports_reference_image', true,
|
||||
'$.supports_start_end_frame', true,
|
||||
'$.supports_multi_image_reference', true,
|
||||
'$.supports_reference_video', true,
|
||||
'$.supports_multi_shot', true,
|
||||
'$.supports_audio', true,
|
||||
'$.supports_lipsync', true,
|
||||
'$.supports_character_reference', true,
|
||||
'$.supports_multi_character', true,
|
||||
'$.supports_style_reference', true,
|
||||
'$.note', 'Kling 3.0 Omni 官方新接口:支持原生 4K、最多 7 个图片与元素参考、单个参考视频、多镜头及原生音频。'
|
||||
),
|
||||
'$.access_key_env',
|
||||
'$.secret_key_env',
|
||||
'$.jwt_ttl_seconds',
|
||||
'$.jwt_nbf_skew_seconds',
|
||||
'$.image_field',
|
||||
'$.reference_images_field',
|
||||
'$.resolution_field'
|
||||
),
|
||||
`cost_rule_json` = JSON_SET(
|
||||
COALESCE(`cost_rule_json`, JSON_OBJECT()),
|
||||
'$.unit', 'video_seconds',
|
||||
'$.currency', 'USD',
|
||||
'$.price_per_second', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN 0.112
|
||||
ELSE 0.14
|
||||
END,
|
||||
'$.cny_fx_rate', 6.79,
|
||||
'$.max_cost_per_call', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN 2
|
||||
ELSE 3
|
||||
END,
|
||||
'$.daily_cost_limit', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video' THEN 30
|
||||
ELSE 50
|
||||
END,
|
||||
'$.estimated_seconds', 10,
|
||||
'$.note', CASE
|
||||
WHEN `provider_code` = 'kling-v3-omni-native-audio-720p-video'
|
||||
THEN 'Kling v3 Omni 原生音频 720P:$0.112/s,10s 约 $1.12 / ¥7.61;最终以 Kling 账单为准。'
|
||||
ELSE 'Kling v3 Omni 原生音频 1080P:$0.14/s,10s 约 $1.40 / ¥9.51;最终以 Kling 账单为准。'
|
||||
END
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN (
|
||||
'kling-v3-omni-native-audio-720p-video',
|
||||
'kling-v3-omni-native-audio-1080p-video'
|
||||
);
|
||||
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'VideoProvider',
|
||||
'kling-v3-omni-native-audio-4k-video',
|
||||
'可灵 v3 Omni 原生音频 4K 视频',
|
||||
'real',
|
||||
'kling-v3-omni',
|
||||
JSON_OBJECT(
|
||||
'driver', 'kling_omni_video',
|
||||
'auth_type', 'bearer',
|
||||
'api_key_env', 'KLING_API_KEY',
|
||||
'base_url', 'https://api-singapore.klingai.com',
|
||||
'timeout_ms', 600000,
|
||||
'create_endpoint', '/v1/videos/omni-video',
|
||||
'task_endpoint_template', '/v1/videos/omni-video/{task_id}',
|
||||
'poll_interval_ms', 10000,
|
||||
'max_poll_attempts', 120,
|
||||
'model_field', 'model_name',
|
||||
'prompt_field', 'prompt',
|
||||
'duration_field', 'duration',
|
||||
'aspect_ratio_field', 'aspect_ratio',
|
||||
'mode_field', 'mode',
|
||||
'aspect_ratio', '9:16',
|
||||
'mode', '4k',
|
||||
'resolution', '4k',
|
||||
'duration', 5,
|
||||
'allowed_modes', JSON_ARRAY('std', 'pro', '4k'),
|
||||
'allowed_resolutions', JSON_ARRAY('720p', '1080p', '4k'),
|
||||
'allowed_durations', JSON_ARRAY(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
'max_prompt_length', 2500,
|
||||
'max_multi_prompt_length', 512,
|
||||
'max_multi_shots', 6,
|
||||
'max_image_inputs', 7,
|
||||
'web_max_image_inputs', 7,
|
||||
'max_reference_images', 6,
|
||||
'reference_image_limit', 6,
|
||||
'max_image_inputs_without_video', 7,
|
||||
'max_image_inputs_with_video', 4,
|
||||
'max_video_inputs', 1,
|
||||
'max_elements_with_start_end_frames', 3,
|
||||
'input_image_formats', JSON_ARRAY('jpg', 'jpeg', 'png'),
|
||||
'input_image_mime_types', JSON_ARRAY('image/jpeg', 'image/png'),
|
||||
'input_image_max_mb', 10,
|
||||
'input_image_min_dimension', 300,
|
||||
'input_image_min_aspect_ratio', 0.4,
|
||||
'input_image_max_aspect_ratio', 2.5,
|
||||
'video_input_formats', JSON_ARRAY('mp4', 'mov'),
|
||||
'video_input_min_seconds', 3,
|
||||
'video_input_max_seconds', 15.5,
|
||||
'video_input_max_mb', 200,
|
||||
'video_input_min_fps', 24,
|
||||
'video_input_max_fps', 60,
|
||||
'video_input_min_dimension', 700,
|
||||
'video_input_max_dimension', 4553,
|
||||
'video_input_max_area', 8294400,
|
||||
'video_modes', JSON_ARRAY('text_to_video', 'first_frame', 'start_end_frame', 'multi_image_reference', 'video_reference'),
|
||||
'extra_body_json', JSON_OBJECT('sound', 'on', 'watermark_info', JSON_OBJECT('enabled', false)),
|
||||
'supports_4k', true,
|
||||
'supports_reference_image', true,
|
||||
'supports_start_end_frame', true,
|
||||
'supports_multi_image_reference', true,
|
||||
'supports_reference_video', true,
|
||||
'supports_multi_shot', true,
|
||||
'supports_audio', true,
|
||||
'supports_lipsync', true,
|
||||
'supports_character_reference', true,
|
||||
'supports_multi_character', true,
|
||||
'supports_style_reference', true,
|
||||
'note', '默认禁用。Kling 3.0 Omni 官方原生 4K 模式,支持最多 7 个图片与元素参考;4K 成本较高,正式批量前需单镜头验证。'
|
||||
),
|
||||
false,
|
||||
41,
|
||||
JSON_OBJECT('rpm', 5, 'concurrency', 1),
|
||||
JSON_OBJECT(
|
||||
'flat_cost', 0,
|
||||
'unit', 'video_seconds',
|
||||
'price_per_second', 0.42,
|
||||
'currency', 'USD',
|
||||
'cny_fx_rate', 6.79,
|
||||
'max_cost_per_call', 7,
|
||||
'daily_cost_limit', 100,
|
||||
'estimated_seconds', 10,
|
||||
'note', 'Kling v3 Omni 原生音频 4K:$0.42/s,10s 约 $4.20 / ¥28.52;最终以 Kling 账单为准。'
|
||||
),
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`cost_rule_json` = VALUES(`cost_rule_json`),
|
||||
`updated_at` = NOW(3);
|
||||
@@ -0,0 +1,230 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_REMOVE(
|
||||
JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.driver', 'kling_v3_image_to_video',
|
||||
'$.auth_type', 'bearer',
|
||||
'$.api_key_env', 'KLING_API_KEY',
|
||||
'$.base_url', 'https://api-singapore.klingai.com',
|
||||
'$.timeout_ms', 600000,
|
||||
'$.create_endpoint', '/v1/videos/image2video',
|
||||
'$.task_endpoint_template', '/v1/videos/image2video/{task_id}',
|
||||
'$.poll_interval_ms', 10000,
|
||||
'$.max_poll_attempts', 120,
|
||||
'$.aspect_ratio', '9:16',
|
||||
'$.mode', CASE
|
||||
WHEN `provider_code` = 'kling-v3-native-audio-720p-video' THEN 'std'
|
||||
ELSE 'pro'
|
||||
END,
|
||||
'$.resolution', CASE
|
||||
WHEN `provider_code` = 'kling-v3-native-audio-720p-video' THEN '720p'
|
||||
ELSE '1080p'
|
||||
END,
|
||||
'$.duration', 5,
|
||||
'$.allowed_modes', JSON_ARRAY('std', 'pro', '4k'),
|
||||
'$.allowed_resolutions', JSON_ARRAY('720p', '1080p', '4k'),
|
||||
'$.allowed_durations', JSON_ARRAY(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
'$.max_prompt_length', 2500,
|
||||
'$.max_multi_prompt_length', 512,
|
||||
'$.max_multi_shots', 6,
|
||||
'$.max_image_inputs', 2,
|
||||
'$.web_max_image_inputs', 2,
|
||||
'$.max_elements', 3,
|
||||
'$.max_voices', 2,
|
||||
'$.input_image_formats', JSON_ARRAY('jpg', 'jpeg', 'png'),
|
||||
'$.input_image_mime_types', JSON_ARRAY('image/jpeg', 'image/png'),
|
||||
'$.input_image_max_mb', 10,
|
||||
'$.input_image_min_dimension', 300,
|
||||
'$.input_image_min_aspect_ratio', 0.4,
|
||||
'$.input_image_max_aspect_ratio', 2.5,
|
||||
'$.video_modes', JSON_ARRAY('first_frame', 'end_frame', 'start_end_frame'),
|
||||
'$.extra_body_json', JSON_OBJECT('sound', 'on', 'watermark_info', JSON_OBJECT('enabled', false)),
|
||||
'$.supports_4k', true,
|
||||
'$.supports_reference_image', true,
|
||||
'$.supports_start_end_frame', true,
|
||||
'$.supports_elements', true,
|
||||
'$.supports_voices', true,
|
||||
'$.supports_multi_shot', true,
|
||||
'$.supports_audio', true,
|
||||
'$.supports_lipsync', true,
|
||||
'$.supports_character_reference', true,
|
||||
'$.supports_multi_character', true,
|
||||
'$.supports_style_reference', false,
|
||||
'$.capability_version', 'kling_video_capabilities_2026-07-15',
|
||||
'$.formal_splus_model', true,
|
||||
'$.official_doc_url', 'https://kling.ai/document-api/api/video/3-0-omni/image-to-video',
|
||||
'$.note', 'Kling v3 官方 image2video 适配器:首帧/尾帧、最多3个元素、最多2个音色、自定义或智能多镜头、原生音频与4K。'
|
||||
),
|
||||
'$.access_key_env',
|
||||
'$.secret_key_env',
|
||||
'$.jwt_ttl_seconds',
|
||||
'$.jwt_nbf_skew_seconds',
|
||||
'$.model_field',
|
||||
'$.image_field',
|
||||
'$.prompt_field',
|
||||
'$.duration_field',
|
||||
'$.aspect_ratio_field',
|
||||
'$.resolution_field',
|
||||
'$.reference_images_field',
|
||||
'$.max_reference_images',
|
||||
'$.reference_image_limit'
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN (
|
||||
'kling-v3-native-audio-720p-video',
|
||||
'kling-v3-native-audio-video'
|
||||
);
|
||||
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'VideoProvider',
|
||||
'kling-v3-native-audio-4k-video',
|
||||
'可灵 v3 原生音频 4K 图生视频',
|
||||
'real',
|
||||
'kling-v3',
|
||||
JSON_OBJECT(
|
||||
'driver', 'kling_v3_image_to_video',
|
||||
'auth_type', 'bearer',
|
||||
'api_key_env', 'KLING_API_KEY',
|
||||
'base_url', 'https://api-singapore.klingai.com',
|
||||
'timeout_ms', 600000,
|
||||
'create_endpoint', '/v1/videos/image2video',
|
||||
'task_endpoint_template', '/v1/videos/image2video/{task_id}',
|
||||
'poll_interval_ms', 10000,
|
||||
'max_poll_attempts', 120,
|
||||
'aspect_ratio', '9:16',
|
||||
'mode', '4k',
|
||||
'resolution', '4k',
|
||||
'duration', 5,
|
||||
'allowed_modes', JSON_ARRAY('std', 'pro', '4k'),
|
||||
'allowed_resolutions', JSON_ARRAY('720p', '1080p', '4k'),
|
||||
'allowed_durations', JSON_ARRAY(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
'max_prompt_length', 2500,
|
||||
'max_multi_prompt_length', 512,
|
||||
'max_multi_shots', 6,
|
||||
'max_image_inputs', 2,
|
||||
'web_max_image_inputs', 2,
|
||||
'max_elements', 3,
|
||||
'max_voices', 2,
|
||||
'input_image_formats', JSON_ARRAY('jpg', 'jpeg', 'png'),
|
||||
'input_image_mime_types', JSON_ARRAY('image/jpeg', 'image/png'),
|
||||
'input_image_max_mb', 10,
|
||||
'input_image_min_dimension', 300,
|
||||
'input_image_min_aspect_ratio', 0.4,
|
||||
'input_image_max_aspect_ratio', 2.5,
|
||||
'video_modes', JSON_ARRAY('first_frame', 'end_frame', 'start_end_frame'),
|
||||
'extra_body_json', JSON_OBJECT('sound', 'on', 'watermark_info', JSON_OBJECT('enabled', false)),
|
||||
'supports_4k', true,
|
||||
'supports_reference_image', true,
|
||||
'supports_start_end_frame', true,
|
||||
'supports_elements', true,
|
||||
'supports_voices', true,
|
||||
'supports_multi_shot', true,
|
||||
'supports_audio', true,
|
||||
'supports_lipsync', true,
|
||||
'supports_character_reference', true,
|
||||
'supports_multi_character', true,
|
||||
'supports_style_reference', false,
|
||||
'capability_version', 'kling_video_capabilities_2026-07-15',
|
||||
'formal_splus_model', true,
|
||||
'official_doc_url', 'https://kling.ai/document-api/api/video/3-0-omni/image-to-video',
|
||||
'note', '默认禁用。Kling v3 官方图生视频4K模式;正式批量前需单镜头验证。'
|
||||
),
|
||||
false,
|
||||
43,
|
||||
JSON_OBJECT('rpm', 5, 'concurrency', 1),
|
||||
JSON_OBJECT(
|
||||
'flat_cost', 0,
|
||||
'unit', 'video_seconds',
|
||||
'price_per_second', 0.504,
|
||||
'currency', 'USD',
|
||||
'cny_fx_rate', 6.79,
|
||||
'max_cost_per_call', 8,
|
||||
'daily_cost_limit', 120,
|
||||
'estimated_seconds', 10,
|
||||
'note', 'Kling v3 原生音频4K暂估 $0.504/s,10s约 $5.04 / ¥34.22;最终以Kling账单为准。'
|
||||
),
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`cost_rule_json` = VALUES(`cost_rule_json`),
|
||||
`updated_at` = NOW(3);
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.capability_version', 'kling_video_capabilities_2026-07-15',
|
||||
'$.formal_splus_model', true,
|
||||
'$.official_doc_url', 'https://kling.ai/document-api/api/video/3-0-omni/video-omni',
|
||||
'$.reference_video_default_type', 'base',
|
||||
'$.reference_video_character_policy', 'reject_with_reference_video',
|
||||
'$.custom_multi_shot_omits_top_prompt', true
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` IN (
|
||||
'kling-v3-omni-native-audio-720p-video',
|
||||
'kling-v3-omni-native-audio-1080p-video',
|
||||
'kling-v3-omni-native-audio-4k-video'
|
||||
);
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.formal_splus_model', false,
|
||||
'$.splus_usage', 'legacy_or_experiment_only'
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` LIKE 'kling%'
|
||||
AND `provider_code` NOT IN (
|
||||
'kling-v3-native-audio-720p-video',
|
||||
'kling-v3-native-audio-video',
|
||||
'kling-v3-native-audio-4k-video',
|
||||
'kling-v3-omni-native-audio-720p-video',
|
||||
'kling-v3-omni-native-audio-1080p-video',
|
||||
'kling-v3-omni-native-audio-4k-video'
|
||||
);
|
||||
|
||||
UPDATE `system_configs`
|
||||
SET
|
||||
`config_value` = JSON_SET(
|
||||
COALESCE(`config_value`, JSON_OBJECT()),
|
||||
'$.splus_live_action_video',
|
||||
JSON_OBJECT(
|
||||
'capability_version', 'kling_video_capabilities_2026-07-15',
|
||||
'formal_provider_codes', JSON_ARRAY(
|
||||
'kling-v3-omni-native-audio-720p-video',
|
||||
'kling-v3-omni-native-audio-1080p-video',
|
||||
'kling-v3-omni-native-audio-4k-video',
|
||||
'kling-v3-native-audio-720p-video',
|
||||
'kling-v3-native-audio-video',
|
||||
'kling-v3-native-audio-4k-video'
|
||||
),
|
||||
'zh-CN', JSON_OBJECT(
|
||||
'thresholds', JSON_OBJECT('premium_importance_gt', 7, 'premium_action_gt', 5),
|
||||
'normal', JSON_OBJECT(
|
||||
'provider_code', 'kling-v3-omni-native-audio-1080p-video',
|
||||
'fallback_chain', JSON_ARRAY('kling-v3-omni-native-audio-1080p-video', 'kling-v3-native-audio-video')
|
||||
),
|
||||
'premium', JSON_OBJECT(
|
||||
'provider_code', 'kling-v3-omni-native-audio-1080p-video',
|
||||
'fallback_chain', JSON_ARRAY('kling-v3-omni-native-audio-1080p-video', 'kling-v3-native-audio-video')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `config_key` = 'ai.router.v1';
|
||||
@@ -0,0 +1,15 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`cost_rule_json` = JSON_SET(
|
||||
COALESCE(`cost_rule_json`, JSON_OBJECT()),
|
||||
'$.price_per_second', 0.42,
|
||||
'$.currency', 'USD',
|
||||
'$.cny_fx_rate', 6.79,
|
||||
'$.max_cost_per_call', 7,
|
||||
'$.daily_cost_limit', 100,
|
||||
'$.estimated_seconds', 10,
|
||||
'$.note', 'Kling v3 原生音频4K $0.42/s,10s约 $4.20 / ¥28.52;最终以Kling账单为准。'
|
||||
),
|
||||
`updated_at` = NOW(3)
|
||||
WHERE `provider_type` = 'VideoProvider'
|
||||
AND `provider_code` = 'kling-v3-native-audio-4k-video';
|
||||
@@ -0,0 +1,64 @@
|
||||
CREATE TABLE `shot_generation_plans` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NOT NULL,
|
||||
`shot_id` BIGINT NOT NULL,
|
||||
`revision` INTEGER NOT NULL,
|
||||
`plan_version` VARCHAR(80) NOT NULL,
|
||||
`plan_hash` VARCHAR(64) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'frozen',
|
||||
`source_engine_version` VARCHAR(50) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`provider_id` BIGINT NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`endpoint` VARCHAR(255) NULL,
|
||||
`capability_version` VARCHAR(100) NULL,
|
||||
`route_tier` VARCHAR(50) NULL,
|
||||
`effective_mode` VARCHAR(30) NULL,
|
||||
`resolution_recommendation` VARCHAR(30) NULL,
|
||||
`effective_generation_resolution` VARCHAR(30) NULL,
|
||||
`aspect_ratio` VARCHAR(30) NULL,
|
||||
`duration` DECIMAL(6, 2) NULL,
|
||||
`sound_enabled` BOOLEAN NOT NULL DEFAULT true,
|
||||
`multi_shot` BOOLEAN NOT NULL DEFAULT false,
|
||||
`native_4k_candidate` BOOLEAN NOT NULL DEFAULT false,
|
||||
`project_native_4k_enabled` BOOLEAN NOT NULL DEFAULT false,
|
||||
`required_assets_json` JSON NULL,
|
||||
`element_plan_json` JSON NULL,
|
||||
`voice_plan_json` JSON NULL,
|
||||
`keyframe_plan_json` JSON NULL,
|
||||
`video_request_json` JSON NULL,
|
||||
`router_decision_json` JSON NOT NULL,
|
||||
`quality_policy_json` JSON NOT NULL,
|
||||
`retry_policy_json` JSON NOT NULL,
|
||||
`fallback_chain_json` JSON NOT NULL,
|
||||
`cost_policy_json` JSON NULL,
|
||||
`provider_snapshot_json` JSON NULL,
|
||||
`prompt_snapshot_json` JSON NULL,
|
||||
`frozen_by_user_id` BIGINT NULL,
|
||||
`frozen_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
UNIQUE INDEX `sgp_shot_revision_key` (`shot_id`, `revision`),
|
||||
UNIQUE INDEX `sgp_shot_hash_key` (`shot_id`, `plan_hash`),
|
||||
INDEX `sgp_project_episode_shot_idx` (`project_id`, `episode_id`, `shot_id`),
|
||||
INDEX `sgp_provider_capability_idx` (`provider_code`, `capability_version`),
|
||||
INDEX `sgp_status_created_idx` (`status`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `storyboard_shots`
|
||||
ADD COLUMN `active_generation_plan_id` BIGINT NULL,
|
||||
ADD INDEX `ss_active_generation_plan_idx` (`active_generation_plan_id`);
|
||||
|
||||
ALTER TABLE `shot_images`
|
||||
ADD COLUMN `generation_plan_id` BIGINT NULL,
|
||||
ADD INDEX `si_generation_plan_idx` (`generation_plan_id`);
|
||||
|
||||
ALTER TABLE `video_clips`
|
||||
ADD COLUMN `generation_plan_id` BIGINT NULL,
|
||||
ADD INDEX `vc_generation_plan_idx` (`generation_plan_id`);
|
||||
|
||||
ALTER TABLE `render_tasks`
|
||||
ADD COLUMN `generation_plan_id` BIGINT NULL,
|
||||
ADD INDEX `rt_generation_plan_idx` (`generation_plan_id`);
|
||||
@@ -0,0 +1,71 @@
|
||||
ALTER TABLE `shot_generation_plans`
|
||||
ADD COLUMN `capability_registry_version_id` BIGINT NULL AFTER `provider_id`,
|
||||
ADD COLUMN `parameter_schema_version_id` BIGINT NULL AFTER `capability_registry_version_id`,
|
||||
ADD COLUMN `pricing_version_id` BIGINT NULL AFTER `parameter_schema_version_id`;
|
||||
|
||||
CREATE INDEX `sgp_capability_registry_idx`
|
||||
ON `shot_generation_plans`(`capability_registry_version_id`);
|
||||
CREATE INDEX `sgp_parameter_schema_idx`
|
||||
ON `shot_generation_plans`(`parameter_schema_version_id`);
|
||||
CREATE INDEX `sgp_pricing_version_idx`
|
||||
ON `shot_generation_plans`(`pricing_version_id`);
|
||||
|
||||
CREATE TABLE `model_capability_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`provider_type` VARCHAR(80) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`revision` INTEGER NOT NULL,
|
||||
`version_key` VARCHAR(160) NOT NULL,
|
||||
`content_hash` VARCHAR(64) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'published',
|
||||
`capability_json` JSON NOT NULL,
|
||||
`source_json` JSON NULL,
|
||||
`effective_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `mcv_provider_revision_key`(`provider_type`, `provider_code`, `revision`),
|
||||
UNIQUE INDEX `mcv_provider_hash_key`(`provider_type`, `provider_code`, `content_hash`),
|
||||
INDEX `mcv_provider_status_effective_idx`(`provider_code`, `status`, `effective_at`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `model_parameter_schema_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`provider_type` VARCHAR(80) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`revision` INTEGER NOT NULL,
|
||||
`version_key` VARCHAR(160) NOT NULL,
|
||||
`content_hash` VARCHAR(64) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'published',
|
||||
`schema_json` JSON NOT NULL,
|
||||
`source_json` JSON NULL,
|
||||
`effective_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `mpsv_provider_revision_key`(`provider_type`, `provider_code`, `revision`),
|
||||
UNIQUE INDEX `mpsv_provider_hash_key`(`provider_type`, `provider_code`, `content_hash`),
|
||||
INDEX `mpsv_provider_status_effective_idx`(`provider_code`, `status`, `effective_at`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `model_pricing_versions` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`provider_type` VARCHAR(80) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`model_name` VARCHAR(160) NULL,
|
||||
`revision` INTEGER NOT NULL,
|
||||
`version_key` VARCHAR(160) NOT NULL,
|
||||
`content_hash` VARCHAR(64) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'published',
|
||||
`pricing_json` JSON NOT NULL,
|
||||
`source_json` JSON NULL,
|
||||
`effective_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `mpv_provider_revision_key`(`provider_type`, `provider_code`, `revision`),
|
||||
UNIQUE INDEX `mpv_provider_hash_key`(`provider_type`, `provider_code`, `content_hash`),
|
||||
INDEX `mpv_provider_status_effective_idx`(`provider_code`, `status`, `effective_at`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
CREATE TABLE `character_provider_bindings` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`global_character_id` BIGINT NOT NULL,
|
||||
`look_version_id` BIGINT NULL,
|
||||
`source_asset_id` BIGINT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`provider_asset_type` VARCHAR(50) NOT NULL DEFAULT 'video_character_element',
|
||||
`provider_element_id` VARCHAR(191) NOT NULL,
|
||||
`element_name` VARCHAR(160) NOT NULL,
|
||||
`element_description` TEXT NULL,
|
||||
`source_duration` DECIMAL(5,2) NULL,
|
||||
`voice_bound` BOOLEAN NOT NULL DEFAULT false,
|
||||
`voice_id` VARCHAR(160) NULL,
|
||||
`voice_description` TEXT NULL,
|
||||
`binding_version` INTEGER NOT NULL DEFAULT 1,
|
||||
`validation_score` DECIMAL(5,2) NULL,
|
||||
`validation_report_json` JSON NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'candidate',
|
||||
`is_primary` BOOLEAN NOT NULL DEFAULT false,
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `cpb_provider_element_key`(`provider_code`, `provider_element_id`),
|
||||
INDEX `cpb_character_provider_status_idx`(`global_character_id`, `provider_code`, `status`),
|
||||
INDEX `cpb_look_version_idx`(`look_version_id`),
|
||||
INDEX `cpb_source_asset_idx`(`source_asset_id`),
|
||||
INDEX `cpb_primary_status_idx`(`is_primary`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.aspect_ratio', '16:9',
|
||||
'$.allowed_aspect_ratios', JSON_ARRAY('16:9'),
|
||||
'$.production_aspect_ratio', '16:9'
|
||||
)
|
||||
WHERE `provider_type` IN ('ImageProvider', 'VideoProvider');
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_SET(`config_json`, '$.size', '2560x1440')
|
||||
WHERE `provider_type` = 'ImageProvider'
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.size')) = '1440x2560';
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_SET(`config_json`, '$.size', '1536x1024')
|
||||
WHERE `provider_type` = 'ImageProvider'
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.size')) = '1024x1792';
|
||||
|
||||
UPDATE `provider_configs`
|
||||
SET `config_json` = JSON_SET(
|
||||
`config_json`,
|
||||
'$.width', CAST(JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.height')) AS UNSIGNED),
|
||||
'$.height', CAST(JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.width')) AS UNSIGNED)
|
||||
)
|
||||
WHERE `provider_type` IN ('ImageProvider', 'VideoProvider')
|
||||
AND JSON_TYPE(JSON_EXTRACT(`config_json`, '$.width')) IN ('INTEGER', 'DOUBLE')
|
||||
AND JSON_TYPE(JSON_EXTRACT(`config_json`, '$.height')) IN ('INTEGER', 'DOUBLE')
|
||||
AND CAST(JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.width')) AS UNSIGNED)
|
||||
< CAST(JSON_UNQUOTE(JSON_EXTRACT(`config_json`, '$.height')) AS UNSIGNED);
|
||||
@@ -0,0 +1,45 @@
|
||||
UPDATE `provider_configs`
|
||||
SET
|
||||
`config_json` = JSON_SET(
|
||||
COALESCE(`config_json`, JSON_OBJECT()),
|
||||
'$.size', '2560x1440',
|
||||
'$.quality', 'medium',
|
||||
'$.allowed_sizes', JSON_ARRAY('1920x1080', '2560x1440', '3840x2160'),
|
||||
'$.allowed_qualities', JSON_ARRAY('low', 'medium', 'high', 'auto'),
|
||||
'$.supports_custom_size', true,
|
||||
'$.supports_4k', true,
|
||||
'$.max_width', 3840,
|
||||
'$.max_height', 3840,
|
||||
'$.max_pixels', 8294400,
|
||||
'$.max_aspect_ratio', 3,
|
||||
'$.experimental_above_size', '2560x1440',
|
||||
'$.official_doc_url', 'https://developers.openai.com/api/docs/guides/image-generation'
|
||||
),
|
||||
`cost_rule_json` = JSON_REMOVE(
|
||||
JSON_SET(
|
||||
COALESCE(`cost_rule_json`, JSON_OBJECT()),
|
||||
'$.flat_cost', 0,
|
||||
'$.unit', 'openai_image_tokens',
|
||||
'$.currency', 'USD',
|
||||
'$.cny_fx_rate', 7.2,
|
||||
'$.pricing_basis', 'official_openai_gpt_image_2_token_formula_2026_07_16',
|
||||
'$.default_quality', 'medium',
|
||||
'$.default_size', '2560x1440',
|
||||
'$.estimated_cost_per_image', 0.05529,
|
||||
'$.price_per_1m_text_input_tokens', 5,
|
||||
'$.price_per_1m_cached_text_input_tokens', 1.25,
|
||||
'$.price_per_1m_image_input_tokens', 8,
|
||||
'$.price_per_1m_cached_image_input_tokens', 2,
|
||||
'$.price_per_1m_image_output_tokens', 30,
|
||||
'$.output_token_formula', 'ceil(long_quality_tokens*round(long_quality_tokens*short_edge/long_edge)*(2000000+width*height)/4000000)',
|
||||
'$.output_price_examples', JSON_OBJECT(
|
||||
'2560x1440_high', 0.2211,
|
||||
'3840x2160_high', 0.40026
|
||||
),
|
||||
'$.note', 'GPT Image 2 按文字输入、参考图输入和图片输出 token 计费;2560×1440 High 纯输出约 $0.2211,3840×2160 High 纯输出约 $0.4003。参考图与提示词输入另计,以 OpenAI usage 和账单为准。'
|
||||
),
|
||||
'$.price_per_image_by_quality',
|
||||
'$.comparable_models'
|
||||
)
|
||||
WHERE `provider_type` = 'ImageProvider'
|
||||
AND `provider_code` = 'openai-image';
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `project_pipeline_configs`
|
||||
ALTER COLUMN `scene_composer_version` SET DEFAULT 'scene_composer_plan_v2';
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
UPDATE `project_pipeline_configs`
|
||||
SET
|
||||
`scene_composer_version` = 'scene_composer_plan_v2',
|
||||
`scene_composer_config_json` = JSON_SET(
|
||||
COALESCE(`scene_composer_config_json`, JSON_OBJECT()),
|
||||
'$.plan_version', 'scene_composer_plan_v2',
|
||||
'$.transition_contract_version', 'transition_contract_v2',
|
||||
'$.picture_edit_policy', 'hard_picture_by_default_explicit_blends_only',
|
||||
'$.audio_edit_policy', 'independent_j_cut_l_cut_and_audio_bridge',
|
||||
'$.planned_features', JSON_ARRAY(
|
||||
'shot_ordering',
|
||||
'emotion_curve',
|
||||
'transition_contract_v2',
|
||||
'boundary_frame_policy',
|
||||
'screen_vector_continuity',
|
||||
'hard_picture_cut',
|
||||
'explicit_visual_blends_only',
|
||||
'independent_j_cut_l_cut',
|
||||
'episode_builder',
|
||||
'bgm_alignment',
|
||||
'original_music_bible',
|
||||
'sfx_cue_plan',
|
||||
'ducking_plan'
|
||||
),
|
||||
'$.note', 'Scene Composer Plan V2 keeps picture hard by default, permits visual overlap only for explicit blend contracts, and schedules J-cuts, L-cuts and audio bridges independently.'
|
||||
);
|
||||
+1151
-256
File diff suppressed because it is too large
Load Diff
+324
-1
@@ -1,4 +1,4 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { Prisma, PrismaClient } from '@prisma/client';
|
||||
import { hash } from 'bcryptjs';
|
||||
import { DEFAULT_AI_ROUTER_CONFIG } from '../src/ai-router/ai-router.types';
|
||||
|
||||
@@ -17,6 +17,296 @@ const mockProviders = [
|
||||
['EmbeddingProvider', 'mock-embedding', 'Mock Embedding Provider', 'mock-embedding-v1']
|
||||
] as const;
|
||||
|
||||
const defaultAgentPrompts = [
|
||||
{
|
||||
agent_name: 'NovelIdeaCoachAgent',
|
||||
provider_type: 'TextProvider',
|
||||
default_provider_code: 'volcengine-doubao-seed20-mini-text',
|
||||
system_prompt: '你是网文平台金牌主编、商业化小说策划、听书编导和短剧改编策划。你的用户是不会写小说的运营,你必须把他的白话需求变成可选择的高质量小说方案。',
|
||||
user_prompt_template: [
|
||||
'请根据运营输入生成 3 个高商业化小说方向卡。必须严格输出紧凑 JSON,不要 Markdown,不要解释。',
|
||||
'运营不是专业作家,所以每个方案要短、准、好判断:为什么能火、主角是谁、开篇怎么抓人。',
|
||||
'本步骤只做方向筛选,不写卷纲和章节蓝图;后续 IP 圣经 Agent 会补完整结构。',
|
||||
'必须兼顾后续听书和短剧改编:人物关系清楚、场景可视化、每章能有钩子。',
|
||||
'输出 JSON 字段:proposals。proposals 是数组,每个元素包含:',
|
||||
'id, title, genre, novel_scale, target_audience, target_words, target_chapters, style_code, logline, opening_hook, main_character, core_conflict, selling_points, risk_notes, adaptation_targets, writing_rules, forbidden_rules, score, operator_reason。',
|
||||
'要求:',
|
||||
'1. title 要像真实网文书名,不要泛泛而谈。',
|
||||
'2. logline 不超过 35 字,opening_hook 不超过 55 字。',
|
||||
'3. main_character 和 core_conflict 各不超过 35 字。',
|
||||
'4. selling_points 只给 3 条,每条不超过 10 字;risk_notes 只给 2 条,每条不超过 12 字。',
|
||||
'5. writing_rules 只给 2 条,forbidden_rules 只给 2 条,每条不超过 12 字。',
|
||||
'6. target_words 和 target_chapters 必须是数字或 null。',
|
||||
'7. adaptation_targets 只输出 ["听书","短剧"],operator_reason 不超过 35 字,score 是 0-100。',
|
||||
'小说长度:{{novel_scale}}',
|
||||
'目标读者:{{target_audience}}',
|
||||
'题材:{{genre}}',
|
||||
'风格代码:{{style_code}}',
|
||||
'目标字数:{{target_words}}',
|
||||
'目标章节数:{{target_chapters}}',
|
||||
'后续用途:{{adaptation_targets}}',
|
||||
'运营灵感:{{inspiration_text}}',
|
||||
'必须包含:{{must_have_text}}',
|
||||
'禁止内容:{{avoid_text}}',
|
||||
'参考风格/作品:{{reference_titles}}'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['proposals'],
|
||||
properties: {
|
||||
proposals: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['title', 'logline', 'opening_hook', 'main_character', 'core_conflict', 'selling_points', 'score'],
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
genre: { type: 'string' },
|
||||
novel_scale: { type: 'string' },
|
||||
target_audience: { type: 'string' },
|
||||
target_words: { type: 'number' },
|
||||
target_chapters: { type: 'number' },
|
||||
style_code: { type: 'string' },
|
||||
logline: { type: 'string' },
|
||||
opening_hook: { type: 'string' },
|
||||
main_character: { type: 'string' },
|
||||
core_conflict: { type: 'string' },
|
||||
selling_points: { type: 'array' },
|
||||
risk_notes: { type: 'array' },
|
||||
adaptation_targets: { type: 'array' },
|
||||
writing_rules: { type: 'array' },
|
||||
forbidden_rules: { type: 'array' },
|
||||
score: { type: 'number' },
|
||||
operator_reason: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
temperature: 0.72,
|
||||
max_output_tokens: 1200
|
||||
},
|
||||
{
|
||||
agent_name: 'IPBibleAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'openai-responses-novel',
|
||||
system_prompt: '你是专业长篇小说总策划、网文主编、文学作家、剧作结构师和影视导演。你的任务是建立稳定、可长期创作、可听书、可短剧改编的 IP 圣经。',
|
||||
user_prompt_template: [
|
||||
'请根据用户 Brief 生成 IP 圣经。必须严格输出 JSON,不要 Markdown。',
|
||||
'JSON 字段:core_logline, theme, worldbuilding, main_characters, supporting_characters, antagonist_system, volume_structure, foreshadow_plan, writing_rules, forbidden_rules, adaptation_rules。',
|
||||
'要求:主线清晰,人设稳定,有禁止改动项,有伏笔规划,考虑听书和 AI 短剧改编。',
|
||||
'用户 Brief:{{brief}}',
|
||||
'小说类型:{{novel_scale}}',
|
||||
'题材:{{genre}}',
|
||||
'风格:{{style}}',
|
||||
'禁止内容:{{avoid}}'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['core_logline', 'theme', 'worldbuilding', 'main_characters', 'volume_structure', 'writing_rules', 'forbidden_rules'],
|
||||
properties: {
|
||||
core_logline: { type: 'string' },
|
||||
theme: { type: 'string' },
|
||||
worldbuilding: { type: 'object' },
|
||||
main_characters: { type: 'array' },
|
||||
supporting_characters: { type: 'array' },
|
||||
antagonist_system: { type: 'object' },
|
||||
volume_structure: { type: 'array' },
|
||||
foreshadow_plan: { type: 'array' },
|
||||
writing_rules: { type: 'array' },
|
||||
forbidden_rules: { type: 'array' },
|
||||
adaptation_rules: { type: 'object' }
|
||||
}
|
||||
},
|
||||
temperature: 0.6,
|
||||
max_output_tokens: 6000
|
||||
},
|
||||
{
|
||||
agent_name: 'ChapterCardAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'openai-responses-novel',
|
||||
system_prompt: '你是长篇小说章节导演。你的任务是设计下一章章节卡,不写正文,只输出可执行的章节方案。',
|
||||
user_prompt_template: [
|
||||
'请生成第 {{chapter_no}} 章章节卡。必须严格输出 JSON,不要 Markdown。',
|
||||
'本章必须承接上一章,推动主线、人物变化或伏笔进展,不得水剧情。',
|
||||
'IP 圣经摘要:{{ip_bible_summary}}',
|
||||
'当前卷纲:{{volume_outline}}',
|
||||
'最近章节摘要:{{recent_summaries}}',
|
||||
'人物当前状态:{{character_states}}',
|
||||
'当前伏笔:{{active_foreshadows}}',
|
||||
'禁止事项:{{forbidden_rules}}',
|
||||
'请输出:chapter_no, title, chapter_goal, scenes, must_happen, must_not_happen, foreshadows_to_add, foreshadows_to_advance, foreshadows_to_resolve, ending_hook, adaptation_notes。'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['chapter_no', 'title', 'chapter_goal', 'scenes', 'must_happen', 'must_not_happen', 'ending_hook'],
|
||||
properties: {
|
||||
chapter_no: { type: 'number' },
|
||||
title: { type: 'string' },
|
||||
chapter_goal: { type: 'string' },
|
||||
scenes: { type: 'array' },
|
||||
must_happen: { type: 'array' },
|
||||
must_not_happen: { type: 'array' },
|
||||
foreshadows_to_add: { type: 'array' },
|
||||
foreshadows_to_advance: { type: 'array' },
|
||||
foreshadows_to_resolve: { type: 'array' },
|
||||
ending_hook: { type: 'string' },
|
||||
adaptation_notes: { type: 'object' }
|
||||
}
|
||||
},
|
||||
temperature: 0.45,
|
||||
max_output_tokens: 4000
|
||||
},
|
||||
{
|
||||
agent_name: 'NovelWriterAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'anthropic-claude-novel',
|
||||
system_prompt: '你是专业小说家。你必须严格按章节卡写正文,不改变 IP 圣经,不改变人物状态,不提前揭露秘密。',
|
||||
user_prompt_template: [
|
||||
'请创作第 {{chapter_no}} 章正文,只输出正文,不要解释。',
|
||||
'目标字数:{{target_words}}',
|
||||
'文风规则:{{style_rules}}',
|
||||
'IP 圣经摘要:{{ip_bible_summary}}',
|
||||
'人物档案:{{character_profiles}}',
|
||||
'人物当前状态:{{character_states}}',
|
||||
'最近章节摘要:{{recent_summaries}}',
|
||||
'章节卡:{{chapter_card}}',
|
||||
'禁止规则:{{forbidden_rules}}',
|
||||
'要求:画面感强、对白符合身份、每场戏推动剧情/人物/伏笔,不能流水账,不能狗血。'
|
||||
].join('\n\n'),
|
||||
output_schema_json: null,
|
||||
temperature: 0.75,
|
||||
max_output_tokens: 9000
|
||||
},
|
||||
{
|
||||
agent_name: 'NovelPolishAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'anthropic-claude-novel',
|
||||
system_prompt: '你是小说修辞和节奏编辑。你只负责润色文风、节奏、对白和画面感,不得改变剧情事实。',
|
||||
user_prompt_template: [
|
||||
'请润色下面章节,输出完整润色稿,不要解释。',
|
||||
'目标文风:{{style_rules}}',
|
||||
'章节卡:{{chapter_card}}',
|
||||
'禁止改变:{{forbidden_rules}}',
|
||||
'原稿:{{draft_text}}'
|
||||
].join('\n\n'),
|
||||
output_schema_json: null,
|
||||
temperature: 0.65,
|
||||
max_output_tokens: 9000
|
||||
},
|
||||
{
|
||||
agent_name: 'ContinuityCheckAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'openai-responses-novel',
|
||||
system_prompt: '你是严苛的小说连续性审稿人,只检查冲突,不负责夸奖。',
|
||||
user_prompt_template: [
|
||||
'请检查本章是否违背设定、人设、时间线、地点、伏笔。必须严格输出 JSON,不要 Markdown。',
|
||||
'IP 圣经:{{ip_bible}}',
|
||||
'人物状态:{{character_states}}',
|
||||
'伏笔库:{{active_foreshadows}}',
|
||||
'章节卡:{{chapter_card}}',
|
||||
'本章正文:{{chapter_text}}',
|
||||
'请输出:has_conflict, conflicts, character_drift, timeline_errors, setting_errors, foreshadow_errors, fix_suggestions。'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['has_conflict', 'conflicts', 'fix_suggestions'],
|
||||
properties: {
|
||||
has_conflict: { type: 'boolean' },
|
||||
conflicts: { type: 'array' },
|
||||
character_drift: { type: 'array' },
|
||||
timeline_errors: { type: 'array' },
|
||||
setting_errors: { type: 'array' },
|
||||
foreshadow_errors: { type: 'array' },
|
||||
fix_suggestions: { type: 'array' }
|
||||
}
|
||||
},
|
||||
temperature: 0.2,
|
||||
max_output_tokens: 3000
|
||||
},
|
||||
{
|
||||
agent_name: 'QualityCheckAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'openai-responses-novel',
|
||||
system_prompt: '你是严苛的小说主编和质量评分官。你只输出评分、问题和修复策略。',
|
||||
user_prompt_template: [
|
||||
'请为本章评分。必须严格输出 JSON,不要 Markdown。',
|
||||
'评分维度:剧情推进、人物一致性、上下文连续性、文风质量、情绪张力、伏笔管理、场景画面感、听书适配度、短剧适配度。',
|
||||
'IP 圣经:{{ip_bible}}',
|
||||
'章节卡:{{chapter_card}}',
|
||||
'连续性检查:{{continuity_check}}',
|
||||
'本章正文:{{chapter_text}}',
|
||||
'请输出:pass, total_score, scores, problems, must_fix, optional_suggestions, rewrite_required, rewrite_strategy。'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['pass', 'total_score', 'scores', 'problems', 'rewrite_required'],
|
||||
properties: {
|
||||
pass: { type: 'boolean' },
|
||||
total_score: { type: 'number' },
|
||||
scores: { type: 'object' },
|
||||
problems: { type: 'array' },
|
||||
must_fix: { type: 'array' },
|
||||
optional_suggestions: { type: 'array' },
|
||||
rewrite_required: { type: 'boolean' },
|
||||
rewrite_strategy: { type: 'array' }
|
||||
}
|
||||
},
|
||||
temperature: 0.2,
|
||||
max_output_tokens: 3000
|
||||
},
|
||||
{
|
||||
agent_name: 'RepairAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'anthropic-claude-novel',
|
||||
system_prompt: '你是小说修稿编辑。你只修复质检指出的问题,不新增无关设定,不破坏上下文。',
|
||||
user_prompt_template: [
|
||||
'请根据质检报告修复本章,输出完整修复稿,不要解释。',
|
||||
'IP 圣经摘要:{{ip_bible_summary}}',
|
||||
'章节卡:{{chapter_card}}',
|
||||
'原正文:{{chapter_text}}',
|
||||
'质检报告:{{quality_report}}',
|
||||
'连续性检查:{{continuity_check}}'
|
||||
].join('\n\n'),
|
||||
output_schema_json: null,
|
||||
temperature: 0.55,
|
||||
max_output_tokens: 9000
|
||||
},
|
||||
{
|
||||
agent_name: 'MemoryUpdateAgent',
|
||||
provider_type: 'NovelProvider',
|
||||
default_provider_code: 'volcengine-doubao-seed20-pro-novel',
|
||||
system_prompt: '你是小说连续性档案管理员。你必须准确、简洁,不得加入正文没有发生的内容,不得猜测未来。',
|
||||
user_prompt_template: [
|
||||
'请根据本章正文更新记忆库。必须严格输出 JSON,不要 Markdown。',
|
||||
'已有角色状态:{{character_states}}',
|
||||
'已有伏笔库:{{active_foreshadows}}',
|
||||
'本章正文:{{chapter_text}}',
|
||||
'请输出:chapter_summary, character_updates, relationship_updates, world_updates, timeline_update, location_update, new_foreshadows, updated_foreshadows, resolved_foreshadows, next_chapter_must_continue, forbidden_to_forget。'
|
||||
].join('\n\n'),
|
||||
output_schema_json: {
|
||||
type: 'object',
|
||||
required: ['chapter_summary', 'character_updates', 'timeline_update', 'next_chapter_must_continue'],
|
||||
properties: {
|
||||
chapter_summary: { type: 'string' },
|
||||
character_updates: { type: 'array' },
|
||||
relationship_updates: { type: 'array' },
|
||||
world_updates: { type: 'array' },
|
||||
timeline_update: { type: 'string' },
|
||||
location_update: { type: 'string' },
|
||||
new_foreshadows: { type: 'array' },
|
||||
updated_foreshadows: { type: 'array' },
|
||||
resolved_foreshadows: { type: 'array' },
|
||||
next_chapter_must_continue: { type: 'array' },
|
||||
forbidden_to_forget: { type: 'array' }
|
||||
}
|
||||
},
|
||||
temperature: 0.25,
|
||||
max_output_tokens: 3500
|
||||
}
|
||||
] as const;
|
||||
|
||||
async function main() {
|
||||
const adminPassword = process.env.SEED_ADMIN_PASSWORD || 'Admin123!';
|
||||
const adminPasswordHash = await hash(adminPassword, 12);
|
||||
@@ -84,6 +374,39 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
for (const prompt of defaultAgentPrompts) {
|
||||
await prisma.agentPrompt.upsert({
|
||||
where: {
|
||||
agent_name_version: {
|
||||
agent_name: prompt.agent_name,
|
||||
version: 1
|
||||
}
|
||||
},
|
||||
update: {
|
||||
provider_type: prompt.provider_type,
|
||||
default_provider_code: prompt.default_provider_code ?? null,
|
||||
system_prompt: prompt.system_prompt,
|
||||
user_prompt_template: prompt.user_prompt_template,
|
||||
output_schema_json: prompt.output_schema_json ?? Prisma.JsonNull,
|
||||
temperature: prompt.temperature,
|
||||
max_output_tokens: prompt.max_output_tokens,
|
||||
is_active: true
|
||||
},
|
||||
create: {
|
||||
agent_name: prompt.agent_name,
|
||||
version: 1,
|
||||
provider_type: prompt.provider_type,
|
||||
default_provider_code: prompt.default_provider_code ?? null,
|
||||
system_prompt: prompt.system_prompt,
|
||||
user_prompt_template: prompt.user_prompt_template,
|
||||
output_schema_json: prompt.output_schema_json ?? Prisma.JsonNull,
|
||||
temperature: prompt.temperature,
|
||||
max_output_tokens: prompt.max_output_tokens,
|
||||
is_active: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await prisma.systemConfig.upsert({
|
||||
where: { config_key: 'system_a.current_stage' },
|
||||
update: {
|
||||
|
||||
Reference in New Issue
Block a user