Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

60 rader
4.1 KiB

  1. import fs from 'node:fs';
  2. import assert from 'node:assert/strict';
  3. import { login, call } from './role-permissions-live.mjs';
  4. import manifest from '../../unreal_tran_web/src/features/virtual-training-scripts/narration-manifest.js';
  5. const dir = 'reports/bridge-digital-video-20260914';
  6. const generated = JSON.parse(fs.readFileSync(`${dir}/generation.json`, 'utf8'));
  7. const session = await login('root');
  8. const api = async (path, body, method) => {
  9. const r = await call(`tran/v1/${path}`, session.accessToken, body, method);
  10. assert.equal(r.status, 200, `${path}: ${r.message}`); return r.data;
  11. };
  12. const assignments = (await api('teaching/assignments?channel=VIRTUAL&assignmentKind=TRAINING&size=100')).records;
  13. const codes = process.argv.slice(2);
  14. for (const pack of manifest.scripts.filter(p => !codes.length || codes.includes(p.code))) {
  15. const clips = generated.clips.filter(c => c.code === pack.code);
  16. assert.equal(clips.length, pack.steps.length); assert.ok(clips.every(c => c.status === 'SUCCEEDED'));
  17. let task = assignments.find(t => t.code === pack.code);
  18. let detail = await api(`content/projects/${task.contentProjectId}`);
  19. const backup = `${dir}/${pack.code}-before.json`;
  20. if (!fs.existsSync(backup)) fs.writeFileSync(backup, JSON.stringify({ task, detail,
  21. runs: await api(`teaching/runs?assignmentId=${task.id}&size=100`) }, null, 2));
  22. const content = structuredClone(detail.currentVersion.content), assets = [...detail.currentVersion.assets];
  23. let changed = false;
  24. for (const step of content.steps) {
  25. const clip = clips.find(c => c.stepCode === (step.stepCode || step.id)); assert.ok(clip);
  26. const existing = assets.find(a => a.code === step.audio?.narrationVideoAssetCode && String(a.metadata?.sourceVideoId) === clip.videoId);
  27. if (existing) continue;
  28. const asset = await api(`content/projects/${task.contentProjectId}/digital-human/videos/${clip.videoId}/import`,
  29. { version: detail.project.version, name: clip.title, appId: clip.appId });
  30. assets.push(asset);
  31. step.audio = { ...step.audio, narrationSource: 'digital-generate', narrationText: clip.text,
  32. narrationUrl: '', narrationAssetCode: '', narrationVideoAssetCode: asset.code,
  33. digitalHuman: { enabled: true, mode: 'video', videoSource: 'library', videoId: clip.videoId,
  34. videoName: clip.title, appId: clip.appId, videoUrl: '', generatedVideoUrl: '', generationStatus: 'generated' } };
  35. changed = true;
  36. console.log('IMPORTED', pack.code, clip.number, asset.code);
  37. }
  38. if (changed) {
  39. detail = await api(`content/projects/${task.contentProjectId}`, { ...detail.project, content,
  40. dependencies: detail.currentVersion.dependencies, assets, changeSummary: '39段数字人视频讲解;原语音保留可切换' }, 'PUT');
  41. }
  42. if (detail.project.currentVersionStatus !== 'PUBLISHED') {
  43. await api(`content/projects/${task.contentProjectId}/publish`, { version: detail.project.version });
  44. detail = await api(`content/projects/${task.contentProjectId}`);
  45. }
  46. if (task.contentVersionId !== detail.project.publishedVersionId) {
  47. task = await api(`teaching/assignments/${task.id}/narration`, { version: task.version,
  48. contentVersionId: detail.project.publishedVersionId, reason: '补充逐步数字人讲解视频,保留原语音,训练操作和评分不变' }, 'PUT');
  49. }
  50. const original = JSON.parse(fs.readFileSync(backup, 'utf8'));
  51. const runs = await api(`teaching/runs?assignmentId=${task.id}&size=100`);
  52. const stableRuns = value => JSON.parse(JSON.stringify(value, (key, item) => key === 'serverNow' ? undefined : item));
  53. assert.deepEqual(stableRuns(runs), stableRuns(original.runs), 'Existing training runs must not change');
  54. const result = { code: pack.code, taskId: task.id, contentVersionId: task.contentVersionId,
  55. clips: task.definitionSnapshot.steps.map(s => ({ stepCode: s.stepCode, videoAssetCode: s.audio.narrationVideoAssetCode })),
  56. runsUnchanged: true, assets: await api(`teaching/assignments/${task.id}/assets`) };
  57. fs.writeFileSync(`${dir}/${pack.code}-binding.json`, JSON.stringify(result, null, 2));
  58. console.log('BOUND', pack.code, task.contentVersionId, result.clips.length);
  59. }