feat: 修改chat
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
||||
from ai.models import ChatConversation
|
||||
from utils.serializers import CustomModelSerializer
|
||||
@@ -25,6 +27,14 @@ class ChatConversationFilter(filters.FilterSet):
|
||||
'system_message', 'max_tokens', 'max_contexts']
|
||||
|
||||
|
||||
class ConversationsSerializer(ModelSerializer):
|
||||
"""
|
||||
AI 聊天对话 列表序列化器
|
||||
"""
|
||||
class Meta:
|
||||
model = ChatConversation
|
||||
fields = ['id', 'title', 'update_time']
|
||||
|
||||
class ChatConversationViewSet(CustomModelViewSet):
|
||||
"""
|
||||
AI 聊天对话 视图集
|
||||
@@ -36,4 +46,22 @@ class ChatConversationViewSet(CustomModelViewSet):
|
||||
ordering_fields = ['create_time', 'id']
|
||||
ordering = ['-create_time']
|
||||
|
||||
# 移入urls中
|
||||
def create(self, request, *args, **kwargs):
|
||||
request.data['max_tokens'] = 2048
|
||||
request.data['max_contexts'] = 10
|
||||
if request.data['platform'] == 'tongyi':
|
||||
model = 'qwen-plus'
|
||||
else:
|
||||
model = 'deepseek-chat'
|
||||
request.data['model'] = model
|
||||
request.data['temperature'] = 0.7
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
@action(methods=['get'], detail=False)
|
||||
def conversations(self):
|
||||
queryset = self.get_queryset().filter(creator=self.request.user.username).values('id', 'title', 'update_time')
|
||||
serializer = ConversationsSerializer(queryset, many=True)
|
||||
return self._build_response(
|
||||
data=serializer.data,
|
||||
message="ok"
|
||||
)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"@vben/utils": "workspace:*",
|
||||
"@vueuse/core": "catalog:",
|
||||
"@vben-core/menu-ui": "workspace:*",
|
||||
"@vben-core/popup-ui": "workspace:*",
|
||||
"ant-design-vue": "catalog:",
|
||||
"dayjs": "catalog:",
|
||||
"pinia": "catalog:",
|
||||
|
||||
79
web/apps/web-antd/src/components/useModelForm/index.ts
Normal file
79
web/apps/web-antd/src/components/useModelForm/index.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { useVbenModal } from '@vben-core/popup-ui';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { BaseModel } from '#/models';
|
||||
|
||||
export interface BaseEntity {
|
||||
id?: number;
|
||||
// 其他公共字段...
|
||||
}
|
||||
|
||||
export function useModelForm<T extends BaseEntity>(options: {
|
||||
model: BaseModel<T>;
|
||||
schema: any;
|
||||
titleKey: string;
|
||||
}) {
|
||||
const formData = ref<T>();
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
const getTitle = computed(() => {
|
||||
return formData.value?.id
|
||||
? $t('ui.actionTitle.edit', [$t(options.titleKey)])
|
||||
: $t('ui.actionTitle.create', [$t(options.titleKey)]);
|
||||
});
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
layout: 'horizontal',
|
||||
schema: options.schema,
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (valid) {
|
||||
modalApi.lock();
|
||||
const rawFormData = await formApi.getValues();
|
||||
const formattedData = rawFormData as Partial<T>; // 关键:类型断言
|
||||
|
||||
try {
|
||||
await (formData.value?.id
|
||||
? options.model.update(formData.value.id, formattedData)
|
||||
: options.model.create(formattedData as Omit<T, any>));
|
||||
await modalApi.close();
|
||||
emit('success');
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
if (isOpen) {
|
||||
const data = modalApi.getData<T>();
|
||||
if (data) {
|
||||
formData.value = data;
|
||||
formApi.setValues(formData.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function resetForm() {
|
||||
formApi.resetForm();
|
||||
formApi.setValues(formData.value || {});
|
||||
}
|
||||
|
||||
return {
|
||||
Form,
|
||||
Modal,
|
||||
formData,
|
||||
getTitle,
|
||||
resetForm,
|
||||
formApi,
|
||||
modalApi,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import type { ExtendedModalApi } from '@vben-core/popup-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export interface CoreModel {
|
||||
@@ -18,6 +22,7 @@ export class BaseModel<
|
||||
UpdateData = Partial<CreateData>,
|
||||
> {
|
||||
protected baseUrl: string;
|
||||
protected formModalApi: ExtendedModalApi | undefined;
|
||||
|
||||
constructor(baseUrl: string) {
|
||||
this.baseUrl = baseUrl;
|
||||
@@ -70,9 +75,6 @@ export class BaseModel<
|
||||
return requestClient.delete(`${this.baseUrl}${id}/`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
*/
|
||||
/**
|
||||
* 导出数据
|
||||
*/
|
||||
@@ -90,6 +92,29 @@ export class BaseModel<
|
||||
return requestClient.get<Array<T>>(this.baseUrl, { params });
|
||||
}
|
||||
|
||||
onDelete<T extends { id: number }>(row: T, refreshGrid: () => void) {
|
||||
const hideLoading = message.loading({
|
||||
content: '删除中...',
|
||||
duration: 0,
|
||||
key: 'action_process_msg',
|
||||
});
|
||||
this.delete(row.id)
|
||||
.then(() => {
|
||||
message.success({
|
||||
content: '删除成功',
|
||||
key: 'action_process_msg',
|
||||
});
|
||||
refreshGrid();
|
||||
})
|
||||
.catch(() => {
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
|
||||
onEdit(row: T) {
|
||||
this.formModalApi?.setData(row).open();
|
||||
}
|
||||
|
||||
/**
|
||||
* 部分更新记录
|
||||
*/
|
||||
@@ -103,6 +128,10 @@ export class BaseModel<
|
||||
async retrieve(id: number) {
|
||||
return requestClient.get<T>(`${this.baseUrl}${id}/`);
|
||||
}
|
||||
|
||||
setFormModalApi(api: ExtendedModalApi) {
|
||||
this.formModalApi = api;
|
||||
}
|
||||
/**
|
||||
* 全量更新记录
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { AiAIModelApi } from '#/models/ai/ai_model';
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import { Plus } from '@vben/icons';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { $t } from '#/locales';
|
||||
@@ -17,19 +17,13 @@ import { AiAIModelModel } from '#/models/ai/ai_model';
|
||||
import { useColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const formModel = new AiAIModelModel();
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 编辑AI 模型
|
||||
*/
|
||||
function onEdit(row: AiAIModelApi.AiAIModel) {
|
||||
formModalApi.setData(row).open();
|
||||
}
|
||||
const formModel = new AiAIModelModel();
|
||||
formModel.setFormModalApi(formModalApi);
|
||||
|
||||
/**
|
||||
* 创建新AI 模型
|
||||
@@ -38,29 +32,6 @@ function onCreate() {
|
||||
formModalApi.setData(null).open();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除AI 模型
|
||||
*/
|
||||
function onDelete(row: AiAIModelApi.AiAIModel) {
|
||||
const hideLoading = message.loading({
|
||||
content: '删除AI 模型',
|
||||
duration: 0,
|
||||
key: 'action_process_msg',
|
||||
});
|
||||
formModel
|
||||
.delete(row.id)
|
||||
.then(() => {
|
||||
message.success({
|
||||
content: '删除成功',
|
||||
key: 'action_process_msg',
|
||||
});
|
||||
refreshGrid();
|
||||
})
|
||||
.catch(() => {
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格操作按钮的回调函数
|
||||
*/
|
||||
@@ -70,11 +41,11 @@ function onActionClick({
|
||||
}: OnActionClickParams<AiAIModelApi.AiAIModel>) {
|
||||
switch (code) {
|
||||
case 'delete': {
|
||||
onDelete(row);
|
||||
formModel.onDelete(row, refreshGrid);
|
||||
break;
|
||||
}
|
||||
case 'edit': {
|
||||
onEdit(row);
|
||||
formModel.onEdit(row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,17 @@ import {
|
||||
Row,
|
||||
Select,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
createConversation,
|
||||
fetchAIStream,
|
||||
getConversations,
|
||||
getMessages,
|
||||
} from '#/api/ai/chat';
|
||||
import {AiChatConversationModel} from "#/models/ai/chat_conversation";
|
||||
import {AiChatMessageModel} from "#/models/ai/chat_message";
|
||||
|
||||
const aiChatConversation = new AiChatConversationModel();
|
||||
const aiChatMessageModel = new AiChatMessageModel();
|
||||
interface Message {
|
||||
id: number;
|
||||
type: 'assistant' | 'user';
|
||||
@@ -60,14 +63,21 @@ const filteredChats = computed(() => {
|
||||
|
||||
async function selectChat(id: number) {
|
||||
selectedChatId.value = id;
|
||||
const { data } = await getMessages(id);
|
||||
const data = await aiChatMessageModel.list({
|
||||
conversation_id: id,
|
||||
});
|
||||
console.log('history', data);
|
||||
messages.value = data;
|
||||
nextTick(scrollToBottom);
|
||||
}
|
||||
|
||||
async function handleNewChat() {
|
||||
// 调用后端新建对话
|
||||
const { data } = await createConversation(selectedPlatform.value!);
|
||||
// const { data } = await createConversation(selectedPlatform.value!);
|
||||
const data = await aiChatConversation.create({
|
||||
platform: selectedPlatform.value!,
|
||||
title: '新对话',
|
||||
});
|
||||
// 刷新对话列表
|
||||
await fetchConversations();
|
||||
// 选中新建的对话
|
||||
@@ -127,7 +137,9 @@ function scrollToBottom() {
|
||||
|
||||
// 获取历史对话
|
||||
async function fetchConversations() {
|
||||
const { data } = await getConversations();
|
||||
// const { data } = await getConversations();
|
||||
const data = await aiChatConversation.list();
|
||||
console.log('history', data);
|
||||
chatList.value = data.map((item: any) => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
|
||||
4
web/pnpm-lock.yaml
generated
4
web/pnpm-lock.yaml
generated
@@ -656,6 +656,9 @@ importers:
|
||||
'@vben-core/menu-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/@core/ui-kit/menu-ui
|
||||
'@vben-core/popup-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/@core/ui-kit/popup-ui
|
||||
'@vben/access':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/effects/access
|
||||
@@ -9994,6 +9997,7 @@ packages:
|
||||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
||||
|
||||
sourcemap-codec@1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
|
||||
Reference in New Issue
Block a user