NODEDC_1C/llm_normalizer/backend/scripts/runCompanyQuestionBatch.js

234 lines
6.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
const fs = require("node:fs");
const path = require("node:path");
const request = require("supertest");
function parseArgs(argv) {
const args = {
questionsFile: "",
runDir: "",
rawFileName: "chat20_wave13_raw.json",
chatFileName: "Chat20.txt",
chatRuFileName: ат20.txt",
promptsFileName: path.join("prompt_dialogs", "chat20_prompts.md"),
useMock: true,
promptVersion: "normalizer_v2_0_2",
sessionId: "",
casePrefix: "q"
};
for (let i = 0; i < argv.length; i += 1) {
const token = argv[i];
if (token === "--questions-file") {
args.questionsFile = String(argv[i + 1] ?? "");
i += 1;
continue;
}
if (token === "--run-dir") {
args.runDir = String(argv[i + 1] ?? "");
i += 1;
continue;
}
if (token === "--raw-file") {
args.rawFileName = String(argv[i + 1] ?? args.rawFileName);
i += 1;
continue;
}
if (token === "--chat-file") {
args.chatFileName = String(argv[i + 1] ?? args.chatFileName);
i += 1;
continue;
}
if (token === "--chat-ru-file") {
args.chatRuFileName = String(argv[i + 1] ?? args.chatRuFileName);
i += 1;
continue;
}
if (token === "--prompts-file") {
args.promptsFileName = String(argv[i + 1] ?? args.promptsFileName);
i += 1;
continue;
}
if (token === "--use-mock") {
const value = String(argv[i + 1] ?? "true").toLowerCase();
args.useMock = value !== "0" && value !== "false" && value !== "no";
i += 1;
continue;
}
if (token === "--prompt-version") {
args.promptVersion = String(argv[i + 1] ?? args.promptVersion);
i += 1;
continue;
}
if (token === "--session-id") {
args.sessionId = String(argv[i + 1] ?? "");
i += 1;
continue;
}
if (token === "--case-prefix") {
args.casePrefix = String(argv[i + 1] ?? args.casePrefix);
i += 1;
}
}
return args;
}
function ensureDir(dirPath) {
fs.mkdirSync(dirPath, { recursive: true });
}
function readJson(filePath) {
const raw = fs.readFileSync(filePath, "utf8").replace(/^\uFEFF/, "");
return JSON.parse(raw);
}
function writeUtf8Bom(filePath, content) {
ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, `\uFEFF${content}`, "utf8");
}
function asText(value) {
return value == null ? "" : String(value);
}
function makeCaseId(prefix, index) {
return `${prefix}${String(index + 1).padStart(2, "0")}`;
}
function buildPromptsMarkdown(questions) {
const lines = [];
for (let i = 0; i < questions.length; i += 1) {
lines.push(`${i + 1}. ${questions[i]}`);
lines.push("");
}
return `${lines.join("\n").trim()}\n`;
}
function buildChatTxt(sessionId, exportedAt, rows) {
const lines = [];
lines.push("# Assistant conversation export");
lines.push(`session_id: ${sessionId}`);
lines.push(`exported_at: ${exportedAt}`);
lines.push("");
let messageCounter = 1;
for (const row of rows) {
lines.push(`## ${messageCounter}. user`);
lines.push("message_id: pending");
lines.push("created_at: pending");
lines.push("reply_type: n/a");
lines.push("");
lines.push(asText(row.user_message));
lines.push("");
messageCounter += 1;
lines.push(`## ${messageCounter}. assistant`);
lines.push(`message_id: ${asText(row.message_id) || "n/a"}`);
lines.push(`created_at: ${asText(row.created_at) || "n/a"}`);
lines.push(`reply_type: ${asText(row.reply_type) || "n/a"}`);
if (row.trace_id) {
lines.push(`trace_id: ${asText(row.trace_id)}`);
}
lines.push("");
lines.push(asText(row.assistant_reply));
lines.push("");
messageCounter += 1;
}
return `${lines.join("\n").trim()}\n`;
}
async function main() {
const args = parseArgs(process.argv.slice(2));
if (!args.questionsFile) {
throw new Error("Missing required argument --questions-file");
}
if (!args.runDir) {
throw new Error("Missing required argument --run-dir");
}
const questionsPath = path.resolve(args.questionsFile);
const runDir = path.resolve(args.runDir);
const backendRoot = path.resolve(__dirname, "..");
const questions = readJson(questionsPath);
if (!Array.isArray(questions) || questions.length === 0) {
throw new Error("Questions JSON must be a non-empty array of strings.");
}
const { createApp } = require(path.join(backendRoot, "dist", "server.js"));
const app = createApp();
ensureDir(runDir);
ensureDir(path.join(runDir, "prompt_dialogs"));
const rows = [];
let sessionId = args.sessionId || `wave13-chat20-${Date.now()}`;
for (let i = 0; i < questions.length; i += 1) {
const userMessage = asText(questions[i]);
const response = await request(app).post("/api/assistant/message").send({
useMock: args.useMock,
promptVersion: args.promptVersion,
session_id: sessionId,
user_message: userMessage
});
const body = response.body || {};
sessionId = asText(body.session_id) || sessionId;
const item = body.conversation_item || {};
rows.push({
case_id: makeCaseId(args.casePrefix, i),
user_message: userMessage,
assistant_reply: asText(body.assistant_reply),
reply_type: asText(body.reply_type),
message_id: asText(item.message_id),
created_at: asText(item.created_at),
trace_id: asText(item.trace_id || body.debug?.trace_id),
http_status: response.status,
debug: body.debug || {}
});
}
const exportedAt = new Date().toISOString();
const rawPayload = {
session_id: sessionId,
exported_at: exportedAt,
cases_total: rows.length,
rows
};
const rawPath = path.join(runDir, args.rawFileName);
const chatPath = path.join(runDir, args.chatFileName);
const chatRuPath = path.join(runDir, args.chatRuFileName);
const promptsPath = path.join(runDir, args.promptsFileName);
writeUtf8Bom(rawPath, `${JSON.stringify(rawPayload, null, 2)}\n`);
const chatBody = buildChatTxt(sessionId, exportedAt, rows);
writeUtf8Bom(chatPath, chatBody);
if (args.chatRuFileName) {
writeUtf8Bom(chatRuPath, chatBody);
}
writeUtf8Bom(promptsPath, buildPromptsMarkdown(questions));
process.stdout.write(
[
`run_dir=${runDir}`,
`session_id=${sessionId}`,
`cases_total=${rows.length}`,
`raw=${rawPath}`,
`chat=${chatPath}`,
`chat_ru=${chatRuPath}`,
`prompts=${promptsPath}`
].join("\n")
);
}
main().catch((error) => {
process.stderr.write(`${error?.stack || error}\n`);
process.exitCode = 1;
});