АРЧ - UI и domain loop: синхронизировать локальную LLM-модель через shared config + КВИН 3
This commit is contained in:
+2
-1
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TRACES_DIR = exports.DATA_DIR = exports.VAT_PAYABLE_19_PREFIXES = exports.VAT_PAYABLE_68_PREFIXES = exports.ASSISTANT_MCP_LIVE_LIMIT = exports.ASSISTANT_MCP_TIMEOUT_MS = exports.ASSISTANT_MCP_CHANNEL = exports.ASSISTANT_MCP_PROXY_URL = exports.FEATURE_ASSISTANT_LIVING_CHAT_ROUTER_V1 = exports.FEATURE_ASSISTANT_ROUTE_EXPECTATION_HARD_GUARD_V1 = exports.FEATURE_ASSISTANT_ROUTE_EXPECTATION_AUDIT_V1 = exports.FEATURE_ASSISTANT_ROUTE_SHADOW_PAYABLES_EXACT_V1 = exports.FEATURE_ASSISTANT_ROUTE_RECEIVABLES_HEURISTIC_V1 = exports.FEATURE_ASSISTANT_ROUTE_PAYABLES_HEURISTIC_V1 = exports.FEATURE_ASSISTANT_ROUTE_RECEIVABLES_CONFIRMED_V1 = exports.FEATURE_ASSISTANT_ROUTE_PAYABLES_CONFIRMED_V1 = exports.FEATURE_ASSISTANT_ROUTE_BALANCE_EXACT_V1 = exports.FEATURE_ASSISTANT_ROUTE_DRILLDOWN_V1 = exports.FEATURE_ASSISTANT_ROUTE_ADDRESS_GENERIC_V1 = exports.FEATURE_ASSISTANT_CAPABILITY_ROUTE_GUARD_V1 = exports.FEATURE_ASSISTANT_ADDRESS_NAVIGATION_STATE_V1 = exports.FEATURE_ASSISTANT_ADDRESS_QUERY_LIVE_V1 = exports.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1 = exports.FEATURE_ASSISTANT_ADDRESS_QUERY_V1 = exports.FEATURE_ASSISTANT_MCP_RUNTIME_V1 = exports.FEATURE_ASSISTANT_GRAPH_RUNTIME_V1 = exports.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1 = exports.FEATURE_ASSISTANT_LIFECYCLE_RUNTIME_V1 = exports.FEATURE_ASSISTANT_STAGE2_EVAL_V1 = exports.FEATURE_ASSISTANT_PROBLEM_UNIT_CONTINUITY_V1 = exports.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1 = exports.FEATURE_ASSISTANT_PROBLEM_UNITS_V1 = exports.FEATURE_ASSISTANT_ACCOUNTANT_EVAL_V1 = exports.FEATURE_ASSISTANT_ANSWER_POLICY_V11 = exports.FEATURE_ASSISTANT_ANTI_GENERIC_RANKING_GUARD_V1 = exports.FEATURE_ASSISTANT_MIN_EVIDENCE_GATE_V1 = exports.FEATURE_ASSISTANT_BROAD_GUARD_V1 = exports.FEATURE_ASSISTANT_EVIDENCE_ENRICHMENT_V1 = exports.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1 = exports.FEATURE_ASSISTANT_CONTRACTS_V11 = exports.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1 = exports.DEFAULT_PROMPT_VERSION = exports.DEFAULT_MAX_OUTPUT_TOKENS = exports.DEFAULT_TEMPERATURE = exports.DEFAULT_MODEL = exports.DEFAULT_OPENAI_BASE_URL = exports.TIMEZONE = exports.PORT = exports.MODULE_ROOT = exports.BACKEND_ROOT = void 0;
|
||||
exports.MANUAL_CASE_DECISION_SCHEMA_FILE = exports.ASSISTANT_CAPABILITIES_REGISTRY_FILE = exports.ASSISTANT_CANON_FILE = exports.ARCH_EXPORT_2020_DIR = exports.SCHEMAS_DIR = exports.EVAL_DATASETS_DIR = exports.REPORTS_DIR = exports.PROMPTS_DIR = exports.AUTORUN_GENERATOR_HISTORY_FILE = exports.AUTORUN_GENERATOR_DIR = exports.AUTORUN_ANNOTATIONS_FILE = exports.AUTORUN_ANNOTATIONS_DIR = exports.ASSISTANT_ANNOTATIONS_FILE = exports.ASSISTANT_ANNOTATIONS_DIR = exports.ASSISTANT_SESSIONS_DIR = exports.EVAL_CASES_DIR = exports.PRESETS_DIR = void 0;
|
||||
exports.MANUAL_CASE_DECISION_SCHEMA_FILE = exports.ASSISTANT_CAPABILITIES_REGISTRY_FILE = exports.ASSISTANT_CANON_FILE = exports.ARCH_EXPORT_2020_DIR = exports.SCHEMAS_DIR = exports.EVAL_DATASETS_DIR = exports.REPORTS_DIR = exports.PROMPTS_DIR = exports.SHARED_LLM_CONNECTION_FILE = exports.AUTORUN_GENERATOR_HISTORY_FILE = exports.AUTORUN_GENERATOR_DIR = exports.AUTORUN_ANNOTATIONS_FILE = exports.AUTORUN_ANNOTATIONS_DIR = exports.ASSISTANT_ANNOTATIONS_FILE = exports.ASSISTANT_ANNOTATIONS_DIR = exports.ASSISTANT_SESSIONS_DIR = exports.EVAL_CASES_DIR = exports.PRESETS_DIR = void 0;
|
||||
const path_1 = __importDefault(require("path"));
|
||||
exports.BACKEND_ROOT = path_1.default.resolve(__dirname, "..");
|
||||
exports.MODULE_ROOT = path_1.default.resolve(exports.BACKEND_ROOT, "..");
|
||||
@@ -90,6 +90,7 @@ exports.AUTORUN_ANNOTATIONS_DIR = path_1.default.resolve(exports.DATA_DIR, "auto
|
||||
exports.AUTORUN_ANNOTATIONS_FILE = path_1.default.resolve(exports.AUTORUN_ANNOTATIONS_DIR, "annotations.json");
|
||||
exports.AUTORUN_GENERATOR_DIR = path_1.default.resolve(exports.DATA_DIR, "autorun_generators");
|
||||
exports.AUTORUN_GENERATOR_HISTORY_FILE = path_1.default.resolve(exports.AUTORUN_GENERATOR_DIR, "history.json");
|
||||
exports.SHARED_LLM_CONNECTION_FILE = path_1.default.resolve(exports.DATA_DIR, "shared_llm_connection.json");
|
||||
exports.PROMPTS_DIR = path_1.default.resolve(exports.MODULE_ROOT, "prompts");
|
||||
exports.REPORTS_DIR = path_1.default.resolve(exports.MODULE_ROOT, "reports");
|
||||
exports.EVAL_DATASETS_DIR = path_1.default.resolve(exports.MODULE_ROOT, "eval_cases");
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildSharedLlmConfigRouter = buildSharedLlmConfigRouter;
|
||||
const express_1 = require("express");
|
||||
const config_1 = require("../config");
|
||||
const http_1 = require("../utils/http");
|
||||
const files_1 = require("../utils/files");
|
||||
const path_1 = __importDefault(require("path"));
|
||||
function sanitizeString(value, fallback) {
|
||||
if (typeof value !== "string") {
|
||||
return fallback;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : fallback;
|
||||
}
|
||||
function sanitizeNumber(value, fallback) {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string" && value.trim().length > 0) {
|
||||
const parsed = Number(value);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
function buildFallbackRecord() {
|
||||
return {
|
||||
schema_version: "shared_llm_connection_v1",
|
||||
updated_at: "",
|
||||
connection: {
|
||||
llmProvider: "local",
|
||||
model: "qwen2.5-14b-instruct-1m",
|
||||
baseUrl: "http://127.0.0.1:1234/v1",
|
||||
temperature: 0,
|
||||
maxOutputTokens: 900
|
||||
}
|
||||
};
|
||||
}
|
||||
function loadSharedRecord() {
|
||||
const fallback = buildFallbackRecord();
|
||||
const parsed = (0, files_1.readJsonFile)(config_1.SHARED_LLM_CONNECTION_FILE, null);
|
||||
if (!parsed || typeof parsed !== "object" || !("connection" in parsed) || !parsed.connection) {
|
||||
return null;
|
||||
}
|
||||
const connection = parsed.connection;
|
||||
return {
|
||||
schema_version: "shared_llm_connection_v1",
|
||||
updated_at: sanitizeString(parsed.updated_at, ""),
|
||||
connection: {
|
||||
llmProvider: connection.llmProvider === "local" ? "local" : "openai",
|
||||
model: sanitizeString(connection.model, fallback.connection.model),
|
||||
baseUrl: sanitizeString(connection.baseUrl, fallback.connection.baseUrl),
|
||||
temperature: sanitizeNumber(connection.temperature, fallback.connection.temperature),
|
||||
maxOutputTokens: Math.max(1, Math.trunc(sanitizeNumber(connection.maxOutputTokens, fallback.connection.maxOutputTokens)))
|
||||
}
|
||||
};
|
||||
}
|
||||
function buildSharedLlmConfigRouter() {
|
||||
const router = (0, express_1.Router)();
|
||||
router.get("/api/llm/shared-connection", (_req, res, next) => {
|
||||
try {
|
||||
const record = loadSharedRecord();
|
||||
(0, http_1.ok)(res, {
|
||||
ok: true,
|
||||
connection: record?.connection ?? null,
|
||||
updated_at: record?.updated_at ?? null,
|
||||
exists: Boolean(record)
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
router.post("/api/llm/shared-connection", (req, res, next) => {
|
||||
try {
|
||||
const body = (req.body ?? {});
|
||||
const fallback = buildFallbackRecord();
|
||||
const record = {
|
||||
schema_version: "shared_llm_connection_v1",
|
||||
updated_at: new Date().toISOString(),
|
||||
connection: {
|
||||
llmProvider: body.llmProvider === "local" ? "local" : "openai",
|
||||
model: sanitizeString(body.model, fallback.connection.model),
|
||||
baseUrl: sanitizeString(body.baseUrl, fallback.connection.baseUrl),
|
||||
temperature: sanitizeNumber(body.temperature, fallback.connection.temperature),
|
||||
maxOutputTokens: Math.max(1, Math.trunc(sanitizeNumber(body.maxOutputTokens, fallback.connection.maxOutputTokens)))
|
||||
}
|
||||
};
|
||||
(0, files_1.ensureDir)(path_1.default.dirname(config_1.SHARED_LLM_CONNECTION_FILE));
|
||||
(0, files_1.writeJsonFile)(config_1.SHARED_LLM_CONNECTION_FILE, record);
|
||||
(0, http_1.ok)(res, {
|
||||
ok: true,
|
||||
connection: record.connection,
|
||||
updated_at: record.updated_at
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
return router;
|
||||
}
|
||||
+2
@@ -15,6 +15,7 @@ const eval_1 = require("./routes/eval");
|
||||
const history_1 = require("./routes/history");
|
||||
const normalize_1 = require("./routes/normalize");
|
||||
const presets_1 = require("./routes/presets");
|
||||
const sharedLlmConfig_1 = require("./routes/sharedLlmConfig");
|
||||
const testConnection_1 = require("./routes/testConnection");
|
||||
const inMemoryRuntimeAdapter_1 = require("./runtime/inMemoryRuntimeAdapter");
|
||||
const assistantService_1 = require("./services/assistantService");
|
||||
@@ -59,6 +60,7 @@ function createApp() {
|
||||
});
|
||||
});
|
||||
app.use((0, testConnection_1.buildTestConnectionRouter)(openaiClient));
|
||||
app.use((0, sharedLlmConfig_1.buildSharedLlmConfigRouter)());
|
||||
app.use((0, normalize_1.buildNormalizeRouter)(services));
|
||||
app.use((0, eval_1.buildEvalRouter)(services));
|
||||
app.use((0, assistant_1.buildAssistantRouter)(services));
|
||||
|
||||
@@ -1345,7 +1345,7 @@ function hasSelectedObjectInventoryCue(text) {
|
||||
}
|
||||
function hasSelectedObjectInventoryProvenanceSignal(text) {
|
||||
return (hasSelectedObjectInventoryCue(text) &&
|
||||
/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(text));
|
||||
/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(text));
|
||||
}
|
||||
function hasSelectedObjectInventoryPurchaseDocumentsSignal(text) {
|
||||
return (hasSelectedObjectInventoryCue(text) &&
|
||||
@@ -1353,7 +1353,7 @@ function hasSelectedObjectInventoryPurchaseDocumentsSignal(text) {
|
||||
}
|
||||
function hasInventoryProvenanceSignalV2(text) {
|
||||
const hasItemCue = /(?:товар|номенклатур|sku|item|product|остат(?:ок|ки)|склад)/iu.test(text);
|
||||
const hasSupplierCue = /(?:от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|товар|позицию))?|где\s+куплено|кто\s+(?:нам\s+)?поставил|кем\s+поставлен|поставщик|supplier|vendor)/iu.test(text);
|
||||
const hasSupplierCue = /(?:от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|товар|позицию))?|где\s+куплено|кто\s+(?:нам\s+)?поставил|кем\s+поставлен|поставщик|supplier|vendor)/iu.test(text);
|
||||
const hasPurchaseCue = /(?:куплен(?:ы|а|о)?|закупк|происхождени|откуда|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|товар|позицию))?|где\s+куплено|когда\s+был\s+куплен|когда\s+куплен|дата\s+закупк|кто\s+(?:нам\s+)?поставил|кем\s+поставлен|поставлен(?:ы|а)?|purchase\s+provenance|purchase\s+date)/iu.test(text);
|
||||
return hasItemCue && hasSupplierCue && hasPurchaseCue;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ function hasSelectedObjectInventoryFollowupSignal(text) {
|
||||
if (!/(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции)/iu.test(text)) {
|
||||
return false;
|
||||
}
|
||||
return /(?:у\s+кого\s+купили|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|товар|позицию))?|где\s+куплено|кто\s+(?:поставил|продал)|кому\s+(?:продали|реализовали)|когда\s+(?:примерно\s+)?купили|по\s+каким\s+документам\s+.*купили)/iu.test(text);
|
||||
return /(?:у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|товар|позицию))?|где\s+куплено|кто\s+(?:поставил|продал)|кому\s+(?:продали|реализовали)|когда\s+(?:примерно\s+)?купили|по\s+каким\s+документам\s+.*купили)/iu.test(text);
|
||||
}
|
||||
function hasDocsOrBankSignal(text) {
|
||||
return /(?:док(?:и|умент|ументы|ументов)|docs?|documents?|банк|выписк|платеж|платёж|оплат|поступлен|списан|транзак|transactions?|bank\s+ops|bank\s+operations?)/iu.test(text);
|
||||
|
||||
@@ -25,7 +25,7 @@ function hasSameDateHint(text) {
|
||||
return /(?:на\s+ту\s+же\s+дат[ауеы]|на\s+эту\s+же\s+дат[ауеы]|на\s+эту\s+дат[ауеы]|эту\s+дат[ауеы]|та\s+же\s+дата|same\s+date|as\s+of\s+same\s+date|the\s+same\s+date)/iu.test(String(text ?? ""));
|
||||
}
|
||||
function hasExplicitPeriodLiteral(text) {
|
||||
return /\b(?:19|20)\d{2}(?:[./-](?:0?[1-9]|1[0-2]))?\b/.test(String(text ?? ""));
|
||||
return /(?:^|[^\d*×xх])((?:19|20)\d{2}(?:[./-](?:0?[1-9]|1[0-2]))?)(?=$|[^\d*×xх])/iu.test(String(text ?? ""));
|
||||
}
|
||||
function hasExplicitCurrentDateHint(text) {
|
||||
return /(?:на\s+текущ(?:ую|ая|ий|ее|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодняшн(?:юю|ий|ей|ем|его)\s+дат(?:у|а|е|ой|ою)|на\s+сегодня|сегодня|на\s+текущ(?:ий|ую)\s+момент|today|as\s+of\s+today|current\s+date|as\s+of\s+current\s+date)/iu.test(String(text ?? ""));
|
||||
@@ -257,7 +257,7 @@ function hasSelectedObjectInventorySignal(text) {
|
||||
return /(?:по\s+выбранному\s+объекту|for\s+selected\s+object)/iu.test(String(text ?? ""));
|
||||
}
|
||||
function hasInventorySupplierFollowupCue(text) {
|
||||
return /(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(String(text ?? ""));
|
||||
return /(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(String(text ?? ""));
|
||||
}
|
||||
function hasInventoryPurchaseDocumentsFollowupCue(text) {
|
||||
return /(?:по\s+каким\s+документам\s+(?:это|его|этот\s+товар|эту\s+позицию)\s+купили|по\s+каким\s+документам\s+(?:был\s+)?куплен|какими\s+документами\s+(?:это|его|этот\s+товар|эту\s+позицию)\s+купили|какими\s+документами\s+(?:был\s+)?куплен|покажи\s+документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|документы\s+по\s+(?:этой\s+позиции|этому\s+товару|ней|нему)|purchase\s+documents|documents\s+of\s+purchase|through\s+which\s+documents)/iu.test(String(text ?? ""));
|
||||
|
||||
Reference in New Issue
Block a user