-- ============================================================
-- KTV服务 uapi/uapiio 补全迁移 Part 1
-- 输入字段使用 _file 命名规范（与 Sage image/video/audio 统一）
-- ============================================================

-- ASR语音识别
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_asr_transcribe_io', 'KTV语音识别', '上传音频文件，返回识别文本和时间戳',
  '{"audio_file":{"type":"string","required":true,"description":"音频文件URL"},"language":{"type":"string","required":false,"default":"zh","description":"语言代码"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- Demucs音频分离
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_demucs_separate_io', 'KTV音频分离', '分离人声和伴奏',
  '{"audio_file":{"type":"string","required":true,"description":"音频文件URL"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 人脸检测
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_face_detect_io', 'KTV人脸检测', '检测图像中的人脸位置',
  '{"image_file":{"type":"string","required":true,"description":"图像URL"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 人脸识别
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_face_recognize_io', 'KTV人脸识别', '识别人脸身份',
  '{"image_file":{"type":"string","required":true,"description":"图像URL"},"face_id":{"type":"string","required":false,"description":"人脸ID"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 人脸比对
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_face_compare_io', 'KTV人脸比对', '比较两张人脸的相似度',
  '{"image_file1":{"type":"string","required":true,"description":"图像1 URL"},"image_file2":{"type":"string","required":true,"description":"图像2 URL"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 字幕渲染
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_subtitle_render_io', 'KTV字幕渲染', '将歌词时间轴渲染为ASS字幕文件',
  '{"lyrics_json":{"type":"string","required":true,"description":"歌词时间轴JSON"},"width":{"type":"integer","required":false,"default":1920,"description":"视频宽度"},"height":{"type":"integer","required":false,"default":1080,"description":"视频高度"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 视频合并
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_merge_video_io', 'KTV视频合并', '合并视频、音频和字幕',
  '{"video_file":{"type":"string","required":false,"description":"视频URL"},"audio_file":{"type":"string","required":false,"description":"音频URL"},"subtitle_file":{"type":"string","required":false,"description":"ASS字幕URL"},"output_format":{"type":"string","required":false,"default":"mp4","description":"输出格式"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 歌曲评分
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_songrate_evaluate_io', 'KTV歌曲评分', 'AI评估歌曲质量',
  '{"audio_file":{"type":"string","required":true,"description":"音频文件URL"},"scene":{"type":"string","required":false,"default":"pop","description":"场景类型"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 音乐合成（异步）
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_synth_generate_io', 'KTV音乐合成', 'AI歌声合成（异步任务）',
  '{"lyrics":{"type":"string","required":true,"description":"歌词文本"},"style":{"type":"string","required":false,"default":"pop","description":"演唱风格"},"audio_file":{"type":"string","required":false,"description":"参考音频URL（声音克隆）"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 合成状态查询
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_synth_status_io', 'KTV合成状态', '查询音乐合成任务状态',
  '{"task_id":{"type":"string","required":true,"description":"任务ID"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 超分辨率（异步）
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_realesrgan_upscale_io', 'KTV超分辨率', '图像/视频超分辨率（异步任务）',
  '{"image_file":{"type":"string","required":true,"description":"图像URL"},"scale":{"type":"integer","required":false,"default":2,"description":"放大倍数"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 超分状态查询
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_realesrgan_status_io', 'KTV超分状态', '查询超分任务状态',
  '{"task_id":{"type":"string","required":true,"description":"任务ID"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- RVC声音转换
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_rvc_convert_io', 'KTV声音转换', '声音克隆/变声',
  '{"audio_file":{"type":"string","required":true,"description":"输入音频URL"},"voice_model":{"type":"string","required":true,"description":"目标声音模型名"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);

-- 视频评估
INSERT INTO uapiio (id, name, description, input_fields) VALUES (
  'ktv_video_eval_evaluate_io', 'KTV视频评估', '评估视频质量',
  '{"video_file":{"type":"string","required":true,"description":"视频URL"}}'
) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields);
-- ============================================================
-- KTV服务 uapi 补全 Part 2
-- data模板使用 _file命名（audio_file/image_file/video_file）
-- response透传GPU返回的usage
-- ============================================================

-- 1. ASR语音识别 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"audio_file":"{{audio_file}}"{% if language %},"language":"{{language}}"{% endif %}}',
  response='{"status":"{{status}}","text":"{{text}}","segments":{{json.dumps(segments,ensure_ascii=False)}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_asr_transcribe_io'
WHERE id='uapi_ktv_asr_transcribe';

-- 2. Demucs音频分离 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"audio_file":"{{audio_file}}"}',
  response='{"status":"{{status}}","vocals_url":"{{vocals_url}}","accompaniment_url":"{{accompaniment_url}}","usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_demucs_separate_io'
WHERE id='uapi_ktv_demucs_separate';

-- 3. 人脸检测 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"image_file":"{{image_file}}"}',
  response='{"status":"{{status}}","faces":{{json.dumps(faces,ensure_ascii=False)}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_face_detect_io'
WHERE id='uapi_ktv_face_detect';

-- 4. 人脸识别 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"image_file":"{{image_file}}"{% if face_id %},"face_id":"{{face_id}}"{% endif %}}',
  response='{"status":"{{status}}","matches":{{json.dumps(matches,ensure_ascii=False)}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_face_recognize_io'
WHERE id='uapi_ktv_face_recognize';

-- 5. 人脸比对 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"image_file1":"{{image_file1}}","image_file2":"{{image_file2}}"}',
  response='{"status":"{{status}}","similarity":{{similarity}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_face_compare_io'
WHERE id='uapi_ktv_face_compare';

-- 6. 字幕渲染 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"lyrics_json":{{lyrics_json}}{% if width %},"width":{{width}}{% endif %}{% if height %},"height":{{height}}{% endif %}}',
  response='{"status":"{{status}}","ass_url":"{{ass_url}}","usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_subtitle_render_io'
WHERE id='uapi_ktv_subtitle_render';

-- 7. 视频合并 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{%set c=joiner(",")%}{{%if video_file%}{{c()}}"video_file":"{{video_file}}"{%endif%}{%if audio_file%}{{c()}}"audio_file":"{{audio_file}}"{%endif%}{%if subtitle_file%}{{c()}}"subtitle_file":"{{subtitle_file}}"{%endif%}{%if output_format%}{{c()}}"output_format":"{{output_format}}"{%endif%}}',
  response='{"status":"{{status}}","output_url":"{{output_url}}","duration":{{duration}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_merge_video_io'
WHERE id='uapi_ktv_merge_video';

-- 8. 歌曲评分 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"audio_file":"{{audio_file}}"{% if scene %},"scene":"{{scene}}"{% endif %}}',
  response='{"status":"{{status}}","score":{{score}},"details":{{json.dumps(details,ensure_ascii=False)}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_songrate_evaluate_io'
WHERE id='uapi_ktv_songrate_evaluate';

-- 9. 音乐合成 (async提交)
UPDATE uapi SET stream='async',headers='{"Content-Type":"application/json"}',
  data='{"lyrics":"{{lyrics}}"{% if style %},"style":"{{style}}"{% endif %}{% if audio_file %},"audio_file":"{{audio_file}}"{% endif %}}',
  response='{"taskid":"{{task_id}}","taskstatus":"PENDING"}',
  ioid='ktv_synth_generate_io'
WHERE id='uapi_ktv_synth_generate';

-- 10. 合成状态查询 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"task_id":"{{task_id}}"}',
  response='{%if status=="SUCCEEDED"%}{"taskstatus":"SUCCEEDED","output_url":"{{output_url}}","usage":{{json.dumps(usage,ensure_ascii=False)}}}{%elif status=="FAILED"%}{"taskstatus":"FAILED","error":"{{error}}"}{%else%}{"taskstatus":"PENDING"}{%endif%}',
  ioid='ktv_synth_status_io'
WHERE id='uapi_ktv_synth_status';

-- 11. 超分辨率 (async提交)
UPDATE uapi SET stream='async',headers='{"Content-Type":"application/json"}',
  data='{"image_file":"{{image_file}}"{% if scale %},"scale":{{scale}}{% endif %}}',
  response='{"taskid":"{{task_id}}","taskstatus":"PENDING"}',
  ioid='ktv_realesrgan_upscale_io'
WHERE id='uapi_ktv_realesrgan_upscale';

-- 12. 超分状态查询 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"task_id":"{{task_id}}"}',
  response='{%if status=="SUCCEEDED"%}{"taskstatus":"SUCCEEDED","output_url":"{{output_url}}","usage":{{json.dumps(usage,ensure_ascii=False)}}}{%elif status=="FAILED"%}{"taskstatus":"FAILED","error":"{{error}}"}{%else%}{"taskstatus":"PENDING"}{%endif%}',
  ioid='ktv_realesrgan_status_io'
WHERE id='uapi_ktv_realesrgan_status';

-- 13. RVC声音转换 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"audio_file":"{{audio_file}}","voice_model":"{{voice_model}}"}',
  response='{"status":"{{status}}","output_url":"{{output_url}}","usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_rvc_convert_io'
WHERE id='uapi_ktv_rvc_convert';

-- 14. 视频评估 (sync)
UPDATE uapi SET stream='sync',headers='{"Content-Type":"application/json"}',
  data='{"video_file":"{{video_file}}"}',
  response='{"status":"{{status}}","score":{{score}},"details":{{json.dumps(details,ensure_ascii=False)}},"usage":{{json.dumps(usage,ensure_ascii=False)}}}',
  ioid='ktv_video_eval_evaluate_io'
WHERE id='uapi_ktv_video_eval_evaluate';

-- async query_apiname
UPDATE llm_api_map SET query_apiname='synth-status',query_period=5
WHERE llmid='llm_ktv_synth_generate' AND llmcatelogid='ktv_pipeline';
UPDATE llm_api_map SET query_apiname='realesrgan-status',query_period=3
WHERE llmid='llm_ktv_realesrgan_upscale' AND llmcatelogid='ktv_pipeline';

-- ============================================================
-- P2 补充: 设置 ppid（v1/models 查询要求 ppid IS NOT NULL）
-- ============================================================
UPDATE llm_api_map SET ppid = 'pp_ktv' WHERE llmid LIKE 'llm_ktv%' AND ppid IS NULL;

-- ============================================================
-- P2 补充: upappkey (API调用鉴权必需)
-- ============================================================
INSERT INTO upappkey (id, upappid, ownerid, apikey, orgid)
SELECT 'ktv_gateway_key', 'ktv-gateway', 'UiEi7hKqAmU1-jqQEVhZe', '', '0'
WHERE NOT EXISTS (SELECT 1 FROM upappkey WHERE upappid = 'ktv-gateway');

-- ============================================================
-- P2 补充: response模板容错 — {% if error %} 处理GPU错误响应
-- 所有同步服务的response模板使用{% if error %}块，GPU返回
-- {"error":"..."}时直接透传，避免Jinja2 UndefinedError
-- （tokentest已手动更新，此处为生产部署用SQL）
-- ============================================================
-- ============================================================
-- KTV Pipeline v1 API RBAC 权限配置
-- 新增 /v1/pipeline/submit 端点权限
-- ============================================================

-- 权限路径（供 load_path.py 或不直接支持的模块参考）
-- 目录级
-- /llmage/v1/pipeline logined
-- /llmage/v1/pipeline/submit logined
-- 文件级
-- /llmage/v1/pipeline/submit/index.dspy logined

-- ============================================================
-- Customer 角色权限（API调用者需要）
-- ============================================================
INSERT INTO permission (id, path, name)
SELECT REPLACE(UUID(), '-', ''), '/llmage/v1/pipeline/submit/index.dspy', 'KTV流水线提交'
WHERE NOT EXISTS (
    SELECT 1 FROM permission WHERE path = '/llmage/v1/pipeline/submit/index.dspy'
);

-- 为 customer.admin 和 customer.user 角色授予权限
-- 注意：以下语句依赖 set_role_perm.py 或等效的角色-权限关联表
-- 如果用的是直接 role_permission 表：
INSERT IGNORE INTO role_permission (role_id, permission_id)
SELECT r.id, p.id
FROM role r, permission p
WHERE r.name IN ('customer.admin', 'customer.user')
AND p.path = '/llmage/v1/pipeline/submit/index.dspy';

-- ============================================================
-- 管理角色权限
-- ============================================================
INSERT IGNORE INTO role_permission (role_id, permission_id)
SELECT r.id, p.id
FROM role r, permission p
WHERE r.name IN ('owner.superuser', 'owner.admin', 'reseller.admin', 'reseller.operator')
AND p.path = '/llmage/v1/pipeline/submit/index.dspy';
