Skip to content

Commit c83e2c6

Browse files
author
Jicheng Lu
committed
refine chat
1 parent 2541311 commit c83e2c6

File tree

12 files changed

+215
-137
lines changed

12 files changed

+215
-137
lines changed

src/lib/helpers/http.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function skipLoader(config) {
6060
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/page', 'g'),
6161
new RegExp('http(s*)://(.*?)/knowledge/(.*?)/search', 'g'),
6262
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/create', 'g'),
63-
new RegExp('http(s*)://(.*?)/knowledge/document/(.*?)/page', 'g')
63+
new RegExp('http(s*)://(.*?)/knowledge/document/(.*?)/page', 'g'),
6464
];
6565

6666
const putRegexes = [
@@ -80,7 +80,8 @@ function skipLoader(config) {
8080
new RegExp('http(s*)://(.*?)/address/options(.*?)', 'g'),
8181
new RegExp('http(s*)://(.*?)/conversation/(.*?)/files/(.*?)', 'g'),
8282
new RegExp('http(s*)://(.*?)/llm-provider/(.*?)/models', 'g'),
83-
new RegExp('http(s*)://(.*?)/knowledge/vector/collections', 'g')
83+
new RegExp('http(s*)://(.*?)/knowledge/vector/collections', 'g'),
84+
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/exist', 'g')
8485
];
8586

8687
if (config.method === 'post' && postRegexes.some(regex => regex.test(config.url || ''))) {

src/lib/scss/custom/pages/_chat.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,10 @@
704704
min-width: 50px;
705705
border-radius: 10px;
706706
}
707+
708+
.link-option:hover {
709+
text-decoration: underline;
710+
}
707711
}
708712

709713
.complex-option-container {
@@ -750,8 +754,8 @@
750754
border-radius: 10px;
751755
}
752756

753-
.btn-link {
754-
background-color: unset !important;
757+
.link-option:hover {
758+
text-decoration: underline;
755759
}
756760
}
757761
}

src/lib/scss/custom/pages/_knowledgebase.scss

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
}
6767

6868
.confidence-box {
69-
width: 40%;
69+
width: 100%;
7070
}
7171

7272
.input-text {
@@ -375,3 +375,24 @@
375375
}
376376
}
377377
}
378+
379+
380+
.vector-collection-create-container {
381+
.collection-input {
382+
.invalid-input {
383+
border-color: var(--bs-danger);
384+
}
385+
386+
.collection-note {
387+
display: flex;
388+
}
389+
390+
.valid {
391+
justify-content: flex-end;
392+
}
393+
394+
.invalid {
395+
justify-content: space-between;
396+
}
397+
}
398+
}

src/lib/services/api-endpoints.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export const endpoints = {
5959
loggingStateLogUrl: `${host}/logger/conversation/{conversationId}/state-log`,
6060

6161
// knowledge base
62-
vectorKnowledgeCollectionsUrl: `${host}/knowledge/vector/collections`,
62+
vectorCollectionExistUrl: `${host}/knowledge/vector/{collection}/exist`,
63+
vectorCollectionsUrl: `${host}/knowledge/vector/collections`,
6364
vectorKnowledgePageListUrl: `${host}/knowledge/vector/{collection}/page`,
6465
vectorKnowledgeSearchUrl: `${host}/knowledge/vector/{collection}/search`,
6566
vectorKnowledgeCreateUrl: `${host}/knowledge/vector/{collection}/create`,

src/lib/services/knowledge-base-service.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,26 @@ import { replaceUrl } from '$lib/helpers/http.js';
22
import { endpoints } from './api-endpoints.js';
33
import axios from 'axios';
44

5+
6+
/**
7+
* @param {string} collection
8+
* @returns {Promise<boolean>}
9+
*/
10+
export async function existVectorCollection(collection) {
11+
const url = replaceUrl(endpoints.vectorCollectionExistUrl, {
12+
collection: collection
13+
});
14+
15+
const response = await axios.get(url);
16+
return response.data;
17+
}
18+
519
/**
620
* @param {string} type
721
* @returns {Promise<string[]>}
822
*/
923
export async function getVectorKnowledgeCollections(type) {
10-
const url = endpoints.vectorKnowledgeCollectionsUrl;
24+
const url = endpoints.vectorCollectionsUrl;
1125
const response = await axios.get(url, {
1226
params: {
1327
type: type

src/routes/chat/[agentId]/[conversationId]/chat-box.svelte

Lines changed: 81 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@
278278
async function refresh() {
279279
// trigger UI render
280280
dialogs = dialogs?.map(item => { return { ...item }; }) || [];
281+
lastBotMsg = null;
282+
await tick();
281283
lastBotMsg = findLastBotMessage(dialogs);
282284
lastMsg = dialogs.slice(-1)[0];
283285
assignMessageDisclaimer(dialogs)
@@ -415,6 +417,7 @@
415417
/** @param {import('$conversationTypes').ConversationMessageDeleteModel} data */
416418
function onConversationMessageDeleted(data) {
417419
if (!!!data?.message_id) return;
420+
418421
truncateDialogs(data.message_id);
419422
}
420423
@@ -863,7 +866,7 @@
863866
}
864867
865868
/** @param {string} messageId */
866-
function truncateDialogs(messageId) {
869+
async function truncateDialogs(messageId) {
867870
const foundIdx = dialogs.findIndex(x => x.message_id === messageId);
868871
if (foundIdx < 0) return false;
869872
dialogs = dialogs.filter((x, idx) => idx < foundIdx);
@@ -1137,85 +1140,85 @@
11371140
<div class="chat-conversation p-3">
11381141
<ul class="list-unstyled mb-0">
11391142
{#each Object.entries(groupedDialogs) as [createDate, dialogGroup]}
1140-
<li>
1141-
<div class="chat-day-title">
1142-
<span class="title">{createDate}</span>
1143-
</div>
1144-
</li>
1145-
{#each dialogGroup as message}
1146-
<li id={'test_k' + message.message_id} class:right={USER_SENDERS.includes(message.sender?.role)}>
1147-
<div class="conv-msg-container">
1148-
{#if USER_SENDERS.includes(message.sender?.role)}
1149-
<div class="msg-container">
1150-
<div
1151-
tabindex="0"
1152-
aria-label="user-msg-to-log"
1153-
role="link"
1154-
on:keydown={() => {}}
1155-
on:click={() => directToLog(message.message_id)}
1156-
>
1157-
<div class="ctext-wrap user-msg"
1158-
class:clickable={!isLite && (isLoadPersistLog || isLoadInstantLog)}
1159-
id={`user-msg-${message.message_id}`}
1160-
>
1161-
<div class="text-start fw-bold">{@html replaceNewLine(message.text)}</div>
1143+
<li>
1144+
<div class="chat-day-title">
1145+
<span class="title">{createDate}</span>
1146+
</div>
1147+
</li>
1148+
{#each dialogGroup as message}
1149+
<li id={'test_k' + message.message_id} class:right={USER_SENDERS.includes(message.sender?.role)}>
1150+
<div class="conv-msg-container">
1151+
{#if USER_SENDERS.includes(message.sender?.role)}
1152+
<div class="msg-container">
1153+
<div
1154+
tabindex="0"
1155+
aria-label="user-msg-to-log"
1156+
role="link"
1157+
on:keydown={() => {}}
1158+
on:click={() => directToLog(message.message_id)}
1159+
>
1160+
<div class="ctext-wrap user-msg"
1161+
class:clickable={!isLite && (isLoadPersistLog || isLoadInstantLog)}
1162+
id={`user-msg-${message.message_id}`}
1163+
>
1164+
<div class="text-start fw-bold">{@html replaceNewLine(message.text)}</div>
1165+
</div>
1166+
<p class="chat-time mb-0 float-end">
1167+
<i class="bx bx-time-five align-middle me-1" />
1168+
{utcToLocal(message.created_at, 'hh:mm A')}
1169+
</p>
1170+
</div>
1171+
{#if !!message.post_action_disclaimer}
1172+
<RcDisclaimer content={message.post_action_disclaimer} />
1173+
{/if}
1174+
{#if !!message.is_chat_message || !!message.has_message_files}
1175+
<MessageFileGallery
1176+
messageId={message?.message_id}
1177+
galleryStyles={'justify-content: flex-end;'}
1178+
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.User)}
1179+
/>
1180+
{/if}
11621181
</div>
1163-
<p class="chat-time mb-0 float-end">
1164-
<i class="bx bx-time-five align-middle me-1" />
1165-
{utcToLocal(message.created_at, 'hh:mm A')}
1166-
</p>
1182+
{#if !isLite}
1183+
<Dropdown>
1184+
<DropdownToggle class="dropdown-toggle" tag="span" disabled={isSendingMsg || isThinking || disableAction}>
1185+
<i class="bx bx-dots-vertical-rounded" />
1186+
</DropdownToggle>
1187+
<DropdownMenu class="dropdown-menu-end">
1188+
<DropdownItem on:click={(e) => editMessage(e, message)}>Edit</DropdownItem>
1189+
<DropdownItem on:click={(e) => resendMessage(e, message)}>Resend</DropdownItem>
1190+
<DropdownItem on:click={(e) => deleteMessage(e, message.message_id)}>Delete</DropdownItem>
1191+
</DropdownMenu>
1192+
</Dropdown>
1193+
{/if}
1194+
{:else}
1195+
<div class="cicon-wrap align-content-end">
1196+
{#if message.sender.role == UserRole.Client}
1197+
<img src="images/users/user-dummy.jpg" class="rounded-circle avatar-sm" style="margin-bottom: -15px;" alt="avatar">
1198+
{:else}
1199+
<img src={PUBLIC_LIVECHAT_ENTRY_ICON} class="rounded-circle avatar-sm" style="margin-bottom: -15px;" alt="avatar">
1200+
{/if}
1201+
</div>
1202+
<div class="msg-container">
1203+
<RcMessage message={message} />
1204+
{#if message?.message_id === lastBotMsg?.message_id}
1205+
<AudioSpeaker
1206+
id={message?.message_id}
1207+
text={message?.rich_content?.message?.text || message?.text}
1208+
/>
1209+
{/if}
1210+
{#if !!message.is_chat_message || !!message.has_message_files}
1211+
<MessageFileGallery
1212+
messageId={message?.message_id}
1213+
galleryStyles={'justify-content: flex-start;'}
1214+
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.Bot)}
1215+
/>
1216+
{/if}
1217+
</div>
1218+
{/if}
11671219
</div>
1168-
{#if !!message.post_action_disclaimer}
1169-
<RcDisclaimer content={message.post_action_disclaimer} />
1170-
{/if}
1171-
{#if !!message.is_chat_message || !!message.has_message_files}
1172-
<MessageFileGallery
1173-
messageId={message?.message_id}
1174-
galleryStyles={'justify-content: flex-end;'}
1175-
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.User)}
1176-
/>
1177-
{/if}
1178-
</div>
1179-
{#if !isLite}
1180-
<Dropdown>
1181-
<DropdownToggle class="dropdown-toggle" tag="span" disabled={isSendingMsg || isThinking || disableAction}>
1182-
<i class="bx bx-dots-vertical-rounded" />
1183-
</DropdownToggle>
1184-
<DropdownMenu class="dropdown-menu-end">
1185-
<DropdownItem on:click={(e) => editMessage(e, message)}>Edit</DropdownItem>
1186-
<DropdownItem on:click={(e) => resendMessage(e, message)}>Resend</DropdownItem>
1187-
<DropdownItem on:click={(e) => deleteMessage(e, message.message_id)}>Delete</DropdownItem>
1188-
</DropdownMenu>
1189-
</Dropdown>
1190-
{/if}
1191-
{:else}
1192-
<div class="cicon-wrap align-content-end">
1193-
{#if message.sender.role == UserRole.Client}
1194-
<img src="images/users/user-dummy.jpg" class="rounded-circle avatar-sm" style="margin-bottom: -15px;" alt="avatar">
1195-
{:else}
1196-
<img src={PUBLIC_LIVECHAT_ENTRY_ICON} class="rounded-circle avatar-sm" style="margin-bottom: -15px;" alt="avatar">
1197-
{/if}
1198-
</div>
1199-
<div class="msg-container">
1200-
<RcMessage message={message} />
1201-
{#if message?.message_id === lastBotMsg?.message_id}
1202-
<AudioSpeaker
1203-
id={message?.message_id}
1204-
text={message?.rich_content?.message?.text || message?.text}
1205-
/>
1206-
{/if}
1207-
{#if !!message.is_chat_message || !!message.has_message_files}
1208-
<MessageFileGallery
1209-
messageId={message?.message_id}
1210-
galleryStyles={'justify-content: flex-start;'}
1211-
fetchFiles={() => getConversationFiles(params.conversationId, message.message_id, FileSourceType.Bot)}
1212-
/>
1213-
{/if}
1214-
</div>
1215-
{/if}
1216-
</div>
1217-
</li>
1218-
{/each}
1220+
</li>
1221+
{/each}
12191222
{/each}
12201223
12211224
{#if isThinking}

src/routes/chat/[agentId]/[conversationId]/rich-content/rc-complex-options.svelte

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@
7272
*/
7373
function handleClickOption(e, option) {
7474
e.preventDefault();
75+
76+
if (option.type === ElementType.Web && option.url) {
77+
window.open(option.url);
78+
return;
79+
}
80+
7581
innerConfirm(option?.title, option?.payload);
7682
}
7783
@@ -111,23 +117,13 @@
111117
{#if card.options?.length > 0}
112118
<div class="card-option-group">
113119
{#each card.options as option, i (i)}
114-
{#if option.type === ElementType.Web && option.url}
115-
<button
116-
class={`btn btn-sm btn-link m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
117-
disabled={disabled}
118-
on:click={() => window.open(option.url)}
119-
>
120-
{option.title}
121-
</button>
122-
{:else}
123-
<button
124-
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
125-
disabled={disabled}
126-
on:click={(e) => handleClickOption(e, option)}
127-
>
128-
{option.title}
129-
</button>
130-
{/if}
120+
<button
121+
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
122+
disabled={disabled}
123+
on:click={(e) => handleClickOption(e, option)}
124+
>
125+
<span class={`${option.type === ElementType.Web && option.url ? 'link-option' : ''}`}>{option.title}</span>
126+
</button>
131127
{/each}
132128
</div>
133129
{/if}

src/routes/chat/[agentId]/[conversationId]/rich-content/rc-plain-options.svelte

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
function handleClickOption(e, option, index) {
7575
e.preventDefault();
7676
77+
if (option.type === ElementType.Web && option.url) {
78+
window.open(option.url);
79+
return;
80+
}
81+
7782
if (!isMultiSelect) {
7883
innerConfirm(option?.title, option?.payload);
7984
} else {
@@ -146,26 +151,17 @@
146151
{#if plainOptions || fileOption}
147152
<div class="plain-option-container center-option">
148153
{#each plainOptions as option, index}
149-
{#if option.type === ElementType.Web && option.url}
150-
<button
151-
class={`btn btn-sm btn-link m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
152-
disabled={disabled}
153-
in:fade={{ duration: duration }}
154-
on:click={() => window.open(option.url)}
155-
>
156-
{option.title}
157-
</button>
158-
{:else}
159-
<button
160-
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
161-
class:active={!!option.isClicked}
162-
disabled={disabled}
163-
in:fade={{ duration: duration }}
164-
on:click={(e) => handleClickOption(e, option, index)}
165-
>
154+
<button
155+
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
156+
class:active={!!option.isClicked}
157+
disabled={disabled}
158+
in:fade={{ duration: duration }}
159+
on:click={(e) => handleClickOption(e, option, index)}
160+
>
161+
<span class={`${option.type === ElementType.Web && option.url ? 'link-option' : ''}`}>
166162
{option.title}
167-
</button>
168-
{/if}
163+
</span>
164+
</button>
169165
{/each}
170166
{#if plainOptions && isMultiSelect}
171167
<button

0 commit comments

Comments
 (0)