Skip to content

Commit

Permalink
add update message
Browse files Browse the repository at this point in the history
  • Loading branch information
Jicheng Lu committed Oct 11, 2024
1 parent e1f60cd commit f89c6ab
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 17 deletions.
7 changes: 6 additions & 1 deletion src/lib/common/audio-player/AudioSpeaker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@
>
<div on:click={() => speak()}>
{#if !speaking}
<i class="bx bx-volume-full clickable" />
<i
class="bx bx-volume-full clickable"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Play"
/>
{:else}
<Stretch unit='px' size='5' gap='5' color="var(--bs-primary)" />
{/if}
Expand Down
1 change: 1 addition & 0 deletions src/lib/helpers/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ function skipLoader(config) {

const putRegexes = [
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/update', 'g'),
new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-message', 'g'),
];

const deleteRegexes = [
Expand Down
12 changes: 12 additions & 0 deletions src/lib/helpers/types/conversationTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ IRichContent.prototype.quick_replies;

/**
* @typedef {Object} ChatResponseModel
* @property {string} uuid - The uuid.
* @property {string} conversation_id - The conversation id.
* @property {import('$userTypes').UserModel} sender - The message sender.
* @property {string} message_id - The message id.
Expand Down Expand Up @@ -246,6 +247,17 @@ IRichContent.prototype.quick_replies;
* @property {string?} [payload] - The payload message.
*/

/**
* @typedef {Object} EditBotMessageModel
* @property {ChatResponseModel} message
* @property {string} source
*/

/**
* @typedef {Object} UpdateBotMessageRequest
* @property {ChatResponseModel} message
* @property {number} innerIndex
*/



Expand Down
2 changes: 2 additions & 0 deletions src/lib/scss/custom/components/_alert.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
left: 35%;
right: 35%;
z-index: 8888;
font-size: 0.9em;

.alert {
text-align: center;
padding: 0.8em;
}

.success {
Expand Down
1 change: 1 addition & 0 deletions src/lib/services/api-endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const endpoints = {
conversationUserUrl: `${host}/conversation/{conversationId}/user`,
dialogsUrl: `${host}/conversation/{conversationId}/dialogs`,
conversationMessageDeletionUrl: `${host}/conversation/{conversationId}/message/{messageId}`,
conversationMessageUpdateUrl: `${host}/conversation/{conversationId}/update-message`,
fileUploadUrl: `${host}/agent/{agentId}/conversation/{conversationId}/upload`,

// LLM provider
Expand Down
25 changes: 25 additions & 0 deletions src/lib/services/conversation-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,31 @@ export async function deleteConversationMessage(conversationId, messageId, isNew
});
}

/**
* delete a message in conversation
* @param {string} conversationId The conversation id
* @param {import('$conversationTypes').UpdateBotMessageRequest} request
* @returns {Promise<boolean>}
*/
export async function updateConversationMessage(conversationId, request) {
let url = replaceUrl(endpoints.conversationMessageUpdateUrl, {
conversationId: conversationId
});

const data = {
message: request.message,
inner_index: request.innerIndex
};

return new Promise((resolve, reject) => {
axios.put(url, {...data}).then(response => {
resolve(response.data);
}).catch(err => {
reject(err)
});
});
}


/**
* upload conversation files
Expand Down
160 changes: 144 additions & 16 deletions src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { OverlayScrollbars } from 'overlayscrollbars';
import _ from "lodash";
import moment from 'moment';
import { v4 as uuidv4 } from 'uuid';
import {
Dropdown,
DropdownToggle,
Expand All @@ -25,10 +26,11 @@
sendMessageToHub,
GetDialogs,
deleteConversationMessage,
updateConversationMessage,
getConversationFiles,
getConversationUser,
uploadConversationFiles,
getAddressOptions
getAddressOptions,
} from '$lib/services/conversation-service.js';
import {
PUBLIC_LIVECHAT_ENTRY_ICON,
Expand All @@ -43,6 +45,7 @@
import HeadTitle from '$lib/common/HeadTitle.svelte';
import LoadingDots from '$lib/common/LoadingDots.svelte';
import StateModal from '$lib/common/StateModal.svelte';
import LoadingToComplete from '$lib/common/LoadingToComplete.svelte';
import ChatTextArea from './chat-util/chat-text-area.svelte';
import AudioSpeaker from '$lib/common/audio-player/AudioSpeaker.svelte';
import { utcToLocal } from '$lib/helpers/datetime';
Expand All @@ -59,7 +62,7 @@
import ChatBigMessage from './chat-util/chat-big-message.svelte';
import PersistLog from './persist-log/persist-log.svelte';
import InstantLog from './instant-log/instant-log.svelte';
import Loader from '$lib/common/Loader.svelte';
const options = {
Expand All @@ -78,6 +81,7 @@
const messageLimit = 100;
const screenWidthThreshold = 1024;
const maxTextLength = 64000;
const duration = 2000;
/** @type {import('$agentTypes').AgentModel} */
export let agent;
Expand All @@ -86,13 +90,16 @@
export let currentUser;
/** @type {string} */
let text = "";
let editText = "";
let bigText = "";
let truncateMsgId = "";
let indication = "";
let text = '';
let editText = '';
let bigText = '';
let botText = '';
let truncateMsgId = '';
let indication = '';
let mode = '';
let notificationText = '';
let successText = "Done";
let errorText = "Error";
/** @type {number} */
let messageInputTimeout;
Expand All @@ -107,6 +114,9 @@
let scrollbars = [];
let microphoneIcon = "microphone-off";
/** @type {import('$conversationTypes').EditBotMessageModel?} */
let editBotMsg;
/** @type {import('$conversationTypes').ChatResponseModel?} */
let lastBotMsg;
Expand Down Expand Up @@ -149,6 +159,7 @@
let isInstantLogClosed = false; // initial condition
let isOpenEditMsgModal = false;
let isOpenBigMsgModal = false;
let isOpenEditBotMsgModal = false;
let isOpenUserAddStateModal = false;
let isSendingMsg = false;
let isThinking = false;
Expand All @@ -163,6 +174,8 @@
let isLoading = false;
let isCreatingNewConv = false;
let isDisplayNotification = false;
let isComplete = false;
let isError = false;
$: {
const editor = lastBotMsg?.rich_content?.editor || '';
Expand Down Expand Up @@ -358,7 +371,7 @@
async function refresh() {
// trigger UI render
dialogs = dialogs?.map(item => { return { ...item }; }) || [];
dialogs = dialogs?.map(item => { return { ...item, uuid: uuidv4() }; }) || [];
lastBotMsg = null;
await tick();
lastBotMsg = findLastBotMessage(dialogs);
Expand Down Expand Up @@ -1141,14 +1154,100 @@
notificationText = '';
}
}
/** @param {import('$conversationTypes').ChatResponseModel} message */
function openEditBotMsgModal(message) {
isOpenEditBotMsgModal = true;
let source = "text";
if (message.rich_content?.message?.text === message.text) {
source = "both";
} else if (message.rich_content?.message?.text) {
source = "rich-content-text";
}
editBotMsg = {
message: message,
source: source
};
botText = message?.rich_content?.message?.text || message?.text;
}
function toggleEditBotMsgModal() {
isOpenEditBotMsgModal = !isOpenEditBotMsgModal;
if (!isOpenEditBotMsgModal) {
editBotMsg = null;
botText = '';
}
}
function saveBotMsg() {
if (!editBotMsg) return;
const found = dialogs.find(x => x.uuid === editBotMsg?.message.uuid);
if (!found) return;
const candidates = dialogs.filter(x => x.message_id === editBotMsg?.message.message_id && x.sender?.role === editBotMsg?.message.sender?.role);
const innerIdx = candidates.findIndex(x => x.uuid === editBotMsg?.message.uuid);
/** @type {import('$conversationTypes').UpdateBotMessageRequest} */
const request = {
message: editBotMsg.message,
innerIndex: innerIdx
};
if (editBotMsg.source === "both") {
found.text = botText;
found.rich_content.message.text = botText;
editBotMsg.message.text = botText;
editBotMsg.message.rich_content.message.text = botText;
} else if (editBotMsg?.source === "rich-content-text") {
found.rich_content.message.text = botText;
editBotMsg.message.rich_content.message.text = botText;
} else {
found.text = botText;
editBotMsg.message.text = botText;
}
isLoading = true;
updateConversationMessage(params.conversationId, request).then(res => {
if (res) {
isComplete = true;
successText = "Message has been updated!";
setTimeout(() => {
isComplete = false;
successText = "";
}, duration);
toggleEditBotMsgModal();
refresh();
} else {
throw "failed to update message";
}
}).catch(err => {
isError = true;
errorText = "Failed to update message!";
setTimeout(() => {
isError = false;
errorText = "";
}, duration);
toggleEditBotMsgModal();
}).finally(() => {
isLoading = false;
});
}
</script>
<svelte:window on:resize={() => resizeChatWindow()}/>
{#if isLoading}
<Loader size={35} />
{/if}
<LoadingToComplete
spinnerSize={35}
isLoading={isLoading}
isComplete={isComplete}
isError={isError}
successText={successText}
errorText={errorText}
/>
<DialogModal
title={'Notification'}
Expand All @@ -1170,7 +1269,7 @@
<DialogModal
title={'Edit message'}
title={'Edit user message'}
size={'md'}
isOpen={isOpenEditMsgModal}
toggleModal={() => toggleEditMsgModal()}
Expand Down Expand Up @@ -1199,6 +1298,21 @@
</div>
</DialogModal>
<DialogModal
title={'Edit bot message'}
size={'xl'}
isOpen={isOpenEditBotMsgModal}
toggleModal={() => toggleEditBotMsgModal()}
confirm={() => saveBotMsg()}
cancel={() => toggleEditBotMsgModal()}
disableConfirmBtn={!!!_.trim(botText)}
>
<textarea class="form-control chat-input" rows="10" maxlength={maxTextLength} bind:value={botText} placeholder="Enter Message..." />
<div class="text-secondary text-end text-count">
<div>{`${(botText?.length || 0)}/${maxTextLength}`}</div>
</div>
</DialogModal>
<StateModal
isOpen={isOpenUserAddStateModal}
bind:states={userAddStates}
Expand Down Expand Up @@ -1377,7 +1491,7 @@
</div>
<div class="msg-container">
<RcMessage message={message} />
{#if message?.message_id === lastBotMsg?.message_id}
{#if message?.message_id === lastBotMsg?.message_id && message?.uuid === lastBotMsg?.uuid}
<div style="display: flex; gap: 10px;">
<AudioSpeaker
id={message?.message_id}
Expand All @@ -1390,14 +1504,28 @@
<div
class="clickable"
style="height: 95%;"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Like"
on:click={e => likeMessage(e, message)}
>
<i
class="mdi mdi-thumb-up-outline text-primary"
/>
<i class="mdi mdi-thumb-up-outline text-primary" />
</div>
</div>
{/if}
<div class="line-align-center" style="font-size: 17px;">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="clickable"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Edit"
on:click={() => openEditBotMsgModal(message)}
>
<i class="bx bxs-edit text-primary" />
</div>
</div>
</div>
{/if}
{#if !!message.is_chat_message || !!message.has_message_files}
Expand Down

0 comments on commit f89c6ab

Please sign in to comment.