CREATE TABLE IF NOT EXISTS `t_ai_provider` ( `id` varchar(64) NOT NULL COMMENT 'primary key', `provider_code` varchar(64) NOT NULL COMMENT 'provider code', `provider_name` varchar(100) NOT NULL COMMENT 'provider display name', `provider_type` varchar(32) NOT NULL COMMENT 'dify/coze/openai/etc', `base_url` varchar(500) NOT NULL COMMENT 'provider base url', `api_key` text NULL COMMENT 'api key or token', `auth_type` varchar(32) DEFAULT 'bearer' COMMENT 'auth type', `default_headers` text NULL COMMENT 'json headers', `timeout_ms` int DEFAULT 60000 COMMENT 'timeout milliseconds', `is_enabled` tinyint DEFAULT 1 COMMENT '0 disabled, 1 enabled', `description` varchar(500) NULL COMMENT 'description', `create_by` varchar(64) NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_by` varchar(64) NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint DEFAULT 0, `remarks` varchar(500) NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_ai_provider_code` (`provider_code`), KEY `idx_ai_provider_type` (`provider_type`, `is_enabled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI provider configuration'; CREATE TABLE IF NOT EXISTS `t_ai_endpoint_config` ( `id` varchar(64) NOT NULL COMMENT 'primary key', `endpoint_code` varchar(100) NOT NULL COMMENT 'endpoint code', `endpoint_name` varchar(100) NOT NULL COMMENT 'endpoint display name', `provider_id` varchar(64) NOT NULL COMMENT 'provider id', `endpoint_type` varchar(32) NOT NULL COMMENT 'workflow/chat/completion', `api_path` varchar(300) NULL COMMENT 'provider api path', `workflow_id` varchar(128) NULL COMMENT 'workflow id', `bot_id` varchar(128) NULL COMMENT 'bot id', `model_name` varchar(128) NULL COMMENT 'model name', `response_mode` varchar(32) DEFAULT 'streaming' COMMENT 'streaming/blocking', `request_template` text NULL COMMENT 'json request template with {{var}} placeholders', `default_inputs` text NULL COMMENT 'json default inputs', `custom_headers` text NULL COMMENT 'json custom headers', `timeout_ms` int DEFAULT 60000 COMMENT 'timeout milliseconds', `support_stream` tinyint DEFAULT 1 COMMENT '0 no, 1 yes', `is_enabled` tinyint DEFAULT 1 COMMENT '0 disabled, 1 enabled', `description` varchar(500) NULL COMMENT 'description', `create_by` varchar(64) NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_by` varchar(64) NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint DEFAULT 0, `remarks` varchar(500) NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_ai_endpoint_code` (`endpoint_code`), KEY `idx_ai_endpoint_provider` (`provider_id`, `is_enabled`), KEY `idx_ai_endpoint_type` (`endpoint_type`, `support_stream`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI endpoint and workflow configuration'; CREATE TABLE IF NOT EXISTS `t_ai_scene_binding` ( `id` varchar(64) NOT NULL COMMENT 'primary key', `scene_code` varchar(100) NOT NULL COMMENT 'scene code', `scene_name` varchar(100) NOT NULL COMMENT 'scene display name', `endpoint_id` varchar(64) NOT NULL COMMENT 'endpoint id', `input_schema` text NULL COMMENT 'json schema or field description', `prompt_template` text NULL COMMENT 'reserved prompt template', `required_stream` tinyint DEFAULT 1 COMMENT '0 no, 1 yes', `priority` int DEFAULT 0 COMMENT 'larger value wins', `is_enabled` tinyint DEFAULT 1 COMMENT '0 disabled, 1 enabled', `version` varchar(32) DEFAULT 'v1' COMMENT 'binding version', `description` varchar(500) NULL COMMENT 'description', `create_by` varchar(64) NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_by` varchar(64) NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint DEFAULT 0, `remarks` varchar(500) NULL, PRIMARY KEY (`id`), KEY `idx_ai_scene_code` (`scene_code`, `is_enabled`, `priority`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI scene to endpoint binding'; CREATE TABLE IF NOT EXISTS `t_ai_call_log` ( `id` varchar(64) NOT NULL COMMENT 'primary key', `scene_code` varchar(100) NULL COMMENT 'scene code', `provider_code` varchar(64) NULL COMMENT 'provider code', `endpoint_code` varchar(100) NULL COMMENT 'endpoint code', `user_id` varchar(64) NULL COMMENT 'user id', `request_id` varchar(64) NULL COMMENT 'request id', `status` varchar(32) NULL COMMENT 'running/success/failed', `input_text` mediumtext NULL COMMENT 'input payload', `output_text` mediumtext NULL COMMENT 'stream output', `error_code` varchar(64) NULL COMMENT 'error code', `error_message` text NULL COMMENT 'error message', `first_token_ms` bigint NULL COMMENT 'first token latency', `duration_ms` bigint NULL COMMENT 'duration milliseconds', `stream_chunks` int DEFAULT 0 COMMENT 'stream delta chunks', `create_by` varchar(64) NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_by` varchar(64) NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint DEFAULT 0, `remarks` varchar(500) NULL, PRIMARY KEY (`id`), KEY `idx_ai_call_scene_time` (`scene_code`, `create_time`), KEY `idx_ai_call_request` (`request_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI runtime call log'; INSERT INTO `t_ai_scene_binding` (`id`, `scene_code`, `scene_name`, `endpoint_id`, `input_schema`, `required_stream`, `priority`, `is_enabled`, `version`, `description`) SELECT UUID(), scene_code, scene_name, '', '{"prompt":"string"}', 1, 0, 0, 'v1', 'Reserved scene. Bind an enabled endpoint before use.' FROM ( SELECT 'chat' scene_code, 'AI 对话' scene_name UNION ALL SELECT 'script_generate', '剧本生成' UNION ALL SELECT 'short_story_generate', '短篇小说生成' UNION ALL SELECT 'diary_summary', '日记总结' UNION ALL SELECT 'emotion_summary', '情绪总结' UNION ALL SELECT 'emotion_analysis', '情绪分析' UNION ALL SELECT 'life_healing', '人生事件疗愈' ) s WHERE NOT EXISTS ( SELECT 1 FROM `t_ai_scene_binding` b WHERE b.`scene_code` = s.scene_code AND b.`is_deleted` = 0 ); UPDATE `t_ai_scene_binding` SET `scene_name` = CASE `scene_code` WHEN 'chat' THEN 'AI 对话' WHEN 'script_generate' THEN '剧本生成' WHEN 'short_story_generate' THEN '短篇小说生成' WHEN 'diary_summary' THEN '日记总结' WHEN 'emotion_summary' THEN '情绪总结' WHEN 'emotion_analysis' THEN '情绪分析' WHEN 'life_healing' THEN '人生事件疗愈' ELSE `scene_name` END WHERE `scene_code` IN ('chat', 'script_generate', 'short_story_generate', 'diary_summary', 'emotion_summary', 'emotion_analysis', 'life_healing') AND `is_deleted` = 0; INSERT INTO `t_ai_provider` (`id`, `provider_code`, `provider_name`, `provider_type`, `base_url`, `api_key`, `auth_type`, `default_headers`, `timeout_ms`, `is_enabled`, `description`) SELECT UUID(), 'coze_default', 'Coze 默认服务商', 'coze', 'https://api.coze.cn', c.`api_token`, 'bearer', NULL, COALESCE(c.`timeout_ms`, 60000), 1, '由旧 AI 配置自动迁移生成' FROM `t_ai_config` c WHERE c.`is_deleted` = 0 AND c.`provider` = 'coze' AND c.`api_token` IS NOT NULL AND c.`api_token` <> '' AND NOT EXISTS ( SELECT 1 FROM `t_ai_provider` p WHERE p.`provider_code` = 'coze_default' AND p.`is_deleted` = 0 ) ORDER BY c.`create_time` DESC LIMIT 1; INSERT INTO `t_ai_provider` (`id`, `provider_code`, `provider_name`, `provider_type`, `base_url`, `api_key`, `auth_type`, `default_headers`, `timeout_ms`, `is_enabled`, `description`) SELECT UUID(), 'dify_default', 'Dify 默认服务商', 'dify', 'http://49.232.138.53/v1', 'app-MqQOx09gCu9zzlKMpeLqHQHv', 'bearer', NULL, 60000, 1, '由 Dify 平台接口文档初始化生成' WHERE NOT EXISTS ( SELECT 1 FROM `t_ai_provider` p WHERE p.`provider_code` = 'dify_default' AND p.`is_deleted` = 0 ); INSERT INTO `t_ai_endpoint_config` (`id`, `endpoint_code`, `endpoint_name`, `provider_id`, `endpoint_type`, `api_path`, `workflow_id`, `bot_id`, `response_mode`, `request_template`, `default_inputs`, `custom_headers`, `timeout_ms`, `support_stream`, `is_enabled`, `description`) SELECT UUID(), c.`config_key`, c.`config_name`, p.`id`, CASE WHEN c.`workflow_id` IS NOT NULL AND c.`workflow_id` <> '' THEN 'workflow' ELSE 'chat' END, CASE WHEN c.`api_base_url` LIKE '%/v1/workflow/stream_run' THEN '/v1/workflow/stream_run' WHEN c.`api_base_url` LIKE '%/v3/chat' THEN '/v3/chat' ELSE '/v1/workflow/stream_run' END, c.`workflow_id`, c.`bot_id`, 'streaming', NULL, '{}', c.`custom_headers`, COALESCE(c.`timeout_ms`, 60000), COALESCE(c.`support_stream`, 1), c.`is_enabled`, CONCAT('由旧 AI 配置迁移:', c.`config_key`) FROM `t_ai_config` c JOIN `t_ai_provider` p ON p.`provider_code` = 'coze_default' AND p.`is_deleted` = 0 WHERE c.`is_deleted` = 0 AND c.`provider` = 'coze' AND NOT EXISTS ( SELECT 1 FROM `t_ai_endpoint_config` e WHERE e.`endpoint_code` COLLATE utf8mb4_unicode_ci = c.`config_key` COLLATE utf8mb4_unicode_ci AND e.`is_deleted` = 0 ); INSERT INTO `t_ai_endpoint_config` (`id`, `endpoint_code`, `endpoint_name`, `provider_id`, `endpoint_type`, `api_path`, `workflow_id`, `bot_id`, `response_mode`, `request_template`, `default_inputs`, `custom_headers`, `timeout_ms`, `support_stream`, `is_enabled`, `description`) SELECT UUID(), endpoint_code, endpoint_name, p.`id`, 'chat', '/chat-messages', NULL, NULL, 'streaming', NULL, '{}', NULL, 60000, 1, 1, '由 Dify 平台接口文档初始化生成' FROM ( SELECT 'dify.script_generate.chat_messages' endpoint_code, 'Dify 剧本生成对话接口' endpoint_name UNION ALL SELECT 'dify.short_story_generate.chat_messages', 'Dify 短篇小说生成对话接口' ) seed JOIN `t_ai_provider` p ON p.`provider_code` = 'dify_default' AND p.`is_deleted` = 0 WHERE NOT EXISTS ( SELECT 1 FROM `t_ai_endpoint_config` e WHERE e.`endpoint_code` = seed.endpoint_code AND e.`is_deleted` = 0 ); UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.chat.default' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 聊天工作流' WHERE s.`scene_code` = 'chat' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'dify.script_generate.chat_messages' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定 Dify 剧本生成接口' WHERE s.`scene_code` = 'script_generate' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'dify.short_story_generate.chat_messages' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定 Dify 短篇小说生成接口' WHERE s.`scene_code` = 'short_story_generate' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.user.dairy.summary' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 日记总结工作流' WHERE s.`scene_code` = 'diary_summary' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.user.life.state' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 用户状态分析工作流' WHERE s.`scene_code` = 'emotion_analysis' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.summary.default' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 情绪总结工作流' WHERE s.`scene_code` = 'emotion_summary' AND s.`is_deleted` = 0; UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.user.dairy.summary' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 日记总结工作流,作为情绪总结兜底' WHERE s.`scene_code` = 'emotion_summary' AND s.`is_deleted` = 0 AND (s.`endpoint_id` IS NULL OR s.`endpoint_id` = '' OR s.`is_enabled` = 0); UPDATE `t_ai_scene_binding` s JOIN `t_ai_endpoint_config` e ON e.`endpoint_code` = 'coze.user.dairy.summary' AND e.`is_deleted` = 0 SET s.`endpoint_id` = e.`id`, s.`is_enabled` = 1, s.`required_stream` = 1, s.`description` = '已绑定现有 Coze 人生事件疗愈工作流' WHERE s.`scene_code` = 'life_healing' AND s.`is_deleted` = 0;