feat(voice): 注入層與 CLI 訊息改成人話;越害羞話越少、心裡話越多(v0.0.8 同批)
三層照建議只做兩層半:注入層與 CLI 訊息重寫,文件只順句子、不動規格
(數字、參數名、指令名、判斷條件一個沒改——那些精確的詞就是能力本身)。
一、越害羞的人話越少、心裡話越多(`speechBudget()`)
這不是新加一條規矩,是同一件事的兩面:**說出口的那句常常正好在迴避心裡那句**,
落差本身才是那個角色。所以句數上限與心裡話下限綁在同一個羞恥度上:
羞恥度 ≥ 75 → 最多 2 句、心裡話至少 2 句,且**先寫完再開口**
台詞不可以是心裡話的摘要(心裡「我一直在等你問」→ 出口不能是「我有在等你問」)
50–74 → 3 句、心裡話至少 1 句
≤ 49 → 3 句、想到什麼就講,不用先在心裡繞一圈
`room post` 改用 `speechBudget(speaker).sentences`,不再是固定三句;
被擋下時會講明「這個人格話比別人少」。
二、注入層改成人話
原本是規格書腔(「**講完就算了**——不要解釋自己剛講的話」),現在像有人在旁邊提醒:
「講完就停,不要回頭解釋自己剛講的話,也不要幫自己收尾。」
黑名單從列舉詞條改成講清楚**為什麼**不像人(「先發一句免費的認可,對方要的是回答」)。
機械會擋的規則壓成最後一行括號——保留全部關鍵詞,但不再稀釋前面的重點。
三、CLI 訊息改成人話(20 條)
「⚠ 這段有 4 句,超過 3 句上限 → 砍到重點」→「講太多了,4 句。這裡最多 3 句——挑最想說的那一兩句就好」
「幾乎只給自己加分——這種偏差要自己看得見」→「幾乎都在給自己加分。delta 是你自己挑的,這種偏差沒人會替你抓」
四、測試
314 項全過(新增 4 項)。既有 6 條斷言原本釘在字面上,措辭一改就紅——
改成釘意思(「最多」「講過」「講完就停」)而不是釘整句,這種脆弱本來就該修。
版本:與 PR #11 同一批,維持 0.0.8。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-15
@@ -802,11 +802,11 @@ commands.said = ({ flags, positional }) => {
|
||||
const lines = [];
|
||||
if (repeat) {
|
||||
lines.push(
|
||||
`⚠ 這句跟 ${repeat.minutes_ago} 分鐘前說過的話相似 ${repeat.similarity}:「${repeat.text.slice(0, 60)}」`,
|
||||
" → 換個角度、補新資訊,或直接推進話題;不要再說一次。",
|
||||
`⚠ 這句 ${repeat.minutes_ago} 分鐘前講過了(像了 ${repeat.similarity}):「${repeat.text.slice(0, 60)}」`,
|
||||
" → 換個角度、補點新的,或直接推進話題。",
|
||||
);
|
||||
}
|
||||
if (tooLong) lines.push(`⚠ 這段有 ${sentences} 句,超過 ${pl.MAX_SENTENCES} 句上限 → 砍到重點。`);
|
||||
if (tooLong) lines.push(`⚠ 講太多了,${sentences} 句(上限 ${pl.MAX_SENTENCES})→ 挑最想說的那一兩句。`);
|
||||
const lint = pl.speechLint(text);
|
||||
const blockers = lint.filter((i) => i.level !== "hint");
|
||||
for (const issue of blockers) lines.push(`⚠ ${pl.speechLintMessage(issue)}。`);
|
||||
@@ -814,7 +814,7 @@ commands.said = ({ flags, positional }) => {
|
||||
for (const issue of lint.filter((i) => i.level === "hint")) lines.push(`· ${pl.speechLintMessage(issue)}。`);
|
||||
const clean = !repeat && !tooLong && !blockers.length;
|
||||
if (clean) {
|
||||
lines.push(`✔ 沒說過,${sentences} 句,可以說。`);
|
||||
lines.push(`✔ 沒講過,${sentences} 句,可以說。`);
|
||||
if (flags.record) pl.recordSaid(slug, text, { kind: "reply" });
|
||||
}
|
||||
emit({ persona: slug, repeat, sentences, lint, ok: clean }, flags.json, lines);
|
||||
@@ -932,8 +932,8 @@ commands.emotion = ({ flags }) => {
|
||||
emit({ persona: slug, read }, flags.json, [
|
||||
`讀「${readText.slice(0, 40)}」:`,
|
||||
read.signals.length
|
||||
? ` 訊號:${read.signals.map((s) => `${s.zh} ${s.score}`).join("、")}|強度 ${read.intensity}|${read.confident ? "夠強,值得參考" : "偏弱,別當判定"}`
|
||||
: " 沒有讀到明確的情緒訊號。",
|
||||
? ` 讀到:${read.signals.map((s) => `${s.zh} ${s.score}`).join("、")}|強度 ${read.intensity}|${read.confident ? "夠明顯,可以參考" : "很弱,別當真"}`
|
||||
: " 這句沒讀出什麼情緒。",
|
||||
...(read.signals.length ? [` 怎麼接:${pl.RESPONSE_STANCE[read.signals[0].key]}`] : []),
|
||||
]);
|
||||
return;
|
||||
@@ -946,8 +946,8 @@ commands.emotion = ({ flags }) => {
|
||||
` 往舒服的方向 ${audit.positive}|往難受的方向 ${audit.negative}` +
|
||||
(audit.positive_ratio === null ? "" : ` → 正向佔 ${audit.positive_ratio}%`),
|
||||
audit.positive_ratio !== null && audit.positive_ratio >= 90
|
||||
? " ⚠ 幾乎只給自己加分——delta 是你自己挑的,這種偏差要自己看得見。"
|
||||
: " 比例還算兩邊都有。",
|
||||
? " ⚠ 幾乎都在給自己加分。delta 是你自己挑的,這種偏差沒人會替你抓。"
|
||||
: " 兩邊都有,還算誠實。",
|
||||
trend ? ` 對方的走向:${trend.zh} ${trend.direction}(近 ${trend.rounds} 輪)` : " 還沒有足夠的輪次算走向。",
|
||||
]);
|
||||
return;
|
||||
@@ -1328,23 +1328,28 @@ commands.room = ({ flags, positional }) => {
|
||||
(speakerRole === "guest" ? null : pl.saidRepeat(speaker, text, opts));
|
||||
if (repeat) {
|
||||
die(
|
||||
`\`${speaker}\` 在 ${repeat.minutes_ago} 分鐘前說過幾乎一樣的話(相似度 ${repeat.similarity}):` +
|
||||
`「${repeat.text.slice(0, 60)}」。換個說法、補新東西或推進話題;` +
|
||||
"真的需要重複(例如被追問)才加 `--allow-repeat`。",
|
||||
`這句 ${repeat.minutes_ago} 分鐘前就講過了(像了 ${repeat.similarity}):「${repeat.text.slice(0, 60)}」。` +
|
||||
"換個角度、補點新的,或者直接把話題往前推。" +
|
||||
"他追問、你非得重講一次,才加 `--allow-repeat`。",
|
||||
);
|
||||
}
|
||||
}
|
||||
const sentences = pl.sentenceCount(text);
|
||||
if (sentences > pl.MAX_SENTENCES && !flags.force) {
|
||||
// 越害羞的人話越少:上限跟著羞恥度走,不是固定三句
|
||||
const budget = pl.personaExists(speaker) ? pl.speechBudget(speaker) : { sentences: pl.MAX_SENTENCES, modesty: 50 };
|
||||
if (sentences > budget.sentences && !flags.force) {
|
||||
const why = budget.sentences < pl.MAX_SENTENCES
|
||||
? `(羞恥度 ${budget.modesty},這個人格話比別人少)`
|
||||
: "";
|
||||
die(
|
||||
`這句有 ${sentences} 句,超過 ${pl.MAX_SENTENCES} 句上限——聊天不是報告,砍到重點再發。` +
|
||||
"(真的需要長段落才加 `--force`。)",
|
||||
`講太多了,${sentences} 句。這裡最多 ${budget.sentences} 句${why}——` +
|
||||
"挑最想說的那一兩句就好,剩下的寫進心裡話。(真的需要長台詞才加 `--force`。)",
|
||||
);
|
||||
}
|
||||
// 短句、日常話、講完不解釋、不說 AI 才會說的話——講話的樣子也擋在 CLI 裡,不靠自律。
|
||||
const lint = pl.speechBlockers(text);
|
||||
if (lint.length && !flags.force) {
|
||||
die(`講話規則:${lint.map(pl.speechLintMessage).join(";")}。(真的需要才加 \`--force\`。)`);
|
||||
die(`${lint.map(pl.speechLintMessage).join(";")}。(真的需要才加 \`--force\`。)`);
|
||||
}
|
||||
let emotion = str(flags.emotion);
|
||||
if (!emotion && pl.personaExists(speaker)) {
|
||||
|
||||
Reference in New Issue
Block a user