@retrivora-ai/rag-engine 2.0.8 → 2.1.2
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/dist/handlers/index.js +113 -75
- package/dist/handlers/index.mjs +113 -75
- package/dist/index.js +19 -12
- package/dist/index.mjs +19 -12
- package/dist/server.js +113 -75
- package/dist/server.mjs +113 -75
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +22 -22
- package/src/core/Pipeline.ts +3 -3
- package/src/llm/providers/GeminiProvider.ts +4 -4
- package/src/llm/providers/GroqProvider.ts +16 -8
- package/src/llm/providers/OpenAIProvider.ts +16 -8
- package/src/llm/providers/QwenProvider.ts +16 -8
- package/src/llm/providers/UniversalLLMAdapter.ts +56 -36
- package/src/rendering/IntentClassifier.ts +3 -3
- package/src/rendering/rules/Rule1SpecificInfoRule.ts +1 -1
- package/src/utils/ProductExtractor.ts +4 -3
- package/src/utils/UITransformer.ts +12 -0
package/dist/server.js
CHANGED
|
@@ -594,6 +594,7 @@ function cleanApiKeyOverride(apiKeyOverride) {
|
|
|
594
594
|
async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
595
595
|
const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
|
|
596
596
|
const provider = resolveProvider(req.model);
|
|
597
|
+
console.log(`[LLM Gateway Router] Dispatching chat request: model=${req.model}, provider=${provider}, hasGroqKey=${Boolean(process.env.GROQ_API_KEY)}, hasGeminiKey=${Boolean(process.env.GROQ_API_KEY || process.env.GEMINI_API_KEY)}, hasHFToken=${Boolean(process.env.HF_TOKEN)}`);
|
|
597
598
|
try {
|
|
598
599
|
switch (provider) {
|
|
599
600
|
case "groq":
|
|
@@ -612,6 +613,10 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
612
613
|
throw new Error(`Unsupported LLM provider for model: ${req.model}`);
|
|
613
614
|
}
|
|
614
615
|
} catch (error) {
|
|
616
|
+
console.error(`[LLM Gateway Router] Provider '${provider}' failed for model '${req.model}':`, {
|
|
617
|
+
message: error.message,
|
|
618
|
+
stack: error.stack
|
|
619
|
+
});
|
|
615
620
|
if (/rate[- ]?limit|429|exhausted/i.test(error.message)) {
|
|
616
621
|
const isGroqKey = process.env.GROQ_API_KEY || effectiveKey && effectiveKey.startsWith("gsk_");
|
|
617
622
|
const reqModelLower = req.model.toLowerCase();
|
|
@@ -619,7 +624,8 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
619
624
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to secondary Groq model (llama-3.3-70b-versatile)...`);
|
|
620
625
|
try {
|
|
621
626
|
return await handleGroqRequest(__spreadProps(__spreadValues({}, req), { model: "llama-3.3-70b-versatile" }), effectiveKey);
|
|
622
|
-
} catch (
|
|
627
|
+
} catch (fErr) {
|
|
628
|
+
console.error("[LLM Gateway] Fallback groq/llama-3.3-70b-versatile failed:", fErr.message);
|
|
623
629
|
}
|
|
624
630
|
}
|
|
625
631
|
const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
|
|
@@ -627,14 +633,16 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
627
633
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Google Gemini (gemini-2.5-flash)...`);
|
|
628
634
|
try {
|
|
629
635
|
return await handleGeminiRequest(__spreadProps(__spreadValues({}, req), { model: "gemini-2.5-flash" }), effectiveKey);
|
|
630
|
-
} catch (
|
|
636
|
+
} catch (fErr) {
|
|
637
|
+
console.error("[LLM Gateway] Fallback gemini-2.5-flash failed:", fErr.message);
|
|
631
638
|
}
|
|
632
639
|
}
|
|
633
640
|
if (provider !== "huggingface" && (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY)) {
|
|
634
641
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Hugging Face (Qwen/Qwen2.5-Coder-32B-Instruct)...`);
|
|
635
642
|
try {
|
|
636
643
|
return await handleHuggingFaceChatRequest(__spreadProps(__spreadValues({}, req), { model: "Qwen/Qwen2.5-Coder-32B-Instruct" }), effectiveKey);
|
|
637
|
-
} catch (
|
|
644
|
+
} catch (fErr) {
|
|
645
|
+
console.error("[LLM Gateway] Fallback HuggingFace Qwen failed:", fErr.message);
|
|
638
646
|
}
|
|
639
647
|
}
|
|
640
648
|
if (provider !== "openai" && process.env.OPENAI_API_KEY) {
|
|
@@ -3489,12 +3497,13 @@ var OpenAIProvider = class {
|
|
|
3489
3497
|
role: "system",
|
|
3490
3498
|
content: buildSystemContent(basePrompt, context)
|
|
3491
3499
|
};
|
|
3500
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3501
|
+
role: m.role || "user",
|
|
3502
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3503
|
+
}));
|
|
3492
3504
|
const formattedMessages = [
|
|
3493
3505
|
systemMessage,
|
|
3494
|
-
...
|
|
3495
|
-
role: m.role,
|
|
3496
|
-
content: m.content
|
|
3497
|
-
}))
|
|
3506
|
+
...safeMessages
|
|
3498
3507
|
];
|
|
3499
3508
|
const completion = await this.client.chat.completions.create({
|
|
3500
3509
|
model: this.llmConfig.model,
|
|
@@ -3513,12 +3522,13 @@ var OpenAIProvider = class {
|
|
|
3513
3522
|
role: "system",
|
|
3514
3523
|
content: buildSystemContent(basePrompt, context)
|
|
3515
3524
|
};
|
|
3525
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3526
|
+
role: m.role || "user",
|
|
3527
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3528
|
+
}));
|
|
3516
3529
|
const formattedMessages = [
|
|
3517
3530
|
systemMessage,
|
|
3518
|
-
...
|
|
3519
|
-
role: m.role,
|
|
3520
|
-
content: m.content
|
|
3521
|
-
}))
|
|
3531
|
+
...safeStreamMessages
|
|
3522
3532
|
];
|
|
3523
3533
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
3524
3534
|
model: this.llmConfig.model,
|
|
@@ -4049,9 +4059,9 @@ var GeminiProvider = class {
|
|
|
4049
4059
|
* - Messages must strictly alternate between `user` and `model`.
|
|
4050
4060
|
*/
|
|
4051
4061
|
buildGeminiContents(messages) {
|
|
4052
|
-
return messages.filter((m) => m.role !== "system").map((m) => ({
|
|
4062
|
+
return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
|
|
4053
4063
|
role: m.role === "assistant" ? "model" : "user",
|
|
4054
|
-
parts: [{ text: m.content }]
|
|
4064
|
+
parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
|
|
4055
4065
|
}));
|
|
4056
4066
|
}
|
|
4057
4067
|
// -------------------------------------------------------------------------
|
|
@@ -4254,12 +4264,13 @@ var GroqProvider = class {
|
|
|
4254
4264
|
role: "system",
|
|
4255
4265
|
content: buildSystemContent(basePrompt, context)
|
|
4256
4266
|
};
|
|
4267
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4268
|
+
role: m.role || "user",
|
|
4269
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4270
|
+
}));
|
|
4257
4271
|
const formattedMessages = [
|
|
4258
4272
|
systemMessage,
|
|
4259
|
-
...
|
|
4260
|
-
role: m.role,
|
|
4261
|
-
content: m.content
|
|
4262
|
-
}))
|
|
4273
|
+
...safeMessages
|
|
4263
4274
|
];
|
|
4264
4275
|
const completion = await this.client.chat.completions.create({
|
|
4265
4276
|
model: this.llmConfig.model,
|
|
@@ -4278,12 +4289,13 @@ var GroqProvider = class {
|
|
|
4278
4289
|
role: "system",
|
|
4279
4290
|
content: buildSystemContent(basePrompt, context)
|
|
4280
4291
|
};
|
|
4292
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4293
|
+
role: m.role || "user",
|
|
4294
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4295
|
+
}));
|
|
4281
4296
|
const formattedMessages = [
|
|
4282
4297
|
systemMessage,
|
|
4283
|
-
...
|
|
4284
|
-
role: m.role,
|
|
4285
|
-
content: m.content
|
|
4286
|
-
}))
|
|
4298
|
+
...safeStreamMessages
|
|
4287
4299
|
];
|
|
4288
4300
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4289
4301
|
model: this.llmConfig.model,
|
|
@@ -4412,12 +4424,13 @@ var QwenProvider = class {
|
|
|
4412
4424
|
role: "system",
|
|
4413
4425
|
content: buildSystemContent(basePrompt, context)
|
|
4414
4426
|
};
|
|
4427
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4428
|
+
role: m.role || "user",
|
|
4429
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4430
|
+
}));
|
|
4415
4431
|
const formattedMessages = [
|
|
4416
4432
|
systemMessage,
|
|
4417
|
-
...
|
|
4418
|
-
role: m.role,
|
|
4419
|
-
content: m.content
|
|
4420
|
-
}))
|
|
4433
|
+
...safeMessages
|
|
4421
4434
|
];
|
|
4422
4435
|
const completion = await this.client.chat.completions.create({
|
|
4423
4436
|
model: this.llmConfig.model,
|
|
@@ -4436,12 +4449,13 @@ var QwenProvider = class {
|
|
|
4436
4449
|
role: "system",
|
|
4437
4450
|
content: buildSystemContent(basePrompt, context)
|
|
4438
4451
|
};
|
|
4452
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4453
|
+
role: m.role || "user",
|
|
4454
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4455
|
+
}));
|
|
4439
4456
|
const formattedMessages = [
|
|
4440
4457
|
systemMessage,
|
|
4441
|
-
...
|
|
4442
|
-
role: m.role,
|
|
4443
|
-
content: m.content
|
|
4444
|
-
}))
|
|
4458
|
+
...safeStreamMessages
|
|
4445
4459
|
];
|
|
4446
4460
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4447
4461
|
model: this.llmConfig.model,
|
|
@@ -4621,14 +4635,18 @@ var UniversalLLMAdapter = class {
|
|
|
4621
4635
|
});
|
|
4622
4636
|
}
|
|
4623
4637
|
async chat(messages, context) {
|
|
4624
|
-
var _a2, _b, _c;
|
|
4638
|
+
var _a2, _b, _c, _d, _e;
|
|
4625
4639
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4640
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4641
|
+
role: m.role || "user",
|
|
4642
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4643
|
+
}));
|
|
4626
4644
|
const formattedMessages = [
|
|
4627
4645
|
{ role: "system", content: `${this.systemPrompt}
|
|
4628
4646
|
|
|
4629
4647
|
Context:
|
|
4630
4648
|
${context != null ? context : "None"}` },
|
|
4631
|
-
...
|
|
4649
|
+
...safeMessages
|
|
4632
4650
|
];
|
|
4633
4651
|
let payload;
|
|
4634
4652
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4646,8 +4664,15 @@ ${context != null ? context : "None"}` },
|
|
|
4646
4664
|
temperature: this.temperature
|
|
4647
4665
|
};
|
|
4648
4666
|
}
|
|
4649
|
-
|
|
4650
|
-
|
|
4667
|
+
try {
|
|
4668
|
+
const { data: data2 } = await this.http.post(path2, payload);
|
|
4669
|
+
const extractPath2 = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
4670
|
+
const result2 = (_c = resolvePath(data2, extractPath2)) != null ? _c : extractContent(data2);
|
|
4671
|
+
if (result2 !== void 0) {
|
|
4672
|
+
return String(result2);
|
|
4673
|
+
}
|
|
4674
|
+
} catch (httpErr) {
|
|
4675
|
+
console.warn(`[UniversalLLMAdapter] Direct HTTP POST to ${this.baseUrl}${path2} failed (${httpErr.message}). Attempting in-process gateway dispatch fallback...`);
|
|
4651
4676
|
const _g2 = globalThis;
|
|
4652
4677
|
let dispatch = _g2.__retrivoraDispatchChat;
|
|
4653
4678
|
if (typeof dispatch !== "function") {
|
|
@@ -4662,28 +4687,22 @@ ${context != null ? context : "None"}` },
|
|
|
4662
4687
|
}
|
|
4663
4688
|
}
|
|
4664
4689
|
if (typeof dispatch === "function") {
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
return content;
|
|
4675
|
-
}
|
|
4676
|
-
throw new Error(`[UniversalLLMAdapter] In-process dispatch returned empty content for model: ${this.model}`);
|
|
4677
|
-
} catch (dispatchErr) {
|
|
4678
|
-
throw dispatchErr;
|
|
4690
|
+
const res = await dispatch({
|
|
4691
|
+
model: this.model,
|
|
4692
|
+
messages: formattedMessages,
|
|
4693
|
+
max_tokens: this.maxTokens,
|
|
4694
|
+
temperature: this.temperature
|
|
4695
|
+
}, this.apiKey);
|
|
4696
|
+
const content = extractContent(res == null ? void 0 : res.response);
|
|
4697
|
+
if (content !== void 0) {
|
|
4698
|
+
return content;
|
|
4679
4699
|
}
|
|
4680
|
-
} else {
|
|
4681
|
-
throw new Error(`[UniversalLLMAdapter] In-process gateway dispatch not registered. Direct self-referential HTTP calls to ${this.baseUrl} are disabled on Vercel to prevent HTTP 508 Loop Detected.`);
|
|
4682
4700
|
}
|
|
4701
|
+
throw httpErr;
|
|
4683
4702
|
}
|
|
4684
4703
|
const { data } = await this.http.post(path2, payload);
|
|
4685
|
-
const extractPath = (
|
|
4686
|
-
const result = (
|
|
4704
|
+
const extractPath = (_d = this.opts.responseExtractPath) != null ? _d : "choices[0].message.content";
|
|
4705
|
+
const result = (_e = resolvePath(data, extractPath)) != null ? _e : extractContent(data);
|
|
4687
4706
|
if (result === void 0) {
|
|
4688
4707
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
4689
4708
|
}
|
|
@@ -4700,12 +4719,16 @@ ${context != null ? context : "None"}` },
|
|
|
4700
4719
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4701
4720
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4702
4721
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
4722
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4723
|
+
role: m.role || "user",
|
|
4724
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4725
|
+
}));
|
|
4703
4726
|
const formattedMessages = [
|
|
4704
4727
|
{ role: "system", content: `${this.systemPrompt}
|
|
4705
4728
|
|
|
4706
4729
|
Context:
|
|
4707
4730
|
${context != null ? context : "None"}` },
|
|
4708
|
-
...
|
|
4731
|
+
...safeMessages
|
|
4709
4732
|
];
|
|
4710
4733
|
let payload;
|
|
4711
4734
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4821,7 +4844,7 @@ ${context != null ? context : "None"}` },
|
|
|
4821
4844
|
});
|
|
4822
4845
|
}
|
|
4823
4846
|
async embed(text) {
|
|
4824
|
-
var _a2, _b, _c, _d;
|
|
4847
|
+
var _a2, _b, _c, _d, _e;
|
|
4825
4848
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4826
4849
|
let payload;
|
|
4827
4850
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4835,8 +4858,15 @@ ${context != null ? context : "None"}` },
|
|
|
4835
4858
|
input: text
|
|
4836
4859
|
};
|
|
4837
4860
|
}
|
|
4838
|
-
|
|
4839
|
-
|
|
4861
|
+
try {
|
|
4862
|
+
const { data: data2 } = await this.http.post(path2, payload);
|
|
4863
|
+
const extractPath2 = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
4864
|
+
const vector2 = resolvePath(data2, extractPath2);
|
|
4865
|
+
if (Array.isArray(vector2)) {
|
|
4866
|
+
return vector2;
|
|
4867
|
+
}
|
|
4868
|
+
} catch (httpErr) {
|
|
4869
|
+
console.warn(`[UniversalLLMAdapter] Direct HTTP embedding POST to ${this.baseUrl}${path2} failed (${httpErr.message}). Attempting in-process gateway dispatch fallback...`);
|
|
4840
4870
|
const _g2 = globalThis;
|
|
4841
4871
|
let dispatch = _g2.__retrivoraDispatchEmbedding;
|
|
4842
4872
|
if (typeof dispatch !== "function") {
|
|
@@ -4851,24 +4881,18 @@ ${context != null ? context : "None"}` },
|
|
|
4851
4881
|
}
|
|
4852
4882
|
}
|
|
4853
4883
|
if (typeof dispatch === "function") {
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
return res.data[0].embedding;
|
|
4861
|
-
}
|
|
4862
|
-
throw new Error(`[UniversalLLMAdapter] In-process embedding dispatch returned invalid vector for model: ${this.model}`);
|
|
4863
|
-
} catch (dispatchErr) {
|
|
4864
|
-
throw dispatchErr;
|
|
4884
|
+
const res = await dispatch({
|
|
4885
|
+
model: this.model,
|
|
4886
|
+
input: text
|
|
4887
|
+
}, this.apiKey);
|
|
4888
|
+
if ((_d = (_c = res == null ? void 0 : res.data) == null ? void 0 : _c[0]) == null ? void 0 : _d.embedding) {
|
|
4889
|
+
return res.data[0].embedding;
|
|
4865
4890
|
}
|
|
4866
|
-
} else {
|
|
4867
|
-
throw new Error(`[UniversalLLMAdapter] In-process gateway dispatch not registered. Direct self-referential HTTP calls to ${this.baseUrl} are disabled on Vercel to prevent HTTP 508 Loop Detected.`);
|
|
4868
4891
|
}
|
|
4892
|
+
throw httpErr;
|
|
4869
4893
|
}
|
|
4870
4894
|
const { data } = await this.http.post(path2, payload);
|
|
4871
|
-
const extractPath = (
|
|
4895
|
+
const extractPath = (_e = this.opts.embedExtractPath) != null ? _e : "data[0].embedding";
|
|
4872
4896
|
const vector = resolvePath(data, extractPath);
|
|
4873
4897
|
if (!Array.isArray(vector)) {
|
|
4874
4898
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -6849,8 +6873,8 @@ var IntentClassifier = class {
|
|
|
6849
6873
|
}
|
|
6850
6874
|
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
6851
6875
|
static isInformationLookup(query) {
|
|
6852
|
-
if (/^(what|who|explain|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of)\s+/i.test(query)) {
|
|
6853
|
-
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
6876
|
+
if (/^(what|who|explain|explore|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(query)) {
|
|
6877
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top 10|top selling|best|chart|graph|plot|breakdown|analytics)\b/i.test(query)) {
|
|
6854
6878
|
return true;
|
|
6855
6879
|
}
|
|
6856
6880
|
}
|
|
@@ -6887,7 +6911,7 @@ var Rule1SpecificInfoRule = class {
|
|
|
6887
6911
|
}
|
|
6888
6912
|
evaluate(context, intent) {
|
|
6889
6913
|
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6890
|
-
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|define|where|when|why|meaning of)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6914
|
+
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|explore|define|where|when|why|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6891
6915
|
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
6892
6916
|
if (isFactQuery && isNonVisual) {
|
|
6893
6917
|
return {
|
|
@@ -8174,6 +8198,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
8174
8198
|
}
|
|
8175
8199
|
static chooseAutomaticVisualization(data, profile, query) {
|
|
8176
8200
|
if (profile.records.length === 0) return null;
|
|
8201
|
+
const q = query.toLowerCase().trim();
|
|
8202
|
+
const isExplicitVisualOrAnalytic = /\b(chart|graph|plot|visualize|trend|monthly|revenue|top\s*\d+|breakdown|analytics|compare|versus|vs\.?|histogram|pie|bar|line|distribution|percentage|share|summary of metrics)\b/i.test(q);
|
|
8203
|
+
if (!isExplicitVisualOrAnalytic) {
|
|
8204
|
+
return null;
|
|
8205
|
+
}
|
|
8177
8206
|
if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
|
|
8178
8207
|
return this.transformToLineChart(profile);
|
|
8179
8208
|
}
|
|
@@ -8289,6 +8318,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8289
8318
|
return Array.from(categories);
|
|
8290
8319
|
}
|
|
8291
8320
|
static getProductCategory(item) {
|
|
8321
|
+
if (!item) return null;
|
|
8292
8322
|
const meta = item.metadata || {};
|
|
8293
8323
|
const metadataCategory = resolveMetadataValue(meta, "category");
|
|
8294
8324
|
if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
|
|
@@ -8405,6 +8435,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8405
8435
|
if (!fields.has(normalized)) fields.set(normalized, clean);
|
|
8406
8436
|
};
|
|
8407
8437
|
data.forEach((item) => {
|
|
8438
|
+
if (!item) return;
|
|
8408
8439
|
Object.keys(item.metadata || {}).forEach(addField);
|
|
8409
8440
|
for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
|
|
8410
8441
|
addField(match[1]);
|
|
@@ -8521,6 +8552,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8521
8552
|
return true;
|
|
8522
8553
|
}
|
|
8523
8554
|
static extractStockQuantity(item) {
|
|
8555
|
+
if (!item) return null;
|
|
8524
8556
|
const meta = item.metadata || {};
|
|
8525
8557
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
8526
8558
|
const numericStock = this.toFiniteNumber(stockValue);
|
|
@@ -9781,7 +9813,10 @@ ${context}`;
|
|
|
9781
9813
|
Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
|
|
9782
9814
|
|
|
9783
9815
|
History:
|
|
9784
|
-
${history.map((m) =>
|
|
9816
|
+
${(history || []).map((m) => {
|
|
9817
|
+
var _a2;
|
|
9818
|
+
return `${(m == null ? void 0 : m.role) || "user"}: ${(_a2 = m == null ? void 0 : m.content) != null ? _a2 : ""}`;
|
|
9819
|
+
}).join("\n")}
|
|
9785
9820
|
|
|
9786
9821
|
New Question: ${question}
|
|
9787
9822
|
|
|
@@ -9805,8 +9840,11 @@ Optimized Search Query:`;
|
|
|
9805
9840
|
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
9806
9841
|
try {
|
|
9807
9842
|
const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
|
|
9808
|
-
if (sources.length === 0) return [];
|
|
9809
|
-
const context = sources.map((s) =>
|
|
9843
|
+
if (!sources || sources.length === 0) return [];
|
|
9844
|
+
const context = sources.map((s) => {
|
|
9845
|
+
var _a2;
|
|
9846
|
+
return (_a2 = s == null ? void 0 : s.content) != null ? _a2 : "";
|
|
9847
|
+
}).join("\n\n---\n\n");
|
|
9810
9848
|
const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
|
|
9811
9849
|
Focus on questions that can be answered by the context.
|
|
9812
9850
|
Keep each question under 10 words and make them very specific to the content.
|