Add separate STT and LLM test commands

This commit is contained in:
2026-05-03 00:44:26 +09:00
parent 48937c684b
commit 7e59013fa4
9 changed files with 274 additions and 22 deletions

View File

@@ -0,0 +1,91 @@
import type { AppConfig } from "../config.js";
import type { Logger } from "../logger.js";
interface OllamaChatMessage {
role: "system" | "user" | "assistant";
content: string;
}
interface OllamaChatResponse {
message?: {
content?: string;
};
}
const SYSTEM_PROMPT =
"너는 한국어로 짧고 자연스럽게 답하는 로컬 음성 비서다. 사용자의 말에 바로 답하고, 군더더기 없는 1~3문장으로 답해라.";
export class OllamaLlmService {
private history: OllamaChatMessage[] = [];
constructor(
private readonly config: AppConfig,
private readonly logger: Logger,
) {}
async warmup(): Promise<void> {
const reply = await this.chat(
[
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: "준비 상태 확인입니다. 한 단어로만 답하세요." },
],
);
this.logger.info("LLM warmup finished", { model: this.config.OLLAMA_MODEL, reply });
}
async generateReply(userText: string): Promise<string> {
const messages: OllamaChatMessage[] = [
{ role: "system", content: SYSTEM_PROMPT },
...this.history,
{ role: "user", content: userText },
];
const reply = await this.chat(messages);
this.history.push({ role: "user", content: userText });
this.history.push({ role: "assistant", content: reply });
this.trimHistory();
return reply;
}
resetConversation(): void {
this.history = [];
}
private trimHistory(): void {
const maxMessages = this.config.MAX_CONVERSATION_TURNS * 2;
if (this.history.length <= maxMessages) {
return;
}
this.history = this.history.slice(-maxMessages);
}
private async chat(messages: OllamaChatMessage[]): Promise<string> {
const response = await fetch(`${this.config.OLLAMA_BASE_URL}/api/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({
model: this.config.OLLAMA_MODEL,
messages,
stream: false,
think: false,
keep_alive: this.config.OLLAMA_KEEP_ALIVE,
}),
});
if (!response.ok) {
const body = await response.text();
throw new Error(`Ollama API ${response.status}: ${body}`);
}
const payload = (await response.json()) as OllamaChatResponse;
const content = payload.message?.content?.trim();
if (!content) {
throw new Error("Ollama 응답에 message.content 가 없습니다.");
}
return content;
}
}