Skip to content

Commit 1672a56

Browse files
author
Jicheng Lu
committed
refine chat images
1 parent 0a7c083 commit 1672a56

File tree

10 files changed

+183
-78
lines changed

10 files changed

+183
-78
lines changed

src/lib/helpers/store.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,22 @@ export const conversationUserMessageStore = createConversationUserMessageStore()
133133

134134

135135
const createConversationUserAttachmentStore = () => {
136+
const { subscribe, set } = writable({ accepted_files: [] });
137+
136138
return {
137139
reset: () => {
138140
localStorage.removeItem(conversationUserAttachmentKey);
141+
set({ accepted_files: [] });
139142
},
140143
get: () => {
141144
const json = localStorage.getItem(conversationUserAttachmentKey);
142145
return json ? JSON.parse(json) : {};
143146
},
144147
put: (value) => {
145148
localStorage.setItem(conversationUserAttachmentKey, JSON.stringify(value));
146-
}
149+
set(value);
150+
},
151+
subscribe
147152
}
148153
};
149154

src/lib/helpers/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ IRichContent.prototype.text;
278278
* @property {string} post_action_disclaimer - The message disclaimer.
279279
* @property {string} data - The message data.
280280
* @property {Date} created_at - The message sent time.
281+
* @property {boolean} is_load_images - Check of the message needs to load images.
281282
*/
282283

283284
/**

src/lib/scss/custom/components/_file.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,12 @@ $file-screen-max-width: 500px;
7474
.add-file-icon {
7575
font-size: 2em;
7676
}
77+
}
78+
79+
.chat-file-upload-gallery {
80+
margin: 5px 10px;
81+
display: flex;
82+
flex-wrap: wrap;
83+
gap: 3px;
84+
justify-content: center;
7785
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,19 +387,26 @@
387387
background-color: var(--#{$prefix}light) !important;
388388
border-color: var(--#{$prefix}light) !important;
389389
resize: none;
390+
padding-right: 1rem;
391+
}
392+
393+
.chat-input-image {
394+
padding-right: 4em;
390395
}
391396

392397
.chat-input-links {
393398
position: absolute;
394-
right: 16px;
399+
right: 3px;
395400
top: 50%;
396401
transform: translateY(-50%);
402+
width: 3em;
397403
li {
398-
a {
404+
span {
399405
font-size: 16px;
400406
line-height: 36px;
401407
padding: 0px 4px;
402408
display: inline-block;
409+
color: var(--bs-primary);
403410
}
404411
}
405412
}

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

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import { EditorType, SenderAction, UserRole } from '$lib/helpers/enums';
2828
import RichContent from './richContent/rich-content.svelte';
2929
import RcDisclaimer from './richContent/rc-disclaimer.svelte';
30-
import ChatImage from './chatImage/chat-image.svelte';
30+
import MessageImageGallery from './chatImage/message-image-gallery.svelte';
31+
import ChatImageUploader from './chatImage/chat-image-uploader.svelte';
32+
import ChatImageGallery from './chatImage/chat-image-gallery.svelte';
3133
import ContentLog from './contentLogs/content-log.svelte';
3234
import _ from "lodash";
3335
import { Pane, Splitpanes } from 'svelte-splitpanes';
@@ -36,6 +38,7 @@
3638
import "sweetalert2/src/sweetalert2.scss";
3739
import moment from 'moment';
3840
41+
3942
const options = {
4043
scrollbars: {
4144
visibility: 'auto',
@@ -216,6 +219,7 @@
216219
// trigger UI render
217220
dialogs = dialogs?.map(item => { return { ...item }; }) || [];
218221
lastBotMsg = findLastBotMessage(dialogs);
222+
assignLoadImageMessages(dialogs);
219223
assignMessageDisclaimer(dialogs)
220224
groupedDialogs = groupDialogs(dialogs);
221225
await tick();
@@ -233,6 +237,29 @@
233237
});
234238
}
235239
240+
/** @param {import('$types').ChatResponseModel[]} dialogs */
241+
function assignLoadImageMessages(dialogs) {
242+
if (!!!dialogs) return;
243+
244+
for (let idx = 0; idx < dialogs.length; idx++) {
245+
const curMsg = dialogs[idx];
246+
if (!USER_SENDERS.includes(curMsg?.sender?.role || '')) {
247+
continue;
248+
}
249+
250+
const botMsgId = dialogs.findLastIndex((x, i) => i < idx && !USER_SENDERS.includes(x.sender?.role || ''));
251+
if (botMsgId > -1 && dialogs[botMsgId]?.rich_content?.editor === EditorType.File) {
252+
const userMsgs = dialogs.filter(x => x.message_id === curMsg.message_id && USER_SENDERS.includes(x.sender?.role || ''));
253+
if (userMsgs?.length > 1) {
254+
const userMsg = userMsgs.slice(-1)[0];
255+
userMsg.is_load_images = true;
256+
} else {
257+
curMsg.is_load_images = true;
258+
}
259+
}
260+
}
261+
}
262+
236263
/** @param {import('$types').ChatResponseModel[]} dialogs */
237264
function assignMessageDisclaimer(dialogs) {
238265
if (!!!dialogs) return null;
@@ -278,13 +305,7 @@
278305
}
279306
280307
const attachments = conversationUserAttachmentStore.get();
281-
const files = attachments?.accepted_files || [];
282-
return files.map((/** @type {any} */ f) => {
283-
return {
284-
...f,
285-
message_id: lastBotMsg?.message_id
286-
};
287-
});
308+
return attachments?.accepted_files || [];
288309
}
289310
290311
@@ -915,18 +936,19 @@
915936
on:click={() => directToLog(message.message_id)}
916937
>
917938
<div>
918-
<!--<div class="conversation-name">{message.sender.full_name}</div>-->
919939
<div class="text-start">{@html replaceNewLine(message.text)}</div>
920940
<p class="chat-time mb-0">
921941
<i class="bx bx-time-five align-middle me-1" />
922-
<!-- {format(message.created_at, 'short-time')} -->
923942
{utcToLocal(message.created_at, 'hh:mm A')}
924943
</p>
925944
</div>
926945
</div>
927946
{#if !!message.post_action_disclaimer}
928947
<RcDisclaimer content={message.post_action_disclaimer} />
929948
{/if}
949+
{#if message.is_load_images}
950+
<MessageImageGallery message={message} />
951+
{/if}
930952
</div>
931953
{#if !isLite}
932954
<Dropdown>
@@ -955,9 +977,6 @@
955977
disabled={isSendingMsg || isThinking}
956978
onConfirm={confirmSelectedOption}
957979
/>
958-
{#if message.rich_content?.editor === EditorType.File && message.message_id != lastBotMsg?.message_id}
959-
<ChatImage message={message} />
960-
{/if}
961980
</div>
962981
{/if}
963982
</div>
@@ -973,9 +992,11 @@
973992
</div>
974993
<div class="msg-container">
975994
<div class="ctext-wrap float-start">
976-
<span class="chat-indication">
977-
{indication}
978-
</span>
995+
{#if !!indication}
996+
<span class="chat-indication">
997+
{indication}
998+
</span>
999+
{/if}
9791000
<div class="flex-shrink-0 align-self-center" style="display: inline-block;">
9801001
<LoadingDots duration={'1s'} size={10} color={'var(--bs-primary)'} />
9811002
</div>
@@ -985,6 +1006,10 @@
9851006
</li>
9861007
{/if}
9871008
</ul>
1009+
1010+
{#if lastBotMsg?.rich_content?.editor === EditorType.File}
1011+
<ChatImageGallery disabled={isSendingMsg || isThinking} />
1012+
{/if}
9881013
</div>
9891014
</div>
9901015
@@ -1003,12 +1028,15 @@
10031028
<div class="col">
10041029
<div class="position-relative">
10051030
<ChatTextArea
1006-
className={'chat-input'}
1031+
className={`chat-input ${lastBotMsg?.rich_content?.editor == EditorType.File ? 'chat-input-image' : ''}`}
10071032
bind:text={text}
10081033
disabled={isSendingMsg || isThinking || lastBotMsg?.rich_content?.editor == EditorType.None}
10091034
editor={lastBotMsg?.rich_content?.editor || ''}
10101035
onKeyDown={e => onSendMessage(e)}
10111036
/>
1037+
{#if lastBotMsg?.rich_content?.editor == EditorType.File}
1038+
<ChatImageUploader />
1039+
{/if}
10121040
</div>
10131041
</div>
10141042
<div class="col-auto">

src/routes/chat/[agentId]/[conversationId]/chatImage/chat-attachment.svelte renamed to src/routes/chat/[agentId]/[conversationId]/chatImage/chat-attachment-options.svelte

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<script>
2-
import { onMount } from "svelte";
3-
import FileDropZone from "$lib/common/FileDropZone.svelte";
4-
import FileGallery from "$lib/common/FileGallery.svelte";
2+
import { onDestroy, onMount } from "svelte";
53
import { conversationUserAttachmentStore } from "$lib/helpers/store";
64
75
/** @type {any[]} */
@@ -19,24 +17,20 @@
1917
let confirmOption;
2018
/** @type {any} */
2119
let cancelOption;
22-
/** @type {boolean} */
23-
let disableFileDrop = false;
24-
/** @type {number} */
25-
let fileUploadLimit = 0;
2620
27-
const fileUpperLimit = 5;
21+
const unsubscribe = conversationUserAttachmentStore.subscribe(value => {
22+
const savedAttachments = conversationUserAttachmentStore.get();
23+
files = value.accepted_files?.length > 0 ? value.accepted_files : savedAttachments.accepted_files || [];
24+
});
2825
2926
onMount(() => {
3027
collectOptions(options);
31-
const savedAttachments = conversationUserAttachmentStore.get();
32-
files = savedAttachments.accepted_files || [];
33-
console.log(files);
28+
3429
});
3530
36-
$: {
37-
disableFileDrop = disabled || files.length >= fileUpperLimit;
38-
fileUploadLimit = Math.max(fileUpperLimit - files.length, 0);
39-
}
31+
onDestroy(() => {
32+
unsubscribe();
33+
});
4034
4135
4236
/** @param {any[]} options */
@@ -75,34 +69,8 @@
7569
function innerConfirm(title, payload) {
7670
onConfirm && onConfirm(title, payload);
7771
}
78-
79-
/** @param {any} e */
80-
async function handleFileDrop(e) {
81-
const { acceptedFiles } = e.detail;
82-
const savedAttachments = conversationUserAttachmentStore.get();
83-
const newAttachments = [...savedAttachments.accepted_files || [], ...acceptedFiles];
84-
conversationUserAttachmentStore.put({
85-
accepted_files: newAttachments
86-
});
87-
files = newAttachments;
88-
}
89-
90-
/** @param {number} index */
91-
function deleteFile(index) {
92-
files = files?.filter((f, idx) => idx !== index) || [];
93-
conversationUserAttachmentStore.put({
94-
accepted_files: files
95-
});
96-
}
9772
</script>
9873
99-
<div style="display: block; margin-top: 3px;">
100-
<div style="display: flex; flex-wrap: wrap; gap: 3px;">
101-
<FileGallery files={files} disabled={disabled} needDelete onDelete={deleteFile} />
102-
<FileDropZone accept="image/*" disabled={disableFileDrop} fileLimit={fileUploadLimit} on:drop={e => handleFileDrop(e)} />
103-
</div>
104-
</div>
105-
10674
<div class="plain-option-container">
10775
{#if files?.length > 0 && confirmOption}
10876
<button
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<script>
2+
import FileGallery from "$lib/common/FileGallery.svelte";
3+
import { conversationUserAttachmentStore } from "$lib/helpers/store";
4+
import { afterUpdate, getContext, onDestroy, onMount } from "svelte";
5+
6+
/** @type {boolean} */
7+
export let disabled = false;
8+
9+
/** @type {any[]} */
10+
let files = [];
11+
12+
const { autoScrollToBottom } = getContext('chat-window-context');
13+
14+
const unsubscribe = conversationUserAttachmentStore.subscribe(value => {
15+
const savedAttachments = conversationUserAttachmentStore.get();
16+
files = value.accepted_files?.length > 0 ? value.accepted_files : savedAttachments.accepted_files || [];
17+
});
18+
19+
afterUpdate(() => {
20+
autoScrollToBottom();
21+
});
22+
23+
onDestroy(() => {
24+
unsubscribe();
25+
});
26+
27+
/** @param {number} index */
28+
function deleteFile(index) {
29+
files = files?.filter((f, idx) => idx !== index) || [];
30+
conversationUserAttachmentStore.put({
31+
accepted_files: files
32+
});
33+
}
34+
</script>
35+
36+
<div>
37+
<div class="chat-file-upload-gallery">
38+
<FileGallery files={files} disabled={disabled} needDelete onDelete={deleteFile} />
39+
</div>
40+
</div>
41+

0 commit comments

Comments
 (0)