235 lines
9.8 KiB
HTML
235 lines
9.8 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>短剧/漫剧创作</title>
|
||
<link rel="stylesheet" href="css/style.css">
|
||
</head>
|
||
<body>
|
||
<div class="header">
|
||
<h1>短剧/漫剧创作</h1>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<!-- 阶段指示器 -->
|
||
<div class="stages" id="stages">
|
||
<div class="stage active" data-stage="script_analysis">1.剧本解析</div>
|
||
<div class="stage" data-stage="narration_design">2.旁白改编</div>
|
||
<div class="stage" data-stage="character_generate">3.角色生成</div>
|
||
<div class="stage" data-stage="scene_generate">4.场景生成</div>
|
||
<div class="stage" data-stage="storyboard_design">5.分镜设计</div>
|
||
<div class="stage" data-stage="shot_video_generate">6.分镜短片</div>
|
||
<div class="stage" data-stage="shot_video_compose">7.成片合成</div>
|
||
</div>
|
||
|
||
<!-- 阶段1: 剧本解析 -->
|
||
<div class="card" id="stage-script_analysis">
|
||
<div class="card-title">剧本解析</div>
|
||
<div class="form-group">
|
||
<label class="form-label">视觉风格 *</label>
|
||
<input type="text" class="form-input" id="visual_style" placeholder="如: 2D,国风,平涂 或 3D,CG动画,写实都市">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">视频比例 *</label>
|
||
<select class="form-select" id="video_ratio">
|
||
<option value="16:9">16:9 横屏</option>
|
||
<option value="9:16">9:16 竖屏</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">剧本文件URL *</label>
|
||
<input type="text" class="form-input" id="file_url" placeholder="公网可访问的剧本文件链接">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">文件类型 *</label>
|
||
<select class="form-select" id="file_type">
|
||
<option value="txt">TXT</option>
|
||
<option value="docx">DOCX</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">文件名 *</label>
|
||
<input type="text" class="form-input" id="file_name" placeholder="剧本文件名">
|
||
</div>
|
||
<button class="btn btn-primary btn-block" onclick="submitScriptAnalysis()">提交剧本解析</button>
|
||
<div id="result-script_analysis"></div>
|
||
</div>
|
||
|
||
<!-- 后续阶段表单(需要thread_id和asset_id) -->
|
||
<div class="card" id="stage-later" style="display:none">
|
||
<div class="card-title" id="later-stage-title">下一阶段</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Thread ID</label>
|
||
<input type="text" class="form-input" id="thread_id" readonly>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Asset ID</label>
|
||
<input type="text" class="form-input" id="asset_id" readonly>
|
||
</div>
|
||
<div id="extra-fields"></div>
|
||
<button class="btn btn-primary btn-block" id="submit-later-btn" onclick="submitLaterStage()">提交</button>
|
||
<div id="result-later"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav">
|
||
<a href="index.html" class="nav-item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||
首页
|
||
</a>
|
||
<a href="novel.html" class="nav-item active">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
|
||
短剧
|
||
</a>
|
||
<a href="video.html" class="nav-item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
|
||
视频
|
||
</a>
|
||
<a href="tasks.html" class="nav-item">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
|
||
任务
|
||
</a>
|
||
</nav>
|
||
|
||
<script src="js/app.js"></script>
|
||
<script>
|
||
let currentThreadID = '';
|
||
let currentAssetID = '';
|
||
let currentStage = 'script_analysis';
|
||
|
||
// 阶段顺序
|
||
const stageOrder = [
|
||
'script_analysis', 'narration_design', 'character_generate',
|
||
'scene_generate', 'storyboard_design', 'shot_video_generate', 'shot_video_compose'
|
||
];
|
||
|
||
function updateStages(completed) {
|
||
document.querySelectorAll('.stage').forEach(el => {
|
||
const s = el.dataset.stage;
|
||
const idx = stageOrder.indexOf(s);
|
||
const compIdx = stageOrder.indexOf(completed);
|
||
if (idx < compIdx) el.className = 'stage completed';
|
||
else if (s === completed) el.className = 'stage active';
|
||
else el.className = 'stage';
|
||
});
|
||
}
|
||
|
||
async function submitScriptAnalysis() {
|
||
const input = {
|
||
action_key: 'script_analysis',
|
||
visual_style: document.getElementById('visual_style').value,
|
||
video_ratio: document.getElementById('video_ratio').value,
|
||
file_url: document.getElementById('file_url').value,
|
||
file_type: document.getElementById('file_type').value,
|
||
file_name: document.getElementById('file_name').value
|
||
};
|
||
try {
|
||
const result = await API.post('/api/novel/submit', input);
|
||
if (result.data) {
|
||
currentThreadID = result.data.thread_id || '';
|
||
showAlert('剧本解析任务已提交!', 'success');
|
||
// 开始轮询
|
||
const taskID = result.data.task_id || '';
|
||
const runID = result.data.run_id || '';
|
||
pollTask(taskID || runID,
|
||
(id) => API.post('/api/novel/query', {task_id: taskID, run_id: runID}),
|
||
(res) => {
|
||
const status = res.data?.status;
|
||
if (status === 'SUCCESS') {
|
||
const novelData = res.data.novel_data;
|
||
if (novelData) {
|
||
currentThreadID = novelData.thread_id || currentThreadID;
|
||
try {
|
||
const respData = JSON.parse(novelData.resp_data || '{}');
|
||
currentAssetID = respData.OverviewAssetID || '';
|
||
} catch(e) {}
|
||
}
|
||
document.getElementById('thread_id').value = currentThreadID;
|
||
document.getElementById('asset_id').value = currentAssetID;
|
||
updateStages('script_analysis');
|
||
showNextStage('narration_design');
|
||
showAlert('剧本解析完成!可以继续下一阶段', 'success');
|
||
}
|
||
}
|
||
);
|
||
}
|
||
} catch(err) {
|
||
showAlert('提交失败: ' + err.message, 'error');
|
||
}
|
||
}
|
||
|
||
function showNextStage(stage) {
|
||
currentStage = stage;
|
||
const stageNames = {
|
||
'narration_design': '旁白改编',
|
||
'character_generate': '角色生成',
|
||
'scene_generate': '场景生成',
|
||
'storyboard_design': '分镜设计',
|
||
'shot_video_generate': '分镜短片生成',
|
||
'shot_video_compose': '成片合成'
|
||
};
|
||
document.getElementById('later-stage-title').textContent = stageNames[stage] || stage;
|
||
document.getElementById('stage-later').style.display = 'block';
|
||
|
||
// 分镜短片需要额外的shot_ids
|
||
let extra = '';
|
||
if (stage === 'shot_video_generate' || stage === 'shot_video_compose') {
|
||
extra = `<div class="form-group">
|
||
<label class="form-label">分镜ID列表(逗号分隔)</label>
|
||
<input type="text" class="form-input" id="shot_ids" placeholder="S1,S2,S3">
|
||
</div>`;
|
||
}
|
||
document.getElementById('extra-fields').innerHTML = extra;
|
||
updateStages(stage);
|
||
}
|
||
|
||
async function submitLaterStage() {
|
||
const input = {
|
||
action_key: currentStage,
|
||
thread_id: document.getElementById('thread_id').value,
|
||
asset_id: document.getElementById('asset_id').value
|
||
};
|
||
// 分镜阶段需要shot_ids
|
||
if (currentStage === 'shot_video_generate' || currentStage === 'shot_video_compose') {
|
||
const shotIds = document.getElementById('shot_ids')?.value;
|
||
if (shotIds) input.shot_ids = shotIds.split(',').map(s => s.trim());
|
||
}
|
||
try {
|
||
const result = await API.post('/api/novel/submit', input);
|
||
if (result.data) {
|
||
showAlert(getActionName(currentStage) + ' 任务已提交!', 'success');
|
||
const nTaskID = result.data.task_id || '';
|
||
const nRunID = result.data.run_id || '';
|
||
pollTask(nTaskID || nRunID,
|
||
(id) => API.post('/api/novel/query', {task_id: nTaskID, run_id: nRunID}),
|
||
(res) => {
|
||
const status = res.data?.status;
|
||
if (status === 'SUCCESS') {
|
||
const novelData = res.data.novel_data;
|
||
if (novelData) {
|
||
try {
|
||
const respData = JSON.parse(novelData.resp_data || '{}');
|
||
if (respData.OverviewAssetID) currentAssetID = respData.OverviewAssetID;
|
||
if (respData.StoryboardAssetID) currentAssetID = respData.StoryboardAssetID;
|
||
} catch(e) {}
|
||
document.getElementById('asset_id').value = currentAssetID;
|
||
}
|
||
updateStages(currentStage);
|
||
const idx = stageOrder.indexOf(currentStage);
|
||
if (idx < stageOrder.length - 1) {
|
||
showNextStage(stageOrder[idx + 1]);
|
||
}
|
||
showAlert(getActionName(currentStage) + ' 完成!', 'success');
|
||
}
|
||
}
|
||
);
|
||
}
|
||
} catch(err) {
|
||
showAlert('提交失败: ' + err.message, 'error');
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|