@salesforcedevs/docs-components 0.0.38-chat → 0.0.39-chat
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
CHANGED
|
@@ -137,7 +137,7 @@ body.chat-closed .global-header {
|
|
|
137
137
|
/* Chat container */
|
|
138
138
|
.chat-container {
|
|
139
139
|
height: 100vh;
|
|
140
|
-
width:
|
|
140
|
+
width: 700px;
|
|
141
141
|
background-color: #fff;
|
|
142
142
|
box-shadow: -8px 0 32px rgb(0 0 0 / 12%), -2px 0 8px rgb(0 0 0 / 8%);
|
|
143
143
|
transform: translateX(100%);
|
|
@@ -176,7 +176,11 @@
|
|
|
176
176
|
</template>
|
|
177
177
|
<template lwc:else>
|
|
178
178
|
<template lwc:if={message.isHTML}>
|
|
179
|
-
<div
|
|
179
|
+
<div
|
|
180
|
+
class="message-text html-content"
|
|
181
|
+
lwc:dom="manual"
|
|
182
|
+
data-message-id={message.id}
|
|
183
|
+
></div>
|
|
180
184
|
</template>
|
|
181
185
|
<template lwc:else>
|
|
182
186
|
<p class="message-text">{message.text}</p>
|
|
@@ -55,11 +55,14 @@ export default class Chat extends LightningElement {
|
|
|
55
55
|
private messageIdCounter: number = 0;
|
|
56
56
|
|
|
57
57
|
// API Configuration
|
|
58
|
-
private static readonly API_URL =
|
|
58
|
+
private static readonly API_URL =
|
|
59
|
+
"https://276ca7264b79.ngrok-free.app/api/llm/search";
|
|
59
60
|
private static readonly MAX_RESULTS = 5;
|
|
60
|
-
|
|
61
|
+
|
|
61
62
|
// Development mode flag - set to true if running in development
|
|
62
|
-
private static readonly IS_DEVELOPMENT =
|
|
63
|
+
private static readonly IS_DEVELOPMENT =
|
|
64
|
+
window.location.hostname === "localhost" ||
|
|
65
|
+
window.location.hostname === "127.0.0.1";
|
|
63
66
|
|
|
64
67
|
// localStorage keys for persisting messages and open state
|
|
65
68
|
private static readonly STORAGE_KEY = "doc-chat-messages";
|
|
@@ -93,24 +96,31 @@ export default class Chat extends LightningElement {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
private renderHTMLMessages() {
|
|
96
|
-
console.log(
|
|
97
|
-
console.log(
|
|
98
|
-
console.log(
|
|
99
|
-
|
|
99
|
+
console.log("=== renderHTMLMessages called ===");
|
|
100
|
+
console.log("All messages:", this.messages);
|
|
101
|
+
console.log(
|
|
102
|
+
"HTML messages:",
|
|
103
|
+
this.messages.filter((msg) => msg.isHTML)
|
|
104
|
+
);
|
|
105
|
+
|
|
100
106
|
// Use a simpler selector approach
|
|
101
|
-
const htmlMessageElements = this.template.querySelectorAll(
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
const htmlMessageElements = this.template.querySelectorAll(
|
|
108
|
+
".html-content[data-message-id]"
|
|
109
|
+
);
|
|
110
|
+
console.log("Found HTML elements:", htmlMessageElements.length);
|
|
111
|
+
|
|
104
112
|
htmlMessageElements.forEach((element) => {
|
|
105
|
-
const messageId = element.getAttribute(
|
|
106
|
-
console.log(
|
|
107
|
-
|
|
108
|
-
const message = this.messages.find(
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
const messageId = element.getAttribute("data-message-id");
|
|
114
|
+
console.log("Processing element with ID:", messageId);
|
|
115
|
+
|
|
116
|
+
const message = this.messages.find(
|
|
117
|
+
(msg) => msg.id === messageId && msg.isHTML
|
|
118
|
+
);
|
|
119
|
+
console.log("Found message:", message);
|
|
120
|
+
|
|
111
121
|
if (message) {
|
|
112
|
-
console.log(
|
|
113
|
-
console.log(
|
|
122
|
+
console.log("Setting innerHTML for message:", messageId);
|
|
123
|
+
console.log("Content:", message.text);
|
|
114
124
|
element.innerHTML = message.text;
|
|
115
125
|
}
|
|
116
126
|
});
|
|
@@ -146,11 +156,17 @@ export default class Chat extends LightningElement {
|
|
|
146
156
|
|
|
147
157
|
// Helper method to get HTML content for a message
|
|
148
158
|
getMessageHTML(messageId: string): string {
|
|
149
|
-
const message = this.messages.find(
|
|
150
|
-
|
|
159
|
+
const message = this.messages.find(
|
|
160
|
+
(msg) => msg.id === messageId && msg.isHTML
|
|
161
|
+
);
|
|
162
|
+
return message ? message.text : "";
|
|
151
163
|
}
|
|
152
164
|
|
|
153
|
-
private addMessage(
|
|
165
|
+
private addMessage(
|
|
166
|
+
text: string,
|
|
167
|
+
sender: "user" | "assistant",
|
|
168
|
+
isHTML: boolean = false
|
|
169
|
+
) {
|
|
154
170
|
const timestamp = new Date();
|
|
155
171
|
const message: ChatMessage = {
|
|
156
172
|
id: `msg-${this.messageIdCounter++}`,
|
|
@@ -323,7 +339,7 @@ export default class Chat extends LightningElement {
|
|
|
323
339
|
private async callChatAPI(userMessage: string): Promise<string> {
|
|
324
340
|
try {
|
|
325
341
|
// Format chat history for API (exclude the current user message)
|
|
326
|
-
const chatHistory = this.messages.map(msg => ({
|
|
342
|
+
const chatHistory = this.messages.map((msg) => ({
|
|
327
343
|
text: msg.text,
|
|
328
344
|
sender: msg.sender
|
|
329
345
|
}));
|
|
@@ -334,71 +350,93 @@ export default class Chat extends LightningElement {
|
|
|
334
350
|
chatHistory: chatHistory
|
|
335
351
|
};
|
|
336
352
|
|
|
337
|
-
console.log(
|
|
353
|
+
console.log("Sending API request:", requestBody);
|
|
338
354
|
|
|
339
355
|
const response = await fetch(Chat.API_URL, {
|
|
340
|
-
method:
|
|
356
|
+
method: "POST",
|
|
341
357
|
headers: {
|
|
342
|
-
|
|
343
|
-
|
|
358
|
+
"Content-Type": "application/json",
|
|
359
|
+
"ngrok-skip-browser-warning": "true" // Skip ngrok browser warning
|
|
344
360
|
},
|
|
345
361
|
body: JSON.stringify(requestBody)
|
|
346
362
|
});
|
|
347
363
|
|
|
348
364
|
if (!response.ok) {
|
|
349
365
|
const errorText = await response.text();
|
|
350
|
-
console.error(
|
|
351
|
-
throw new Error(
|
|
366
|
+
console.error("API Error Response:", errorText);
|
|
367
|
+
throw new Error(
|
|
368
|
+
`API request failed with status: ${response.status}`
|
|
369
|
+
);
|
|
352
370
|
}
|
|
353
371
|
|
|
354
372
|
const data = await response.json();
|
|
355
|
-
console.log(
|
|
356
|
-
|
|
373
|
+
console.log("API Response:", data);
|
|
374
|
+
|
|
357
375
|
// Handle the new API response format with "data" field
|
|
358
|
-
const responseText =
|
|
359
|
-
|
|
360
|
-
|
|
376
|
+
const responseText =
|
|
377
|
+
data.data ||
|
|
378
|
+
data.answer ||
|
|
379
|
+
data.text ||
|
|
380
|
+
data.response ||
|
|
381
|
+
data.result ||
|
|
382
|
+
data.message;
|
|
383
|
+
console.log("Response Text:", responseText);
|
|
384
|
+
|
|
361
385
|
if (!responseText) {
|
|
362
|
-
console.warn(
|
|
363
|
-
return
|
|
386
|
+
console.warn("No response text found in API response:", data);
|
|
387
|
+
return "I received your message but couldn't generate a proper response.";
|
|
364
388
|
}
|
|
365
|
-
|
|
389
|
+
|
|
366
390
|
return responseText;
|
|
367
|
-
|
|
368
391
|
} catch (error) {
|
|
369
|
-
console.error(
|
|
370
|
-
|
|
392
|
+
console.error("Chat API error:", error);
|
|
393
|
+
|
|
371
394
|
// Provide more specific error messages for CORS issues
|
|
372
|
-
if (error instanceof TypeError && error.message.includes(
|
|
373
|
-
return
|
|
395
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
396
|
+
return "I'm having trouble connecting to the service. This might be a CORS configuration issue. Please check your internet connection and try again.";
|
|
374
397
|
}
|
|
375
|
-
|
|
376
|
-
if (
|
|
377
|
-
|
|
398
|
+
|
|
399
|
+
if (
|
|
400
|
+
error instanceof Error &&
|
|
401
|
+
(error.message.includes("CORS") ||
|
|
402
|
+
error.message.includes("cross-origin"))
|
|
403
|
+
) {
|
|
404
|
+
return "I'm having trouble connecting due to browser security restrictions. Please ask your administrator to configure CORS headers on the backend API.";
|
|
378
405
|
}
|
|
379
|
-
|
|
380
|
-
return
|
|
406
|
+
|
|
407
|
+
return "I apologize, but I'm having trouble connecting to the service right now. Please try again later.";
|
|
381
408
|
}
|
|
382
409
|
}
|
|
383
410
|
|
|
384
411
|
private parseMarkdownToHTML(text: string): string {
|
|
385
412
|
// Convert markdown-like text to HTML
|
|
386
413
|
let html = text;
|
|
387
|
-
|
|
388
|
-
console.log(
|
|
389
|
-
|
|
414
|
+
|
|
415
|
+
console.log("Original text:", text);
|
|
416
|
+
|
|
390
417
|
// First, convert markdown links [text](url) to HTML links
|
|
391
|
-
|
|
392
|
-
|
|
418
|
+
// Make sure links are absolute (relative to root) by adding leading slash if missing
|
|
419
|
+
html = html.replace(
|
|
420
|
+
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
421
|
+
(match, linkText, url) => {
|
|
422
|
+
// If URL doesn't start with http, https, or /, make it absolute
|
|
423
|
+
let absoluteUrl = url;
|
|
424
|
+
if (!url.startsWith('http') && !url.startsWith('/')) {
|
|
425
|
+
absoluteUrl = '/' + url;
|
|
426
|
+
}
|
|
427
|
+
return `<a href="${absoluteUrl}" target="_blank" rel="noopener noreferrer" class="chat-link">${linkText}</a>`;
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
|
|
393
431
|
// Handle numbered lists with descriptions (more complex pattern)
|
|
394
432
|
// Split into lines to process each line
|
|
395
|
-
const lines = html.split(
|
|
433
|
+
const lines = html.split("\n");
|
|
396
434
|
const processedLines = [];
|
|
397
435
|
let inList = false;
|
|
398
|
-
|
|
436
|
+
|
|
399
437
|
for (let i = 0; i < lines.length; i++) {
|
|
400
438
|
const line = lines[i];
|
|
401
|
-
|
|
439
|
+
|
|
402
440
|
// Check if this is a numbered list item (starts with number and dot)
|
|
403
441
|
if (/^\d+\.\s+/.test(line)) {
|
|
404
442
|
if (!inList) {
|
|
@@ -406,50 +444,52 @@ export default class Chat extends LightningElement {
|
|
|
406
444
|
inList = true;
|
|
407
445
|
}
|
|
408
446
|
// Extract the content after the number
|
|
409
|
-
const content = line.replace(/^\d+\.\s+/,
|
|
447
|
+
const content = line.replace(/^\d+\.\s+/, "");
|
|
410
448
|
processedLines.push(`<li>${content}`);
|
|
411
|
-
|
|
449
|
+
|
|
412
450
|
// Check if next line is indented (description)
|
|
413
451
|
if (i + 1 < lines.length && /^\s{2,}/.test(lines[i + 1])) {
|
|
414
452
|
i++; // Skip to next line
|
|
415
453
|
const description = lines[i].trim();
|
|
416
|
-
processedLines.push(
|
|
454
|
+
processedLines.push(
|
|
455
|
+
`<br><span class="chat-description">${description}</span></li>`
|
|
456
|
+
);
|
|
417
457
|
} else {
|
|
418
|
-
processedLines.push(
|
|
458
|
+
processedLines.push("</li>");
|
|
419
459
|
}
|
|
420
|
-
} else if (line.trim() ===
|
|
460
|
+
} else if (line.trim() === "" && inList) {
|
|
421
461
|
// Empty line might end the list
|
|
422
462
|
continue;
|
|
423
463
|
} else {
|
|
424
|
-
if (inList && line.trim() !==
|
|
425
|
-
processedLines.push(
|
|
464
|
+
if (inList && line.trim() !== "") {
|
|
465
|
+
processedLines.push("</ol>");
|
|
426
466
|
inList = false;
|
|
427
467
|
}
|
|
428
|
-
if (line.trim() !==
|
|
468
|
+
if (line.trim() !== "") {
|
|
429
469
|
processedLines.push(line);
|
|
430
470
|
}
|
|
431
471
|
}
|
|
432
472
|
}
|
|
433
|
-
|
|
473
|
+
|
|
434
474
|
// Close any open list
|
|
435
475
|
if (inList) {
|
|
436
|
-
processedLines.push(
|
|
476
|
+
processedLines.push("</ol>");
|
|
437
477
|
}
|
|
438
|
-
|
|
439
|
-
html = processedLines.join(
|
|
440
|
-
|
|
478
|
+
|
|
479
|
+
html = processedLines.join("<br>");
|
|
480
|
+
|
|
441
481
|
// Clean up extra breaks
|
|
442
|
-
html = html.replace(/<br><br>/g,
|
|
443
|
-
html = html.replace(/^<br>/,
|
|
444
|
-
|
|
482
|
+
html = html.replace(/<br><br>/g, "<br>");
|
|
483
|
+
html = html.replace(/^<br>/, "");
|
|
484
|
+
|
|
445
485
|
// Convert **bold** to <strong>
|
|
446
|
-
html = html.replace(/\*\*([^*]+)\*\*/g,
|
|
447
|
-
|
|
486
|
+
html = html.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
487
|
+
|
|
448
488
|
// Convert *italic* to <em>
|
|
449
|
-
html = html.replace(/\*([^*]+)\*/g,
|
|
450
|
-
|
|
451
|
-
console.log(
|
|
452
|
-
|
|
489
|
+
html = html.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
490
|
+
|
|
491
|
+
console.log("Processed HTML:", html);
|
|
492
|
+
|
|
453
493
|
return html;
|
|
454
494
|
}
|
|
455
495
|
|
|
@@ -459,15 +499,15 @@ export default class Chat extends LightningElement {
|
|
|
459
499
|
// Convert markdown to HTML for rich content display
|
|
460
500
|
const htmlContent = this.parseMarkdownToHTML(response);
|
|
461
501
|
this.addMessage(htmlContent, "assistant", true); // true indicates HTML content
|
|
462
|
-
|
|
502
|
+
|
|
463
503
|
// Force a re-render after adding the message
|
|
464
504
|
setTimeout(() => {
|
|
465
505
|
this.renderHTMLMessages();
|
|
466
506
|
}, 100);
|
|
467
507
|
} catch (error) {
|
|
468
|
-
console.error(
|
|
508
|
+
console.error("Error getting assistant response:", error);
|
|
469
509
|
this.addMessage(
|
|
470
|
-
|
|
510
|
+
"I apologize, but I encountered an error while processing your request. Please try again.",
|
|
471
511
|
"assistant"
|
|
472
512
|
);
|
|
473
513
|
} finally {
|