UNPKG

i18n-ai-translate

Version:

AI-powered localization CLI, Node library, and GitHub Action. Translate i18next JSON, Gettext PO, Java .properties, and iOS .strings with ChatGPT, Claude, Gemini, or local Ollama models.

97 lines (80 loc) 3.01 kB
import { printError } from "../utils"; import { zodResponseFormat } from "openai/helpers/zod"; import ChatInterface, { type InvalidKind } from "./chat_interface"; import Role from "../enums/role"; import type { ZodType, ZodTypeDef } from "zod"; import type OpenAI from "openai"; import type RateLimiter from "../rate_limiter"; export default class ChatGPT extends ChatInterface { model: OpenAI; chatParams: OpenAI.ChatCompletionCreateParamsNonStreaming | null; history: OpenAI.ChatCompletionMessageParam[]; rateLimiter: RateLimiter; constructor(model: OpenAI, rateLimiter: RateLimiter) { super(); this.model = model; this.chatParams = null; this.history = []; this.rateLimiter = rateLimiter; } startChat(params: OpenAI.ChatCompletionCreateParamsNonStreaming): void { this.chatParams = params; if (params.messages.length > 0) { this.history = params.messages; } } async sendMessage( message: string, format?: ZodType<any, ZodTypeDef, any>, ): Promise<string> { if (!this.chatParams) { console.trace("Chat not started"); return ""; } // Limit the history to prevent wasting tokens if (this.history.length > 2) { this.history = this.history.slice(this.history.length - 2); } await this.rateLimiter.acquire(Math.ceil(message.length / 2)); this.history.push({ content: message, role: Role.User }); const formatSchema = format ? zodResponseFormat(format, format.description ?? "responseObject") : undefined; try { const response = await this.model.chat.completions.create({ ...this.chatParams, messages: this.history, response_format: formatSchema, }); const responseText = response.choices[0].message.content; if (!responseText) { return ""; } this.history.push({ content: responseText, role: Role.Assistant }); return responseText; } catch (err) { printError(err); return ""; } } resetChatHistory(): void { this.history = []; } rollbackLastMessage(): void { if (this.history[this.history.length - 1].role === Role.Assistant) { // Remove the last two messages (user and assistant) // so we can get back to the last successful state in history this.history.pop(); this.history.pop(); } else if (this.history[this.history.length - 1].role === Role.User) { // The model didn't respond, so we only need to remove the user message this.history.pop(); } } signalInvalid(kind: InvalidKind): void { this.history.push({ content: this.invalidMessage(kind), role: Role.System, }); } }