数字我 Digital Me:全量入库(大文件走 Git LFS)
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { STYLES, listErchuangAnchors, buildErchuangPrompt, buildSegmentPrompt, parseSegments } from '../src/erchuang.js';
|
||||
import { buildPack } from '../src/sucaibao.js';
|
||||
|
||||
test('锚点名录:战役 + 她传人物 + 体裁', () => {
|
||||
const a = listErchuangAnchors();
|
||||
assert.ok(a.zhanzhen.length >= 11, '应含全部战役');
|
||||
assert.ok(a.nvxing.length >= 18, '应含全部她传人物');
|
||||
assert.ok(a.zhanzhen.every((x) => x.type === 'zhanzhen' && x.title && x.sub));
|
||||
assert.ok(a.nvxing.every((x) => x.type === 'nvxing' && x.title && x.sub));
|
||||
for (const k of ['ci', 'fu', 'ji', 'juben', 'shi', 'weishichen', 'duitan', 'gongzhi', 'huimu', 'gongxu']) {
|
||||
assert.ok(a.styles.some((s) => s.key === k), `体裁应含 ${k}`);
|
||||
}
|
||||
// 每体裁有 layer 标
|
||||
for (const v of Object.values(STYLES)) assert.ok(['work', 'segment'].includes(v.layer), `${v.label} 须有 layer`);
|
||||
});
|
||||
|
||||
test('buildSegmentPrompt:骨架注入 + 出处自标铁律 + 黑名单/断代守卫', () => {
|
||||
const pack = buildPack('zhanzhen', 'chibi');
|
||||
const { messages } = buildSegmentPrompt(pack, 'weishichen', {});
|
||||
const sys = messages[0].content, user = messages[1].content;
|
||||
assert.ok(/\[\[f:key\|/.test(sys) && /\[\[y:子类\|/.test(sys), 'system 须给出 f/y 自标语法');
|
||||
assert.ok(/对话永远是 y/.test(sys), '对话恒演绎铁律');
|
||||
assert.ok(/演义黑名单/.test(sys) && /借东风/.test(sys), '须注入黑名单');
|
||||
assert.ok(/断代=donghan/.test(sys), '须注入断代守卫');
|
||||
assert.ok(user.includes('史实骨架') && /\[c\d\]/.test(user), 'user 须带编号骨架');
|
||||
});
|
||||
|
||||
test('parseSegments:f挂cite/表外key降y/对话保子类/黑名单剔除/标点并段', () => {
|
||||
const table = { c1: '《三国志·周瑜传》:操军方连船舰' };
|
||||
const r = parseSegments('[[f:c1|曹军船舰首尾相接]]。[[y:对话|黄盖低声:今夜可成]]。[[f:c9|某表外句]]。[[y:叙事|借东风起了]]。', table, { blacklist: ['借东风'], era: 'donghan' });
|
||||
const f = r.segs.find((s) => s.text.includes('船舰'));
|
||||
assert.equal(f.t, 'f'); assert.ok(f.cite.includes('周瑜传'));
|
||||
assert.ok(f.text.endsWith('。'), '标点应并进史实段');
|
||||
const dia = r.segs.find((s) => s.text.includes('黄盖'));
|
||||
assert.equal(dia.t, 'y'); assert.equal(dia.kind, '对话'); assert.ok(!dia.cite, '对话永不挂cite');
|
||||
const wild = r.segs.find((s) => s.text.includes('表外'));
|
||||
assert.equal(wild.t, 'y', '表外key必须降为演绎(护城河)');
|
||||
assert.ok(!r.segs.some((s) => s.text.includes('借东风')), '演义黑名单段被剔除');
|
||||
});
|
||||
|
||||
test('buildErchuangPrompt:把双证史实卡拼进 prompt,含红线约束', () => {
|
||||
const fact = { title: '赤壁之战', sub: '孙刘联军 vs 曹军 · 208年', facts: ['火攻破曹'], cites: ['《三國志·吳書·周瑜傳》:「……」'] };
|
||||
const { messages, styleLabel } = buildErchuangPrompt(fact, 'ci', { seed: '写周瑜的意气', role: '周瑜部将' });
|
||||
assert.equal(styleLabel, '词');
|
||||
assert.equal(messages[0].role, 'system');
|
||||
assert.ok(/文学演绎/.test(messages[0].content) && /相悖的硬事实/.test(messages[0].content), 'system 须含创作≠史料红线');
|
||||
assert.ok(messages[1].content.includes('赤壁之战') && messages[1].content.includes('《三國志'), 'user 须带真实事件+正史依据');
|
||||
assert.ok(messages[1].content.includes('周瑜部将') && messages[1].content.includes('写周瑜的意气'), 'user 须带身份+方向');
|
||||
});
|
||||
|
||||
test('未知体裁回落古体诗', () => {
|
||||
const { styleLabel } = buildErchuangPrompt({ title: 't', sub: 's', facts: [], cites: [] }, 'nope', {});
|
||||
assert.equal(styleLabel, STYLES.shi.label);
|
||||
});
|
||||
Reference in New Issue
Block a user