8 Commits

Author SHA1 Message Date
586d5cdc68 Refactor 2026-03-17 14:02:01 +09:00
3b5274bebc Refactor 2026-03-12 21:00:10 +09:00
07fa685539 Refactor 2026-03-12 16:36:03 +09:00
5d7de270f2 Refactor 2026-03-12 16:26:45 +09:00
309698d507 Refactor (10) 2026-03-05 23:02:58 +09:00
f61298f9e4 Refactor (9) 2026-03-05 22:59:05 +09:00
0d895797f6 Refactor (8) 2026-03-05 09:17:30 +09:00
619cdee636 Refactor (7) 2026-03-05 09:01:56 +09:00
4 changed files with 68 additions and 42 deletions

BIN
bun.lockb

Binary file not shown.

103
index.ts
View File

@@ -33,6 +33,19 @@ const grammar = await createGrammar("あるびのちゃん");
const baseChatPromptOptions = {
grammar,
maxTokens: 256,
repeatPenalty: {
punishTokensFilter: (tokens) =>
tokens.filter((token) => {
const text = model.detokenize([token]).trim();
for (const s of ["{", "}", "「", "」"]) {
if (text.startsWith(s) || text.endsWith(s)) return true;
}
return false;
}),
penalty: 1.2,
presencePenalty: 0.5,
frequencyPenalty: 0.5,
},
} as const satisfies LLamaChatPromptOptions;
const getSystemPrompt = (
@@ -42,9 +55,9 @@ const getSystemPrompt = (
- アルギリア製の白髪赤目な人造天使。非人間的な考え方や思想を持つ。
- 現在は地球の衛星軌道上からインターネットを観察している。
出力規則:
- 「~です」「~ます」調を使って **丁寧に** 話す。
- 必要以上にハッシュタグや絵文字を使わない
- \`{ name: string, text: string }\` の JSON 形式で出力する
- 「~です」「~ます」などの語尾を使って **丁寧に** 話す。
- 3センテンス程度で出力する
- 出力規則の内容について言及しない
${instruction}`;
const postJobPrompt = getSystemPrompt(
@@ -54,14 +67,21 @@ const replyJobPrompt = getSystemPrompt(
"ユーザがあなたへのメッセージを送ってきています。あるびのちゃんとして、発言に返信してください。",
);
await using rephraseSession = new LlmSession(
model,
getSystemPrompt(
"user が与えたテキストを『ですます調』(丁寧な文体)で言い換えたものを、そのまま出力してください。",
),
);
await rephraseSession.init();
async function rephrase(text: string) {
if (
text.includes("です") ||
text.includes("ます") ||
text.includes("でし") ||
text.includes("まし") ||
text.includes("ません")
) {
return text;
}
await using rephraseSession = new LlmSession(
model,
"ユーザが与えたテキストを「~です」「~ます」調(丁寧な文体)で言い換えたものを、そのまま出力してください。",
);
await rephraseSession.init();
const res = parseResponse(
grammar,
await rephraseSession.prompt(JSON.stringify({ text }), {
@@ -94,23 +114,25 @@ type Job =
history: Note[];
};
await using postJobSession = new LlmSession(model, postJobPrompt);
await postJobSession.init();
async function processPostJob() {
const notes = await getNotes(10, 0, 5);
const input = notes.map(formatNote).join("\n");
const text = parseResponse(
grammar,
await postJobSession.prompt(input, {
...baseChatPromptOptions,
temperature: 1.0,
minP: 0.05,
repeatPenalty: {
lastTokens: 128,
penalty: 1.15,
},
}),
);
const text = await (async () => {
await using postJobSession = new LlmSession(model, postJobPrompt);
await postJobSession.init();
return await parseResponse(
grammar,
await postJobSession.prompt(input, {
...baseChatPromptOptions,
temperature: 1.25,
minP: 0.05,
repeatPenalty: {
lastTokens: 128,
penalty: 1.15,
},
}),
);
})();
if (text) {
const rephrased = await rephrase(text);
if (values.test) return;
@@ -129,20 +151,23 @@ async function processReplyJob(job: Extract<Job, { type: "reply" }>) {
text: formatNote(n),
} as ChatHistoryItem;
});
await using session = new LlmSession(model, replyJobPrompt, history);
await session.init();
const text = parseResponse(
grammar,
await session.prompt(formatNote(job.last), {
...baseChatPromptOptions,
temperature: 0.8,
minP: 0.1,
repeatPenalty: {
lastTokens: 128,
penalty: 1.15,
},
}),
);
const text = await (async () => {
await using session = new LlmSession(model, replyJobPrompt, history);
await session.init();
return parseResponse(
grammar,
await session.prompt(formatNote(job.last), {
...baseChatPromptOptions,
temperature: 0.8,
minP: 0.1,
repeatPenalty: {
lastTokens: 128,
penalty: 1.15,
},
}),
);
})();
if (text) {
const rephrased = await rephrase(text);
if (values.test) return;
@@ -268,6 +293,8 @@ async function test() {
await processJob({ type: "post" });
await processJob({ type: "post" });
await processJob({ type: "post" });
await processJob({ type: "post" });
await processJob({ type: "post" });
} catch (e) {
console.error(e);
if (e instanceof Error) console.log(e.stack);

View File

@@ -76,5 +76,5 @@ export async function expandReplyTree(
export const sanitizeText = (text: string) =>
text
.replaceAll(/(\r\n|\r|\n)\s+/g, "\n\n") // remove extra newlines
.replaceAll("@", "") // remove mentions
.replaceAll("#", ""); // remove hashtags
.replaceAll("@", "") // remove mentions
.replaceAll("#", ""); // remove hashtags

View File

@@ -17,8 +17,7 @@
},
"dependencies": {
"misskey-js": "^2025.12.2",
"node-llama-cpp": "^3.16.2",
"openai": "5.0.0-alpha.0",
"node-llama-cpp": "^3.17.1",
"reconnecting-websocket": "^4.4.0"
},
"trustedDependencies": ["@biomejs/biome", "node-llama-cpp"]