From d1e47d2b04779d1362f6fadc86beac3d38f9f794 Mon Sep 17 00:00:00 2001
From: hyf-github-user <1348977728@qq.com>
Date: Tue, 13 Aug 2024 22:57:08 +0800
Subject: [PATCH 1/2] add edit chat
---
src/components/chat/Message.vue | 146 +++++++++++++++++++++++++++++---
src/i18n/zh-CN/chat.json | 4 +
src/pages/chat/Conversation.vue | 4 +
3 files changed, 140 insertions(+), 14 deletions(-)
diff --git a/src/components/chat/Message.vue b/src/components/chat/Message.vue
index 3faff506..4b24d1c2 100644
--- a/src/components/chat/Message.vue
+++ b/src/components/chat/Message.vue
@@ -16,20 +16,45 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -45,8 +70,9 @@
import { defineComponent } from 'vue';
import AnsweringMark from './AnsweringMark.vue';
import copy from 'copy-to-clipboard';
-import { ElAlert, ElButton, ElImage } from 'element-plus';
+import { ElAlert, ElButton, ElImage, ElTooltip, ElInput } from 'element-plus';
import MarkdownRenderer from '@/components/common/MarkdownRenderer.vue';
+import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { IApplication, IChatMessage, IChatMessageState } from '@/models';
import CopyToClipboard from '../common/CopyToClipboard.vue';
import {
@@ -64,6 +90,8 @@ import { ROUTE_CONSOLE_APPLICATION_BUY } from '@/router';
interface IData {
copied: boolean;
+ isEditing: boolean;
+ questionValue: string;
messageState: typeof IChatMessageState;
}
@@ -75,9 +103,16 @@ export default defineComponent({
MarkdownRenderer,
ElAlert,
ElButton,
- ElImage
+ ElImage,
+ ElTooltip,
+ FontAwesomeIcon,
+ ElInput
},
props: {
+ question: {
+ type: String,
+ required: true
+ },
message: {
type: Object as () => IChatMessage,
required: true
@@ -87,10 +122,12 @@ export default defineComponent({
required: true
}
},
- emits: ['stop'],
+ emits: ['stop', 'update:question', 'submit'],
data(): IData {
return {
copied: false,
+ isEditing: false,
+ questionValue: this.message.content as string,
messageState: IChatMessageState
};
},
@@ -123,7 +160,35 @@ export default defineComponent({
return this.message.role === ROLE_ASSISTANT && this.message.error?.code === ERROR_CODE_USED_UP;
}
},
+ watch: {
+ questionValue(val: string) {
+ this.$emit('update:question', val);
+ },
+ question(val: string) {
+ if (val !== this.questionValue) {
+ this.questionValue = val;
+ }
+ }
+ },
methods: {
+ startEditing() {
+ this.isEditing = true;
+ this.questionValue = this.message.content as string;
+ },
+ cancelEdit() {
+ this.isEditing = false;
+ },
+ sendEdit() {
+ // Implement the logic to save the edited content
+ this.isEditing = false;
+ this.onSubmit();
+ },
+ onSubmit() {
+ if (!this.question) {
+ return;
+ }
+ this.$emit('submit');
+ },
onCopy() {
copy(this.message.content!.toString(), {
debug: true
@@ -209,7 +274,48 @@ export default defineComponent({
width: fit-content;
text-align: left;
max-width: 100%;
- padding: 8px 15px;
+ position: relative;
+ .edit-left {
+ position: absolute;
+ left: -25px; /* Adjust as needed */
+ top: 50%;
+ transform: translateY(-50%);
+ }
+ .chat-container {
+ // background-color: var(--el-bg-color-page);
+ // color: var(--el-text-color-primary);
+ padding: 10px;
+ width: 100%;
+ height: 100%;
+ .chat-input {
+ // background-color: var(--el-bg-color-page);
+ // color: var(--el-text-color-primary);
+ padding-bottom: 30px; /* 为按钮预留空间 */
+ }
+
+ .button-group {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+ .cancel-button {
+ // background-color: #333;
+ // color: white;
+ background-color: var(--el-bg-color-page);
+ color: var(--el-text-color-primary);
+ border-radius: 20px;
+ // border: none;
+ }
+
+ .send-button {
+ // background-color: white;
+ // color: black;
+ background-color: var(--el-bg-color-page);
+ color: var(--el-text-color-primary);
+ border-radius: 20px;
+ // border: none;
+ }
+ }
+ }
}
}
.content {
@@ -223,6 +329,18 @@ export default defineComponent({
margin: 5px 0;
border-radius: 10px;
}
+ .edit-area {
+ width: 100%;
+ min-height: 100px;
+ border-radius: 10px;
+ padding: 8px;
+ margin-bottom: 10px;
+ }
+ .edit-buttons {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+ }
}
.operations {
diff --git a/src/i18n/zh-CN/chat.json b/src/i18n/zh-CN/chat.json
index 10923ea6..6e50fb28 100644
--- a/src/i18n/zh-CN/chat.json
+++ b/src/i18n/zh-CN/chat.json
@@ -1,4 +1,8 @@
{
+ "button.edit": {
+ "message": "编辑消息",
+ "description": "编辑发送的消息"
+ },
"model.35Standard": {
"message": "3.5 标准",
"description": "服务的模型名称,即 GPT 3.5 基础"
diff --git a/src/pages/chat/Conversation.vue b/src/pages/chat/Conversation.vue
index 0827923b..2a0e9aca 100644
--- a/src/pages/chat/Conversation.vue
+++ b/src/pages/chat/Conversation.vue
@@ -16,8 +16,11 @@
v-for="(message, messageIndex) in messages"
:key="messageIndex"
:message="message"
+ :question="question"
:application="application"
class="message"
+ @update:question="question = $event"
+ @submit="onSubmit"
/>
@@ -163,6 +166,7 @@ export default defineComponent({
await this.onCreateNewConversation();
await this.$store.dispatch('chat/getApplication');
},
+ // Send a message
async onSubmit() {
if (this.references.length > 0) {
let content = [];
From 93db9eb7cfe474af59bb8a0ba09a14264b74ccbb Mon Sep 17 00:00:00 2001
From: hyf-github-user <1348977728@qq.com>
Date: Wed, 14 Aug 2024 15:36:56 +0800
Subject: [PATCH 2/2] finish edit chat
---
...-844d84c0-8975-4ee8-a722-0aa345d61351.json | 7 ++
src/components/chat/Message.vue | 23 +-----
src/models/chat.ts | 6 +-
src/pages/chat/Conversation.vue | 80 ++++++++++++++++++-
4 files changed, 93 insertions(+), 23 deletions(-)
create mode 100644 change/@acedatacloud-nexior-844d84c0-8975-4ee8-a722-0aa345d61351.json
diff --git a/change/@acedatacloud-nexior-844d84c0-8975-4ee8-a722-0aa345d61351.json b/change/@acedatacloud-nexior-844d84c0-8975-4ee8-a722-0aa345d61351.json
new file mode 100644
index 00000000..c378e0ec
--- /dev/null
+++ b/change/@acedatacloud-nexior-844d84c0-8975-4ee8-a722-0aa345d61351.json
@@ -0,0 +1,7 @@
+{
+ "type": "minor",
+ "comment": "add edit chat",
+ "packageName": "@acedatacloud/nexior",
+ "email": "1348977728@qq.com",
+ "dependentChangeType": "patch"
+}
diff --git a/src/components/chat/Message.vue b/src/components/chat/Message.vue
index 4b24d1c2..50210d71 100644
--- a/src/components/chat/Message.vue
+++ b/src/components/chat/Message.vue
@@ -109,10 +109,6 @@ export default defineComponent({
ElInput
},
props: {
- question: {
- type: String,
- required: true
- },
message: {
type: Object as () => IChatMessage,
required: true
@@ -122,7 +118,7 @@ export default defineComponent({
required: true
}
},
- emits: ['stop', 'update:question', 'submit'],
+ emits: ['stop', 'update:messages', 'edit'],
data(): IData {
return {
copied: false,
@@ -160,20 +156,12 @@ export default defineComponent({
return this.message.role === ROLE_ASSISTANT && this.message.error?.code === ERROR_CODE_USED_UP;
}
},
- watch: {
- questionValue(val: string) {
- this.$emit('update:question', val);
- },
- question(val: string) {
- if (val !== this.questionValue) {
- this.questionValue = val;
- }
- }
- },
+ watch: {},
methods: {
startEditing() {
this.isEditing = true;
this.questionValue = this.message.content as string;
+ console.debug('start to get answer', this.message);
},
cancelEdit() {
this.isEditing = false;
@@ -184,10 +172,7 @@ export default defineComponent({
this.onSubmit();
},
onSubmit() {
- if (!this.question) {
- return;
- }
- this.$emit('submit');
+ this.$emit('edit', this.message, this.questionValue);
},
onCopy() {
copy(this.message.content!.toString(), {
diff --git a/src/models/chat.ts b/src/models/chat.ts
index 9bacd028..f7e12618 100644
--- a/src/models/chat.ts
+++ b/src/models/chat.ts
@@ -46,13 +46,13 @@ export interface IChatMessage {
}
export interface IChatConversation {
- id: string;
- messages: IChatMessage[];
+ id?: string;
+ messages?: IChatMessage[];
title?: string;
deleting?: boolean;
editing?: boolean;
new?: boolean;
- updated_at: number;
+ updated_at?: number;
}
export interface IChatConversationOptions {
diff --git a/src/pages/chat/Conversation.vue b/src/pages/chat/Conversation.vue
index 2a0e9aca..39568af2 100644
--- a/src/pages/chat/Conversation.vue
+++ b/src/pages/chat/Conversation.vue
@@ -16,11 +16,13 @@
v-for="(message, messageIndex) in messages"
:key="messageIndex"
:message="message"
+ :messages="messages"
:question="question"
:application="application"
class="message"
@update:question="question = $event"
- @submit="onSubmit"
+ @update:messages="messages = $event"
+ @edit="onEdit"
/>
@@ -157,6 +159,80 @@ export default defineComponent({
this.question = question;
this.onSubmit();
},
+ async onEdit(targetMessage: IChatMessage, questionValue: string) {
+ // 1. Clear the following message
+ const targetIndex = this.messages.findIndex((message) => message === targetMessage);
+ if (targetIndex !== -1) {
+ this.messages = this.messages.slice(0, targetIndex);
+ }
+ this.question = questionValue;
+ // 2. Update the messages
+ const token = this.credential?.token;
+ // reset question and references
+ if (!token) {
+ console.error('no token or endpoint or question');
+ this.messages.push({
+ error: {
+ code: ERROR_CODE_NOT_APPLIED
+ },
+ role: ROLE_ASSISTANT,
+ state: IChatMessageState.FAILED
+ });
+ return;
+ }
+ let conversationId = this.conversationId;
+ chatOperator
+ .updateConversation(
+ {
+ id: this.conversationId,
+ messages: this.messages
+ },
+ {
+ token
+ }
+ )
+ .then(async () => {
+ await this.$store.dispatch('chat/setConversation', {
+ id: conversationId,
+ messages: this.messages
+ });
+ // 3. Send edited questions
+
+ this.messages.push({
+ content: this.question,
+ role: ROLE_USER
+ });
+ console.debug('onEdit', this.question);
+ await this.onFetchAnswer();
+ })
+ .catch((error) => {
+ if (this.messages && this.messages.length > 0) {
+ this.messages[this.messages.length - 1].state = IChatMessageState.FAILED;
+ }
+ console.error(error);
+ if (axios.isCancel(error)) {
+ this.messages[this.messages.length - 1].error = {
+ code: ERROR_CODE_CANCELED
+ };
+ } else if (error?.response?.data) {
+ let data = error?.response?.data;
+ if (isJSONString(data)) {
+ data = JSON.parse(data);
+ }
+ console.debug('error', data);
+ if (this.messages && this.messages.length > 0) {
+ this.messages[this.messages.length - 1].error = data.error;
+ }
+ } else {
+ if (this.messages && this.messages.length > 0) {
+ this.messages[this.messages.length - 1].error = {
+ code: ERROR_CODE_UNKNOWN
+ };
+ }
+ }
+ this.answering = false;
+ });
+ },
async onCreateNewConversation() {
await this.$router.push({
name: ROUTE_CHAT_CONVERSATION_NEW
@@ -194,6 +270,7 @@ export default defineComponent({
console.debug('onSubmit', this.question, this.references);
await this.onFetchAnswer();
},
+ // Swipe the message to the bottom
async onScrollDown() {
setTimeout(() => {
const container = document.querySelector('.dialogue') as HTMLDivElement;
@@ -203,6 +280,7 @@ export default defineComponent({
container.scrollTop = container?.scrollHeight;
}, 0);
},
+ // Get answers to questions
async onFetchAnswer() {
const token = this.credential?.token;
const question = this.question;