Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

44 Zeilen
3.4 KiB

  1. import fs from 'node:fs';
  2. import path from 'node:path';
  3. import assert from 'node:assert/strict';
  4. import crypto from 'node:crypto';
  5. const web=path.resolve('../unreal_tran_web'),dir=path.resolve('reports/bridge-narration-junhao-20260921');
  6. const source=path.join(web,'src/features/virtual-training-scripts');
  7. const audio=JSON.parse(fs.readFileSync(path.join(dir,'audio-manifest.json'),'utf8'));
  8. const video=JSON.parse(fs.readFileSync(path.join(dir,'video-manifest.json'),'utf8'));
  9. const quality=JSON.parse(fs.readFileSync(path.join(dir,'quality.json'),'utf8'));
  10. const hash=file=>crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
  11. assert.equal(quality.length,39);assert.ok(quality.every(c=>c.technicalPass));
  12. for(const old of JSON.parse(fs.readFileSync(path.join(dir,'previous-media.json'),'utf8')))assert.equal(hash(web+'/public'+old.url),old.sha256);
  13. assert.equal(audio.scripts.flatMap(p=>p.steps).length,39);
  14. for(const pack of audio.scripts)for(const clip of pack.steps){
  15. const v=video.scripts.find(p=>p.code===pack.code)?.steps.find(s=>s.stepCode===clip.stepCode);
  16. assert.equal(v.text,clip.text);assert.equal(v.expectedTitle,clip.expectedTitle);assert.equal(v.expectedInstruction,clip.expectedInstruction);
  17. assert.equal(hash(web+'/public'+clip.url),clip.stepSha256);assert.equal(hash(web+'/public'+v.url),v.sha256);
  18. assert.equal(quality.find(q=>q.key===`${pack.code}-step-${String(clip.number).padStart(2,'0')}`).sha256,v.sha256);
  19. if(clip.safetyUrl){assert.match(clip.safetyUrl,/junhao-v2-20260921/);assert.equal(hash(web+'/public'+clip.safetyUrl),clip.safetySha256);}
  20. }
  21. for(const [name,data]of [['narration-junhao-20260921.js',audio],['narration-video-junhao-20260921.js',video]])
  22. fs.writeFileSync(path.join(source,name),'// Generated by bridge-narration-current-voice.py; original release remains unchanged.\nexport default '+JSON.stringify(data,null,2)+';\n');
  23. fs.writeFileSync(path.join(source,'narration-release.js'),`import previousAudio from './narration-manifest.js';
  24. import previousVideo from './narration-video-manifest.js';
  25. import junhaoAudio from './narration-junhao-20260921.js';
  26. import junhaoVideo from './narration-video-junhao-20260921.js';
  27. // Build-time switch. Preserve both generations so rollback never regenerates media.
  28. export function selectNarrationRelease(name) {
  29. if (name === 'previous') return { manifest: previousAudio, videos: previousVideo };
  30. if (name === 'junhao-v2-20260921') return { manifest: junhaoAudio, videos: junhaoVideo };
  31. throw new Error('未知的桥梁讲解资源版本:' + name);
  32. }
  33. export const activeRelease = import.meta.env?.VITE_BRIDGE_NARRATION_RELEASE || 'junhao-v2-20260921';
  34. export const { manifest, videos } = selectNarrationRelease(activeRelease);
  35. `);
  36. const filename=path.join(source,'narration.js');
  37. const original=fs.readFileSync(filename,'utf8');
  38. const replacement=original.replace("import manifest from './narration-manifest.js';\nimport videos from './narration-video-manifest.js';","import { manifest, videos } from './narration-release.js';");
  39. assert.ok(replacement.includes("import { manifest, videos } from './narration-release.js';"));
  40. fs.writeFileSync(filename,replacement);
  41. fs.writeFileSync(path.join(dir,'activation.json'),JSON.stringify({release:'junhao-v2-20260921',oldMediaCount:80,oldMediaUnchanged:true,clips:39,qualityPassed:true,taskDefinitionsChanged:false},null,2));
  42. console.log('Activated 39 clips; previous 80 media files preserved.');