@iola_adm/iola-cli 0.1.82 → 0.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli.js +57 -5
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -6140,7 +6140,7 @@ function pickDirectDataItem(question, dataContext, rows) {
|
|
|
6140
6140
|
function itemNameHasNumber(item, number) {
|
|
6141
6141
|
const name = String(item.name || item.title || item.fns_full_name || item.fns_short_name || "").toLocaleLowerCase("ru-RU");
|
|
6142
6142
|
const escaped = String(number).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6143
|
-
return new RegExp(`(?:№\\s*${escaped}|\\b(?:школа|сош|лицей|гимназия|сад|детский сад)\\s*№?\\s*${escaped}\\b)`, "iu").test(name);
|
|
6143
|
+
return new RegExp(`(?:№\\s*${escaped}(?!\\d)|\\b(?:школа|сош|лицей|гимназия|сад|детский сад)\\s*№?\\s*${escaped}\\b)`, "iu").test(name);
|
|
6144
6144
|
}
|
|
6145
6145
|
|
|
6146
6146
|
function formatDirectDataField(field, item) {
|
|
@@ -6148,7 +6148,7 @@ function formatDirectDataField(field, item) {
|
|
|
6148
6148
|
if (field === "head") {
|
|
6149
6149
|
const head = item.head || item.fns_head_name;
|
|
6150
6150
|
if (!head) return "";
|
|
6151
|
-
const position = item.fns_head_position || (item.layer === "kindergartens" ? "заведующий" : "директор");
|
|
6151
|
+
const position = capitalizeFirst(item.fns_head_position || (item.layer === "kindergartens" ? "заведующий" : "директор"));
|
|
6152
6152
|
return `${position}: ${head} (${name}).`;
|
|
6153
6153
|
}
|
|
6154
6154
|
if (field === "website") return item.website ? `Сайт: ${item.website}` : `Сайт для ${name} в открытых данных не указан.`;
|
|
@@ -6171,6 +6171,11 @@ function getDirectDataItemName(item) {
|
|
|
6171
6171
|
return item.name || item.title || item.fns_short_name || item.fns_full_name || "организация";
|
|
6172
6172
|
}
|
|
6173
6173
|
|
|
6174
|
+
function capitalizeFirst(value) {
|
|
6175
|
+
const text = String(value || "");
|
|
6176
|
+
return text ? `${text[0].toLocaleUpperCase("ru-RU")}${text.slice(1)}` : text;
|
|
6177
|
+
}
|
|
6178
|
+
|
|
6174
6179
|
async function resolveUsableAiProfile(config, options = {}) {
|
|
6175
6180
|
const explicit = Boolean(options.profile || options.provider);
|
|
6176
6181
|
const providerConfig = resolveAiProfile(config, options);
|
|
@@ -6589,6 +6594,7 @@ async function buildDataContext(question) {
|
|
|
6589
6594
|
try {
|
|
6590
6595
|
const context = await callPublicMcpTool("layer_answer_context", { question, limit: 8 });
|
|
6591
6596
|
const layerMap = Object.fromEntries((context.results || []).map((result) => [result.layer?.id || result.layer, result.items || []]));
|
|
6597
|
+
await enrichLayerMapWithExactMatches(layerMap, question, queryTerms, patterns);
|
|
6592
6598
|
return {
|
|
6593
6599
|
source: "remote-mcp",
|
|
6594
6600
|
contract_version: context.contract_version,
|
|
@@ -6626,6 +6632,31 @@ async function buildDataContext(question) {
|
|
|
6626
6632
|
}
|
|
6627
6633
|
}
|
|
6628
6634
|
|
|
6635
|
+
async function enrichLayerMapWithExactMatches(layerMap, question, queryTerms, patterns) {
|
|
6636
|
+
if (!patterns.numbers?.length) return;
|
|
6637
|
+
const targetLayerIds = resolveTargetLayerIds(patterns);
|
|
6638
|
+
await Promise.all(targetLayerIds.map(async (layer) => {
|
|
6639
|
+
try {
|
|
6640
|
+
const result = await queryLayer(layer, { query: question, terms: queryTerms, patterns, limit: 8 });
|
|
6641
|
+
const existing = layerMap[layer] || [];
|
|
6642
|
+
const existingKeys = new Set(existing.map((item) => item.inn || item.name || item.fns_short_name).filter(Boolean));
|
|
6643
|
+
const exact = (result.items || []).filter((item) =>
|
|
6644
|
+
patterns.numbers.some((number) => itemNameHasNumber(item, number)));
|
|
6645
|
+
layerMap[layer] = [
|
|
6646
|
+
...exact.filter((item) => {
|
|
6647
|
+
const key = item.inn || item.name || item.fns_short_name;
|
|
6648
|
+
if (!key || existingKeys.has(key)) return false;
|
|
6649
|
+
existingKeys.add(key);
|
|
6650
|
+
return true;
|
|
6651
|
+
}),
|
|
6652
|
+
...existing,
|
|
6653
|
+
];
|
|
6654
|
+
} catch {
|
|
6655
|
+
// Remote MCP remains the primary source; exact local/API enrichment is best effort.
|
|
6656
|
+
}
|
|
6657
|
+
}));
|
|
6658
|
+
}
|
|
6659
|
+
|
|
6629
6660
|
function resolveTargetLayerIds(patterns = {}) {
|
|
6630
6661
|
const knownLayers = Object.keys(DATASETS);
|
|
6631
6662
|
if (patterns.targetLayers?.length) return patterns.targetLayers.filter((layer) => DATASETS[layer]);
|
|
@@ -6723,13 +6754,16 @@ function extractSearchTerms(question) {
|
|
|
6723
6754
|
|
|
6724
6755
|
function extractStructuredPatterns(question) {
|
|
6725
6756
|
const normalized = question.toLocaleLowerCase("ru-RU");
|
|
6726
|
-
const numbers = [...new Set([
|
|
6757
|
+
const numbers = [...new Set([
|
|
6758
|
+
...[...normalized.matchAll(/\b\d{1,3}\b/g)].map((match) => match[0]),
|
|
6759
|
+
...extractOrdinalNumbers(normalized),
|
|
6760
|
+
])];
|
|
6727
6761
|
const inns = [...new Set([...normalized.matchAll(/\b\d{10,12}\b/g)].map((match) => match[0]))];
|
|
6728
6762
|
const targetLayers = [];
|
|
6729
|
-
if (/(
|
|
6763
|
+
if (/(школ|сош|лице|гимнази)/iu.test(normalized)) {
|
|
6730
6764
|
targetLayers.push("schools");
|
|
6731
6765
|
}
|
|
6732
|
-
if (/(
|
|
6766
|
+
if (/(детсад|детск|сад|сады|доу|мбдоу)/iu.test(normalized)) {
|
|
6733
6767
|
targetLayers.push("kindergartens");
|
|
6734
6768
|
}
|
|
6735
6769
|
const streetMatches = [
|
|
@@ -6741,6 +6775,24 @@ function extractStructuredPatterns(question) {
|
|
|
6741
6775
|
return { numbers, inns, streets, targetLayers: [...new Set(targetLayers)] };
|
|
6742
6776
|
}
|
|
6743
6777
|
|
|
6778
|
+
function extractOrdinalNumbers(normalizedQuestion) {
|
|
6779
|
+
const ordinals = [
|
|
6780
|
+
["1", "(?:перв(?:ая|ой|ую|ое|ого|ом|ым|ых)?|первую)"],
|
|
6781
|
+
["2", "(?:втор(?:ая|ой|ую|ое|ого|ом|ым|ых)?|вторую)"],
|
|
6782
|
+
["3", "(?:трет(?:ья|ий|ью|ье|ьего|ьем|ьим|ьих)?|третью)"],
|
|
6783
|
+
["4", "четверт(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6784
|
+
["5", "пят(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6785
|
+
["6", "шест(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6786
|
+
["7", "седьм(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6787
|
+
["8", "восьм(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6788
|
+
["9", "девят(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6789
|
+
["10", "десят(?:ая|ой|ую|ое|ого|ом|ым|ых)?"],
|
|
6790
|
+
];
|
|
6791
|
+
return ordinals
|
|
6792
|
+
.filter(([, pattern]) => new RegExp(`(^|[^а-яёa-z])${pattern}(?=$|[^а-яёa-z])`, "iu").test(normalizedQuestion))
|
|
6793
|
+
.map(([number]) => number);
|
|
6794
|
+
}
|
|
6795
|
+
|
|
6744
6796
|
function cleanupPattern(value) {
|
|
6745
6797
|
return value
|
|
6746
6798
|
.replace(/\b(школа|школы|сад|детский|детские|сады|лицей|гимназия|контакты|телефон|адрес|найди|покажи)\b/giu, " ")
|