Add separate STT and LLM test commands
This commit is contained in:
91
src/services/ollama-llm.ts
Normal file
91
src/services/ollama-llm.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user