"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIResponsesClient = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const config_1 = require("../config"); const http_1 = require("../utils/http"); function extractUsage(raw) { const usage = (raw.usage ?? {}); const input = Number(usage.input_tokens ?? usage.prompt_tokens ?? 0); const output = Number(usage.output_tokens ?? usage.completion_tokens ?? 0); const total = Number(usage.total_tokens ?? input + output); return { input_tokens: Number.isFinite(input) ? input : 0, output_tokens: Number.isFinite(output) ? output : 0, total_tokens: Number.isFinite(total) ? total : 0 }; } function extractOutputText(raw) { if (typeof raw.output_text === "string" && raw.output_text.trim().length > 0) { return raw.output_text; } const output = raw.output; if (Array.isArray(output)) { for (const item of output) { if (!item || typeof item !== "object") { continue; } const content = item.content; if (!Array.isArray(content)) { continue; } for (const c of content) { if (!c || typeof c !== "object") { continue; } const block = c; if (typeof block.text === "string" && block.text.trim()) { return block.text; } } } } const response = raw.response; if (response && typeof response === "object") { const nested = response; if (typeof nested.output_text === "string" && nested.output_text.trim().length > 0) { return nested.output_text; } } throw new http_1.ApiError("OPENAI_OUTPUT_PARSE_FAILED", "Не удалось извлечь output_text из Responses API ответа.", 502, raw); } function loadSchemaForTransport(schemaVersion) { const schemaFile = schemaVersion === "v1" ? "normalized_query_v1.json" : schemaVersion === "v2_0_1" ? "normalized_query_v2_0_1.json" : schemaVersion === "v2_0_2" ? "normalized_query_v2_0_2.json" : "normalized_query_v2.json"; const schemaPath = path_1.default.resolve(config_1.SCHEMAS_DIR, schemaFile); return JSON.parse(fs_1.default.readFileSync(schemaPath, "utf-8")); } class OpenAIResponsesClient { async testConnection(config) { const payload = { model: config.model, input: [ { role: "user", content: [{ type: "input_text", text: "ping" }] } ], max_output_tokens: 16 }; await this.post(config, payload); return { ok: true, model: config.model }; } async normalize(config, prompt) { const schema = loadSchemaForTransport(prompt.schemaVersion); const schemaName = prompt.schemaVersion === "v1" ? "normalized_query_v1" : prompt.schemaVersion === "v2_0_1" ? "normalized_query_v2_0_1" : prompt.schemaVersion === "v2_0_2" ? "normalized_query_v2_0_2" : "normalized_query_v2"; const developerPrompt = prompt.controlledRetryInstruction ? `${prompt.developerPrompt}\n\n${prompt.controlledRetryInstruction}` : prompt.developerPrompt; const payload = { model: config.model, temperature: config.temperature ?? 0, max_output_tokens: config.maxOutputTokens ?? 700, input: [ { role: "system", content: [{ type: "input_text", text: prompt.systemPrompt }] }, { role: "developer", content: [{ type: "input_text", text: developerPrompt }] }, { role: "user", content: [ { type: "input_text", text: `${prompt.domainPrompt}\n\nПользовательский вопрос:\n${prompt.userQuestion}` } ] } ], text: { format: { type: "json_schema", name: schemaName, strict: true, schema } } }; const raw = await this.post(config, payload); const outputText = extractOutputText(raw); return { raw, outputText, usage: extractUsage(raw) }; } async post(config, payload) { if (!config.apiKey || config.apiKey.trim().length < 10) { throw new http_1.ApiError("OPENAI_API_KEY_MISSING", "API ключ OpenAI не задан или слишком короткий.", 400); } const url = `${(config.baseUrl ?? config_1.DEFAULT_OPENAI_BASE_URL).replace(/\/$/, "")}/responses`; const response = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${config.apiKey}`, "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const text = await response.text(); let data; try { data = JSON.parse(text); } catch { throw new http_1.ApiError("OPENAI_NON_JSON_RESPONSE", "OpenAI вернул не-JSON ответ.", 502, { status: response.status, body: text.slice(0, 500) }); } if (!response.ok) { const errorObj = (data.error ?? {}); throw new http_1.ApiError("OPENAI_REQUEST_FAILED", String(errorObj.message ?? `OpenAI request failed with status ${response.status}`), response.status, { status: response.status, type: errorObj.type ?? null, code: errorObj.code ?? null }); } return data; } } exports.OpenAIResponsesClient = OpenAIResponsesClient;