1|-- ============================================================ 2|-- KTV服务 uapi/uapiio 补全迁移脚本 3|-- 为14个GPU服务端点补全 stream/data/response/ioid 字段 4|-- 执行环境: Sage生产数据库 5|-- ============================================================ 6| 7|-- ============================================================ 8|-- 1. uapiio 输入字段定义 9|-- ============================================================ 10| 11|-- ASR语音识别 12|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 13| 'ktv_asr_transcribe_io', 'KTV语音识别', '上传音频文件,返回识别文本和时间戳', 14| '{"audio_url":{"type":"string","required":true,"description":"音频文件URL"},"language":{"type":"string","required":false,"default":"zh","description":"语言代码"}}' 15|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 16| 17|-- Demucs音频分离 18|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 19| 'ktv_demucs_separate_io', 'KTV音频分离', '分离人声和伴奏', 20| '{"audio_url":{"type":"string","required":true,"description":"音频文件URL"}}' 21|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 22| 23|-- 人脸检测 24|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 25| 'ktv_face_detect_io', 'KTV人脸检测', '检测图像中的人脸位置', 26| '{"image_url":{"type":"string","required":true,"description":"图像URL"}}' 27|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 28| 29|-- 人脸识别 30|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 31| 'ktv_face_recognize_io', 'KTV人脸识别', '识别人脸身份', 32| '{"image_url":{"type":"string","required":true,"description":"图像URL"},"face_id":{"type":"string","required":false,"description":"人脸ID"}}' 33|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 34| 35|-- 人脸比对 36|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 37| 'ktv_face_compare_io', 'KTV人脸比对', '比较两张人脸的相似度', 38| '{"image_url1":{"type":"string","required":true,"description":"图像1 URL"},"image_url2":{"type":"string","required":true,"description":"图像2 URL"}}' 39|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 40| 41|-- 字幕渲染 42|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 43| 'ktv_subtitle_render_io', 'KTV字幕渲染', '将歌词时间轴渲染为ASS字幕文件', 44| '{"lyrics_json":{"type":"string","required":true,"description":"歌词时间轴JSON [{\"text\":\"...\",\"start\":0,\"end\":3},...]"},"width":{"type":"integer","required":false,"default":1920,"description":"视频宽度"},"height":{"type":"integer","required":false,"default":1080,"description":"视频高度"}}' 45|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 46| 47|-- 视频合并 48|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 49| 'ktv_merge_video_io', 'KTV视频合并', '合并视频、音频和字幕', 50| '{"video_url":{"type":"string","required":false,"description":"视频URL"},"audio_url":{"type":"string","required":false,"description":"音频URL"},"subtitle_url":{"type":"string","required":false,"description":"字幕ASS文件URL"},"output_format":{"type":"string","required":false,"default":"mp4","description":"输出格式"}}' 51|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 52| 53|-- 歌曲评分 54|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 55| 'ktv_songrate_evaluate_io', 'KTV歌曲评分', 'AI评估歌曲质量', 56| '{"audio_url":{"type":"string","required":true,"description":"音频文件URL"},"scene":{"type":"string","required":false,"default":"pop","description":"场景类型(pop/folk/rock等)"}}' 57|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 58| 59|-- 音乐合成(异步提交) 60|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 61| 'ktv_synth_generate_io', 'KTV音乐合成', 'AI歌声合成(异步任务)', 62| '{"lyrics":{"type":"string","required":true,"description":"歌词文本"},"style":{"type":"string","required":false,"default":"pop","description":"演唱风格"},"reference_audio":{"type":"string","required":false,"description":"参考音频URL(声音克隆)"}}' 63|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 64| 65|-- 合成状态查询 66|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 67| 'ktv_synth_status_io', 'KTV合成状态', '查询音乐合成任务状态', 68| '{"task_id":{"type":"string","required":true,"description":"任务ID"}}' 69|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 70| 71|-- 超分辨率(异步提交) 72|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 73| 'ktv_realesrgan_upscale_io', 'KTV超分辨率', '图像/视频超分辨率(异步任务)', 74| '{"image_url":{"type":"string","required":true,"description":"图像URL"},"scale":{"type":"integer","required":false,"default":2,"description":"放大倍数"}}' 75|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 76| 77|-- 超分状态查询 78|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 79| 'ktv_realesrgan_status_io', 'KTV超分状态', '查询超分任务状态', 80| '{"task_id":{"type":"string","required":true,"description":"任务ID"}}' 81|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 82| 83|-- RVC声音转换(异步) 84|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 85| 'ktv_rvc_convert_io', 'KTV声音转换', '声音克隆/变声(异步任务)', 86| '{"audio_url":{"type":"string","required":true,"description":"输入音频URL"},"voice_model":{"type":"string","required":true,"description":"目标声音模型名"}}' 87|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 88| 89|-- 视频评估 90|INSERT INTO uapiio (id, name, description, input_fields) VALUES ( 91| 'ktv_video_eval_evaluate_io', 'KTV视频评估', '评估视频质量', 92| '{"video_url":{"type":"string","required":true,"description":"视频URL"}}' 93|) ON DUPLICATE KEY UPDATE description=VALUES(description), input_fields=VALUES(input_fields); 94| -- ============================================================ -- Part 2: uapi 字段补全 + async 模型 query_apiname 更新 -- ============================================================ 1|-- ============================================================ 2|-- KTV服务 uapi 补全迁移脚本 Part 2 3|-- 更新14条uapi记录:stream/data/response/ioid/headers 4|-- ============================================================ 5| 6|-- ============================================================ 7|-- 1. ASR语音识别 (sync) 8|-- GPU: /asr/api/asr-transcribe → localhost:9925 9|-- uapiio: ktv_asr_transcribe_io 10|-- ============================================================ 11|UPDATE uapi SET 12| stream = 'sync', 13| headers = '{"Content-Type": "application/json"}', 14| data = '{ 15| "audio_url": "{{audio_url}}" 16|{% if language %} 17| ,"language": "{{language}}" 18|{% endif %} 19|}', 20| response = '{ 21| "status": "{{status}}", 22| "text": "{{text}}", 23| "segments": {{json.dumps(segments, ensure_ascii=False)}}, 24| "usage": {"audio_seconds": {{audio_seconds|float}}} 25|}', 26| ioid = 'ktv_asr_transcribe_io' 27|WHERE id = 'uapi_ktv_asr_transcribe'; 28| 29|-- ============================================================ 30|-- 2. Demucs音频分离 (sync) 31|-- GPU: /demucs/api/demucs-separate → localhost:9083 32|-- ============================================================ 33|UPDATE uapi SET 34| stream = 'sync', 35| headers = '{"Content-Type": "application/json"}', 36| data = '{ 37| "audio_url": "{{audio_url}}" 38|}', 39| response = '{ 40| "status": "{{status}}", 41| "vocals_url": "{{vocals_url}}", 42| "accompaniment_url": "{{accompaniment_url}}", 43| "usage": {"audio_seconds": {{audio_seconds|float}}} 44|}', 45| ioid = 'ktv_demucs_separate_io' 46|WHERE id = 'uapi_ktv_demucs_separate'; 47| 48|-- ============================================================ 49|-- 3. 人脸检测 (sync) 50|-- GPU: /face/api/face-detect → localhost:9091 51|-- ============================================================ 52|UPDATE uapi SET 53| stream = 'sync', 54| headers = '{"Content-Type": "application/json"}', 55| data = '{ 56| "image_url": "{{image_url}}" 57|}', 58| response = '{ 59| "status": "{{status}}", 60| "faces": {{json.dumps(faces, ensure_ascii=False)}}, 61| "usage": {"detect_count": {{faces|length}}} 62|}', 63| ioid = 'ktv_face_detect_io' 64|WHERE id = 'uapi_ktv_face_detect'; 65| 66|-- ============================================================ 67|-- 4. 人脸识别 (sync) 68|-- ============================================================ 69|UPDATE uapi SET 70| stream = 'sync', 71| headers = '{"Content-Type": "application/json"}', 72| data = '{ 73| "image_url": "{{image_url}}" 74|{% if face_id %} 75| ,"face_id": "{{face_id}}" 76|{% endif %} 77|}', 78| response = '{ 79| "status": "{{status}}", 80| "matches": {{json.dumps(matches, ensure_ascii=False)}}, 81| "usage": {"recognize_count": {{matches|length}}} 82|}', 83| ioid = 'ktv_face_recognize_io' 84|WHERE id = 'uapi_ktv_face_recognize'; 85| 86|-- ============================================================ 87|-- 5. 人脸比对 (sync) 88|-- ============================================================ 89|UPDATE uapi SET 90| stream = 'sync', 91| headers = '{"Content-Type": "application/json"}', 92| data = '{ 93| "image_url1": "{{image_url1}}", 94| "image_url2": "{{image_url2}}" 95|}', 96| response = '{ 97| "status": "{{status}}", 98| "similarity": {{similarity|float}}, 99| "usage": {"compare_count": 1} 100|}', 101| ioid = 'ktv_face_compare_io' 102|WHERE id = 'uapi_ktv_face_compare'; 103| 104|-- ============================================================ 105|-- 6. 字幕渲染 (sync) 106|-- GPU: /subtitle/api/subtitle-render → localhost:9080 107|-- ============================================================ 108|UPDATE uapi SET 109| stream = 'sync', 110| headers = '{"Content-Type": "application/json"}', 111| data = '{ 112| "lyrics_json": {{lyrics_json}} 113|{% if width %} 114| ,"width": {{width}} 115|{% endif %} 116|{% if height %} 117| ,"height": {{height}} 118|{% endif %} 119|}', 120| response = '{ 121| "status": "{{status}}", 122| "ass_url": "{{ass_url}}", 123| "usage": {"subtitle_count": {{segments|length}}} 124|}', 125| ioid = 'ktv_subtitle_render_io' 126|WHERE id = 'uapi_ktv_subtitle_render'; 127| 128|-- ============================================================ 129|-- 7. 视频合并 (sync) 130|-- GPU: /merge/api/merge-video → localhost:9080 131|-- ============================================================ 132|UPDATE uapi SET 133| stream = 'sync', 134| headers = '{"Content-Type": "application/json"}', 135| data = '{ 136|{% if video_url %} 137| "video_url": "{{video_url}}" 138|{% endif %} 139|{% if audio_url %} 140| ,"audio_url": "{{audio_url}}" 141|{% endif %} 142|{% if subtitle_url %} 143| ,"subtitle_url": "{{subtitle_url}}" 144|{% endif %} 145|{% if output_format %} 146| ,"output_format": "{{output_format}}" 147|{% endif %} 148|}', 149| response = '{ 150| "status": "{{status}}", 151| "output_url": "{{output_url}}", 152| "duration": {{duration|float}}, 153| "usage": {"output_seconds": {{duration|float}}} 154|}', 155| ioid = 'ktv_merge_video_io' 156|WHERE id = 'uapi_ktv_merge_video'; 157| 158|-- ============================================================ 159|-- 8. 歌曲评分 (sync) 160|-- GPU: /songrate/api/songrate-evaluate → localhost:8901 161|-- ============================================================ 162|UPDATE uapi SET 163| stream = 'sync', 164| headers = '{"Content-Type": "application/json"}', 165| data = '{ 166| "audio_url": "{{audio_url}}" 167|{% if scene %} 168| ,"scene": "{{scene}}" 169|{% endif %} 170|}', 171| response = '{ 172| "status": "{{status}}", 173| "score": {{score|float}}, 174| "details": {{json.dumps(details, ensure_ascii=False)}}, 175| "usage": {"audio_seconds": {{audio_seconds|float}}} 176|}', 177| ioid = 'ktv_songrate_evaluate_io' 178|WHERE id = 'uapi_ktv_songrate_evaluate'; 179| 180|-- ============================================================ 181|-- 9. 音乐合成 (async - 提交任务) 182|-- GPU: /synth/api/synth-generate → localhost:9084 183|-- ============================================================ 184|UPDATE uapi SET 185| stream = 'async', 186| headers = '{"Content-Type": "application/json"}', 187| data = '{ 188| "lyrics": "{{lyrics}}" 189|{% if style %} 190| ,"style": "{{style}}" 191|{% endif %} 192|{% if reference_audio %} 193| ,"reference_audio": "{{reference_audio}}" 194|{% endif %} 195|}', 196| response = '{ 197| "taskid": "{{task_id}}", 198| "taskstatus": "PENDING" 199|}', 200| ioid = 'ktv_synth_generate_io' 201|WHERE id = 'uapi_ktv_synth_generate'; 202| 203|-- ============================================================ 204|-- 10. 合成状态查询 (sync) 205|-- GPU: /synth/api/synth-status → localhost:9084 206|-- ============================================================ 207|UPDATE uapi SET 208| stream = 'sync', 209| headers = '{"Content-Type": "application/json"}', 210| data = '{"task_id": "{{task_id}}"}', 211| response = '{ 212|{% if status == "SUCCEEDED" %} 213| "taskstatus": "SUCCEEDED", 214| "output_url": "{{output_url}}", 215| "usage": {"audio_seconds": {{duration|float}}} 216|{% elif status == "FAILED" %} 217| "taskstatus": "FAILED", 218| "error": "{{error}}" 219|{% else %} 220| "taskstatus": "PENDING" 221|{% endif %} 222|}', 223| ioid = 'ktv_synth_status_io' 224|WHERE id = 'uapi_ktv_synth_status'; 225| 226|-- ============================================================ 227|-- 11. 超分辨率 (async - 提交任务) 228|-- GPU: /realesrgan/api/realesrgan-upscale → localhost:9082 229|-- ============================================================ 230|UPDATE uapi SET 231| stream = 'async', 232| headers = '{"Content-Type": "application/json"}', 233| data = '{ 234| "image_url": "{{image_url}}" 235|{% if scale %} 236| ,"scale": {{scale}} 237|{% endif %} 238|}', 239| response = '{ 240| "taskid": "{{task_id}}", 241| "taskstatus": "PENDING" 242|}', 243| ioid = 'ktv_realesrgan_upscale_io' 244|WHERE id = 'uapi_ktv_realesrgan_upscale'; 245| 246|-- ============================================================ 247|-- 12. 超分状态查询 (sync) 248|-- GPU: /realesrgan/api/realesrgan-status → localhost:9082 249|-- ============================================================ 250|UPDATE uapi SET 251| stream = 'sync', 252| headers = '{"Content-Type": "application/json"}', 253| data = '{"task_id": "{{task_id}}"}', 254| response = '{ 255|{% if status == "SUCCEEDED" %} 256| "taskstatus": "SUCCEEDED", 257| "output_url": "{{output_url}}", 258| "usage": {"image_count": 1} 259|{% elif status == "FAILED" %} 260| "taskstatus": "FAILED", 261| "error": "{{error}}" 262|{% else %} 263| "taskstatus": "PENDING" 264|{% endif %} 265|}', 266| ioid = 'ktv_realesrgan_status_io' 267|WHERE id = 'uapi_ktv_realesrgan_status'; 268| 269|-- ============================================================ 270|-- 13. RVC声音转换 (sync) 271|-- GPU: /rvc/api/rvc-convert → localhost:9085 272|-- ============================================================ 273|UPDATE uapi SET 274| stream = 'sync', 275| headers = '{"Content-Type": "application/json"}', 276| data = '{ 277| "audio_url": "{{audio_url}}", 278| "voice_model": "{{voice_model}}" 279|}', 280| response = '{ 281| "status": "{{status}}", 282| "output_url": "{{output_url}}", 283| "usage": {"audio_seconds": {{audio_seconds|float}}} 284|}', 285| ioid = 'ktv_rvc_convert_io' 286|WHERE id = 'uapi_ktv_rvc_convert'; 287| 288|-- ============================================================ 289|-- 14. 视频评估 (sync) 290|-- GPU: /video-eval/api/video-eval-evaluate → localhost:8902 291|-- ============================================================ 292|UPDATE uapi SET 293| stream = 'sync', 294| headers = '{"Content-Type": "application/json"}', 295| data = '{ 296| "video_url": "{{video_url}}" 297|}', 298| response = '{ 299| "status": "{{status}}", 300| "score": {{score|float}}, 301| "details": {{json.dumps(details, ensure_ascii=False)}}, 302| "usage": {"video_seconds": {{video_seconds|float}}} 303|}', 304| ioid = 'ktv_video_eval_evaluate_io' 305|WHERE id = 'uapi_ktv_video_eval_evaluate'; 306| 307|-- ============================================================ 308|-- 关键:更新 llm_api_map 中的 async 模型的 query_apiname 309|-- synth-generate 查询 synth-status 310|-- realesrgan-upscale 查询 realesrgan-status 311|-- ============================================================ 312|UPDATE llm_api_map SET query_apiname = 'synth-status', query_period = 5 313|WHERE llmid = 'llm_ktv_synth_generate' AND llmcatelogid = 'ktv_pipeline'; 314| 315|UPDATE llm_api_map SET query_apiname = 'realesrgan-status', query_period = 3 316|WHERE llmid = 'llm_ktv_realesrgan_upscale' AND llmcatelogid = 'ktv_pipeline'; 317| -- ============================================================ -- Part 3: RBAC 权限 -- ============================================================ 1|-- ============================================================ 2|-- KTV Pipeline v1 API RBAC 权限配置 3|-- 新增 /v1/pipeline/submit 端点权限 4|-- ============================================================ 5| 6|-- 权限路径(供 load_path.py 或不直接支持的模块参考) 7|-- 目录级 8|-- /llmage/v1/pipeline logined 9|-- /llmage/v1/pipeline/submit logined 10|-- 文件级 11|-- /llmage/v1/pipeline/submit/index.dspy logined 12| 13|-- ============================================================ 14|-- Customer 角色权限(API调用者需要) 15|-- ============================================================ 16|INSERT INTO permission (id, path, name) 17|SELECT REPLACE(UUID(), '-', ''), '/llmage/v1/pipeline/submit/index.dspy', 'KTV流水线提交' 18|WHERE NOT EXISTS ( 19| SELECT 1 FROM permission WHERE path = '/llmage/v1/pipeline/submit/index.dspy' 20|); 21| 22|-- 为 customer.admin 和 customer.user 角色授予权限 23|-- 注意:以下语句依赖 set_role_perm.py 或等效的角色-权限关联表 24|-- 如果用的是直接 role_permission 表: 25|INSERT IGNORE INTO role_permission (role_id, permission_id) 26|SELECT r.id, p.id 27|FROM role r, permission p 28|WHERE r.name IN ('customer.admin', 'customer.user') 29|AND p.path = '/llmage/v1/pipeline/submit/index.dspy'; 30| 31|-- ============================================================ 32|-- 管理角色权限 33|-- ============================================================ 34|INSERT IGNORE INTO role_permission (role_id, permission_id) 35|SELECT r.id, p.id 36|FROM role r, permission p 37|WHERE r.name IN ('owner.superuser', 'owner.admin', 'reseller.admin', 'reseller.operator') 38|AND p.path = '/llmage/v1/pipeline/submit/index.dspy'; 39|