1
0
forked from Leaf/amber-ui

改进 侧边栏增加对话信息修改

This commit is contained in:
ivamp 2024-09-13 18:52:38 +08:00
parent e36f93cf26
commit 79cd53535c
13 changed files with 652 additions and 134 deletions

View File

@ -86,6 +86,9 @@ definitions:
entity.ChatMessage:
properties:
assistant_id:
description: AssistantId 可以让同一个对话中,使用不同的助手来处理消息
type: integer
chat_id:
type: integer
completion_tokens:
type: integer
@ -124,15 +127,6 @@ definitions:
type: boolean
created_at:
type: string
file:
$ref: '#/definitions/entity.File'
file_hash:
description: |-
FileHash 是 File 结构体的 hash用于判断文件内容是否发生变化
只不过一般情况也不会改变,因为 File 就不会变
type: string
file_id:
type: integer
id:
description: Id schema.EntityId `gorm:"primarykey" json:"id,string"`
type: integer
@ -339,6 +333,8 @@ definitions:
type: object
schema.ChatMessageAddRequest:
properties:
assistant_id:
type: integer
message:
maxLength: 255
type: string
@ -383,6 +379,18 @@ definitions:
- guest_id
- name
type: object
schema.ChatUpdateRequest:
properties:
assistant_id:
type: integer
expired_at:
$ref: '#/definitions/schema.CustomTime'
name:
maxLength: 30
type: string
required:
- name
type: object
schema.CurrentUserResponse:
properties:
ip:
@ -401,6 +409,16 @@ definitions:
time.Time:
type: string
type: object
schema.DocumentCreateRequest:
properties:
content:
type: string
name:
type: string
required:
- content
- name
type: object
schema.FunctionsInput:
properties:
description:
@ -1406,6 +1424,88 @@ paths:
summary: Delete Chat
tags:
- chat
get:
consumes:
- application/json
description: 将返回一个实体
parameters:
- in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/schema.ResponseBody'
- properties:
data:
$ref: '#/definitions/entity.Chat'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/schema.ResponseBody'
"404":
description: Not Found
schema:
$ref: '#/definitions/schema.ResponseBody'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/schema.ResponseBody'
security:
- ApiKeyAuth: []
summary: 显示一个对话的数据
tags:
- chat
put:
consumes:
- application/json
description: 可以重新设置对话的一些信息
parameters:
- in: path
name: id
required: true
type: integer
- description: ChatUpdateRequest
in: body
name: schema.ChatUpdateRequest
required: true
schema:
$ref: '#/definitions/schema.ChatUpdateRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/schema.ResponseBody'
- properties:
data:
$ref: '#/definitions/entity.Chat'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/schema.ResponseBody'
"404":
description: Not Found
schema:
$ref: '#/definitions/schema.ResponseBody'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/schema.ResponseBody'
security:
- ApiKeyAuth: []
summary: 更新对话
tags:
- chat
/api/v1/chats/{id}/clear:
post:
consumes:
@ -1803,6 +1903,33 @@ paths:
summary: 列出资料库以及资料库下的文档
tags:
- libraries
post:
consumes:
- application/json
parameters:
- in: path
name: id
type: integer
- description: schema.DocumentCreateRequest
in: body
name: schema.DocumentCreateRequest
required: true
schema:
$ref: '#/definitions/schema.DocumentCreateRequest'
produces:
- application/json
responses:
"204":
description: No Content
"400":
description: Bad Request
schema:
$ref: '#/definitions/schema.ResponseBody'
security:
- ApiKeyAuth: []
summary: 创建文档
tags:
- libraries
/api/v1/libraries/{id}/documents/{document_id}:
delete:
consumes:

View File

@ -839,11 +839,17 @@ export interface EntityChat {
*/
export interface EntityChatMessage {
/**
*
* AssistantId 使
* @type {number}
* @memberof EntityChatMessage
*/
'assistant_id'?: number;
/**
*
* @type {number}
* @memberof EntityChatMessage
*/
'chat_id'?: number;
/**
*
* @type {number}
@ -941,24 +947,6 @@ export interface EntityDocument {
* @memberof EntityDocument
*/
'created_at'?: string;
/**
*
* @type {EntityFile}
* @memberof EntityDocument
*/
'file'?: EntityFile;
/**
* FileHash File hash File
* @type {string}
* @memberof EntityDocument
*/
'file_hash'?: string;
/**
*
* @type {number}
* @memberof EntityDocument
*/
'file_id'?: number;
/**
* Id schema.EntityId `gorm:\"primarykey\" json:\"id,string\"`
* @type {number}
@ -1419,6 +1407,12 @@ export interface SchemaChatCreateRequest {
* @interface SchemaChatMessageAddRequest
*/
export interface SchemaChatMessageAddRequest {
/**
*
* @type {number}
* @memberof SchemaChatMessageAddRequest
*/
'assistant_id'?: number;
/**
*
* @type {string}
@ -1501,6 +1495,31 @@ export interface SchemaChatPublicRequest {
*/
'name': string;
}
/**
*
* @export
* @interface SchemaChatUpdateRequest
*/
export interface SchemaChatUpdateRequest {
/**
*
* @type {number}
* @memberof SchemaChatUpdateRequest
*/
'assistant_id'?: number;
/**
*
* @type {SchemaCustomTime}
* @memberof SchemaChatUpdateRequest
*/
'expired_at'?: SchemaCustomTime;
/**
*
* @type {string}
* @memberof SchemaChatUpdateRequest
*/
'name': string;
}
/**
*
* @export
@ -1551,6 +1570,25 @@ export interface SchemaCustomTime {
*/
'time.Time'?: string;
}
/**
*
* @export
* @interface SchemaDocumentCreateRequest
*/
export interface SchemaDocumentCreateRequest {
/**
*
* @type {string}
* @memberof SchemaDocumentCreateRequest
*/
'content': string;
/**
*
* @type {string}
* @memberof SchemaDocumentCreateRequest
*/
'name': string;
}
/**
*
* @export
@ -3159,6 +3197,86 @@ export const ChatApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {number} id
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1ChatsIdGet: async (id: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('apiV1ChatsIdGet', 'id', id)
const localVarPath = `/api/v1/chats/{id}`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication ApiKeyAuth required
await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {number} id
* @param {SchemaChatUpdateRequest} schemaChatUpdateRequest ChatUpdateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1ChatsIdPut: async (id: number, schemaChatUpdateRequest: SchemaChatUpdateRequest, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('apiV1ChatsIdPut', 'id', id)
// verify required parameter 'schemaChatUpdateRequest' is not null or undefined
assertParamExists('apiV1ChatsIdPut', 'schemaChatUpdateRequest', schemaChatUpdateRequest)
const localVarPath = `/api/v1/chats/{id}`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication ApiKeyAuth required
await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration)
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(schemaChatUpdateRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* get string by ID
* @summary Create Chat
@ -3248,6 +3366,33 @@ export const ChatApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['ChatApi.apiV1ChatsIdDelete']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary
* @param {number} id
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiV1ChatsIdGet(id: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ApiV1ChatPublicPost200Response>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1ChatsIdGet(id, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['ChatApi.apiV1ChatsIdGet']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary
* @param {number} id
* @param {SchemaChatUpdateRequest} schemaChatUpdateRequest ChatUpdateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiV1ChatsIdPut(id: number, schemaChatUpdateRequest: SchemaChatUpdateRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ApiV1ChatPublicPost200Response>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1ChatsIdPut(id, schemaChatUpdateRequest, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['ChatApi.apiV1ChatsIdPut']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* get string by ID
* @summary Create Chat
@ -3302,6 +3447,27 @@ export const ChatApiFactory = function (configuration?: Configuration, basePath?
apiV1ChatsIdDelete(id: number, options?: RawAxiosRequestConfig): AxiosPromise<SchemaResponseBody> {
return localVarFp.apiV1ChatsIdDelete(id, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {number} id
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1ChatsIdGet(id: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1ChatPublicPost200Response> {
return localVarFp.apiV1ChatsIdGet(id, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {number} id
* @param {SchemaChatUpdateRequest} schemaChatUpdateRequest ChatUpdateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1ChatsIdPut(id: number, schemaChatUpdateRequest: SchemaChatUpdateRequest, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1ChatPublicPost200Response> {
return localVarFp.apiV1ChatsIdPut(id, schemaChatUpdateRequest, options).then((request) => request(axios, basePath));
},
/**
* get string by ID
* @summary Create Chat
@ -3359,6 +3525,31 @@ export class ChatApi extends BaseAPI {
return ChatApiFp(this.configuration).apiV1ChatsIdDelete(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {number} id
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ChatApi
*/
public apiV1ChatsIdGet(id: number, options?: RawAxiosRequestConfig) {
return ChatApiFp(this.configuration).apiV1ChatsIdGet(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {number} id
* @param {SchemaChatUpdateRequest} schemaChatUpdateRequest ChatUpdateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ChatApi
*/
public apiV1ChatsIdPut(id: number, schemaChatUpdateRequest: SchemaChatUpdateRequest, options?: RawAxiosRequestConfig) {
return ChatApiFp(this.configuration).apiV1ChatsIdPut(id, schemaChatUpdateRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
* get string by ID
* @summary Create Chat
@ -4639,6 +4830,49 @@ export const LibrariesApiAxiosParamCreator = function (configuration?: Configura
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {number} id
* @param {SchemaDocumentCreateRequest} schemaDocumentCreateRequest schema.DocumentCreateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1LibrariesIdDocumentsPost: async (id: number, schemaDocumentCreateRequest: SchemaDocumentCreateRequest, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('apiV1LibrariesIdDocumentsPost', 'id', id)
// verify required parameter 'schemaDocumentCreateRequest' is not null or undefined
assertParamExists('apiV1LibrariesIdDocumentsPost', 'schemaDocumentCreateRequest', schemaDocumentCreateRequest)
const localVarPath = `/api/v1/libraries/{id}/documents`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication ApiKeyAuth required
await setApiKeyToObject(localVarHeaderParameter, "Authorization", configuration)
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(schemaDocumentCreateRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
@ -4820,6 +5054,20 @@ export const LibrariesApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['LibrariesApi.apiV1LibrariesIdDocumentsGet']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary
* @param {number} id
* @param {SchemaDocumentCreateRequest} schemaDocumentCreateRequest schema.DocumentCreateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiV1LibrariesIdDocumentsPost(id: number, schemaDocumentCreateRequest: SchemaDocumentCreateRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1LibrariesIdDocumentsPost(id, schemaDocumentCreateRequest, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['LibrariesApi.apiV1LibrariesIdDocumentsPost']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary
@ -4910,6 +5158,17 @@ export const LibrariesApiFactory = function (configuration?: Configuration, base
apiV1LibrariesIdDocumentsGet(id: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1LibrariesIdDocumentsGet200Response> {
return localVarFp.apiV1LibrariesIdDocumentsGet(id, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {number} id
* @param {SchemaDocumentCreateRequest} schemaDocumentCreateRequest schema.DocumentCreateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiV1LibrariesIdDocumentsPost(id: number, schemaDocumentCreateRequest: SchemaDocumentCreateRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
return localVarFp.apiV1LibrariesIdDocumentsPost(id, schemaDocumentCreateRequest, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
@ -4999,6 +5258,19 @@ export class LibrariesApi extends BaseAPI {
return LibrariesApiFp(this.configuration).apiV1LibrariesIdDocumentsGet(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {number} id
* @param {SchemaDocumentCreateRequest} schemaDocumentCreateRequest schema.DocumentCreateRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof LibrariesApi
*/
public apiV1LibrariesIdDocumentsPost(id: number, schemaDocumentCreateRequest: SchemaDocumentCreateRequest, options?: RawAxiosRequestConfig) {
return LibrariesApiFp(this.configuration).apiV1LibrariesIdDocumentsPost(id, schemaDocumentCreateRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary

1
src/components.d.ts vendored
View File

@ -11,6 +11,7 @@ declare module 'vue' {
Assistants: typeof import('./components/assistants/index.vue')['default']
Chat: typeof import('./components/chat/chat.vue')['default']
ChatMenu: typeof import('./components/ChatMenu.vue')['default']
ChatSettings: typeof import('./components/ChatSettings.vue')['default']
LeftSettings: typeof import('./components/LeftSettings.vue')['default']
Menu: typeof import('./components/Menu.vue')['default']
MessageList: typeof import('./components/chat/MessageList.vue')['default']

View File

@ -0,0 +1,165 @@
<template>
<n-list hoverable clickable v-if="chatStore.chats?.length">
<n-list-item
v-for="c in chatStore.chats"
:key="c.id"
:class="
c.id === chatStore.currentChatId ? ' bg-gray-100 dark:bg-gray-700' : ''
"
@click="viewChat(c.id ?? 0)"
>
<n-thing>
<div class="flex justify-between items-center">
<div>
{{ c.name }}
</div>
<div>
<n-button
quaternary
circle
type="info"
@click.stop="editChat(c.id ?? 0)"
>
<template #icon>
<n-icon size="16" class="cursor-pointer">
<SettingsOutline />
</n-icon>
</template>
</n-button>
<n-button
quaternary
circle
type="warning"
@click.stop="deleteChat(c.id ?? 0)"
>
<template #icon>
<n-icon size="16" class="cursor-pointer">
<TrashBinOutline />
</n-icon>
</template>
</n-button>
</div>
</div>
</n-thing>
</n-list-item>
</n-list>
<div v-else>
<n-result status="404" title="你还没有对话" description="不如现在就开始?">
</n-result>
</div>
<div>
<n-drawer placement="left" v-model:show="showSettingsDialog" :width="600">
<n-drawer-content closable title="编辑对话">
<div v-if="currentChat">
<n-form >
<n-form-item label="对话名称">
<n-input
v-model:value="currentChat.name"
@keydown.enter.prevent
/>
</n-form-item>
<n-form-item label="指定助理">
<n-select
:style="{ width: '33%' }"
v-model:value="currentChat.assistant_id"
:options="assistantSelects"
/>
</n-form-item>
<n-button type="primary" @click="editChatPost"> 更新 </n-button>
</n-form>
</div>
</n-drawer-content>
</n-drawer>
</div>
</template>
<script lang="ts" setup>
import { NMenu, useDialog } from "naive-ui";
import { useRoute } from "vue-router";
import { leftMenuOptions } from "../plugins/menus/left";
import {
ChatboxOutline,
TrashBinOutline,
SettingsOutline,
} from "@vicons/ionicons5";
import getApi from "../plugins/api";
import { useChatStore } from "../stores/chat";
import router from "@/router";
import { ref } from "vue";
import { EntityAssistant, EntityChat } from "@/api";
const dialog = useDialog();
const chatStore = useChatStore();
const showSettingsDialog = ref(false);
const currentChatId = ref();
const currentChat: Ref<EntityChat> = ref({});
const assistants: Ref<EntityAssistant[]> = ref([]);
const assistantSelects = ref([
{
label: "不使用",
value: null,
},
]);
async function getChats() {
chatStore.chats = (await getApi().Chat.apiV1ChatsGet()).data.data;
}
const viewChat = (chatId: number) => {
router.push("/chat/" + chatId);
};
const deleteChat = async (chatId: number) => {
dialog.warning({
title: "删除对话",
content: "删除后,将不能恢复",
positiveText: "确定",
negativeText: "取消",
onPositiveClick: async () => {
await getApi().Chat.apiV1ChatsIdDelete(chatId);
await getChats();
},
});
};
const editChat = async (_chatId: number) => {
showSettingsDialog.value = true;
currentChatId.value = _chatId;
currentChat.value =
(await getApi().Chat.apiV1ChatsIdGet(_chatId)).data.data ?? {};
};
const editChatPost = async () => {
await getApi().Chat.apiV1ChatsIdPut(currentChatId.value, {
name: currentChat.value?.name ?? "",
assistant_id: currentChat.value?.assistant_id,
});
await getChats();
};
const getAssistants = async () => {
assistants.value =
(await getApi().Assistant.apiV1AssistantsGet()).data.data ?? [];
assistantSelects.value = [];
assistantSelects.value.push({
label: "不使用",
value: null,
});
assistants.value.forEach((a) => {
if (a.name !== undefined && a.id !== undefined) {
return assistantSelects.value.push({
label: a.name,
// @ts-ignore
value: a.id,
});
}
});
};
getChats();
getAssistants();
</script>

View File

@ -1,46 +1,7 @@
<template>
<n-tabs type="segment" animated class="select-none">
<n-tab-pane name="chap1" tab="对话">
<n-list hoverable clickable v-if="chatStore.chats?.length">
<n-list-item
v-for="c in chatStore.chats"
:key="c.id"
:class="
c.id === chatStore.currentChatId
? ' bg-gray-100 dark:bg-gray-700'
: ''
"
@click="viewChat(c.id ?? 0)"
>
<n-thing>
<div class="flex justify-between items-center">
<div>
{{ c.name }}
</div>
<n-button
quaternary
circle
type="warning"
@click.stop="deleteChat(c.id ?? 0)"
>
<template #icon>
<n-icon size="16" class="cursor-pointer">
<TrashBinOutline />
</n-icon>
</template>
</n-button>
</div>
</n-thing>
</n-list-item>
</n-list>
<div v-else>
<n-result
status="404"
title="你还没有对话"
description="不如现在就开始?"
>
</n-result>
</div>
<ChatSettings />
</n-tab-pane>
<n-tab-pane name="chap2" tab="助理">
<Assistants />
@ -79,43 +40,4 @@
<script setup lang="ts">
import { NMenu, useDialog } from "naive-ui";
import { useRoute } from "vue-router";
import { leftMenuOptions } from "../plugins/menus/left";
import { ChatboxOutline, TrashBinOutline } from "@vicons/ionicons5";
import getApi from "../plugins/api";
import { useChatStore } from "../stores/chat";
import router from "@/router";
const dialog = useDialog();
const route = useRoute();
// @ts-ignore
const chatId = route.params.id as number;
const currentRoute: any = computed(() => route.name);
const collapsed = ref(false);
const chatStore = useChatStore();
async function getChats() {
chatStore.chats = (await getApi().Chat.apiV1ChatsGet()).data.data;
}
const viewChat = (chatId: number) => {
router.push("/chat/" + chatId);
};
const deleteChat = async (chatId: number) => {
dialog.warning({
title: "删除对话",
content: "删除后,将不能恢复",
positiveText: "确定",
negativeText: "取消",
onPositiveClick: async () => {
await getApi().Chat.apiV1ChatsIdDelete(chatId);
await getChats();
},
});
};
getChats();
</script>

View File

@ -179,7 +179,6 @@ const uploading = ref(false);
const autoScroll = ref(true);
const onBottom = ref(false);
function onKeydown(e: KeyboardEvent) {
// shift
if (e.shiftKey || inputExpanded.value) {
@ -292,6 +291,13 @@ function sendText() {
input.innerText = "";
updateInputHeight();
//
// @ts-ignore ignore
element.mainContainer?.scrollTo({
top: "999999",
behavior: "smooth",
});
}
async function sendMessage(
@ -395,6 +401,14 @@ async function getChatMessages() {
chatMessages.value = cm.data.data;
//
setTimeout(() => {
// @ts-ignore ignore
element.mainContainer?.scrollTo({
top: "999999",
behavior: "smooth",
});
}, 400);
//
return true;
}
@ -478,6 +492,7 @@ function streamChat(streamId: String, redirect = false) {
}
if (autoScroll.value) {
// @ts-ignore ignore
element.mainContainer?.scrollTo({
top: "999999",
behavior: "smooth",
@ -515,14 +530,14 @@ onUnmounted(() => {
});
const uploadFile = () => {
if (!fileUpload.value) {
if (!fileUpload.value || !chatId.value) {
return;
}
uploading.value = true;
getApi()
.ChatMessage.apiV1ChatsIdFilesPost(
chatId,
Number(chatId.value),
{
file: fileUpload.value,
url: "",

View File

@ -16,7 +16,7 @@ if (process.env.NODE_ENV === "production") {
config.oauth_client_id = "16";
}
config.backend = "https://amber-api.leaflow.cn";
// config.backend = "https://amber-api.leaflow.cn";
// console.log("api endpoint: " + config.backend);

View File

@ -23,7 +23,7 @@ onMounted(() => {
<template>
<Header
v-show="userStore.logined"
v-if="userStore.logined"
style="
min-height: var(--header-height);
position: fixed;
@ -36,7 +36,7 @@ onMounted(() => {
<n-layout
:native-scrollbar="isMobile"
position="absolute"
style="margin-top: var(--header-height)"
:style="userStore.logined ? 'margin-top: var(--header-height)' : ''"
ref="mainContainer"
>
<!-- <n-layout-sider
@ -59,11 +59,8 @@ onMounted(() => {
<n-layout :native-scrollbar="isMobile">
<!-- <Guest v-if="!userStore.logined && currentRoute != '/auth/login'" />
<Container v-else /> -->
<Guest
v-if="!userStore.logined && !currentRoute?.startsWith('/auth')"
style="min-height: 85vh"
/>
<div v-else class="pt-2">
<Guest v-if="!userStore.logined && !currentRoute?.startsWith('/auth')" />
<div v-else :class="userStore.logined ? 'pt-2' : ''">
<!-- <div style="height: calc(var(--header-height)*2)"></div> -->
<router-view :key="route.path"> </router-view>

View File

@ -40,7 +40,7 @@
<n-icon size="24">
<menu-outline />
</n-icon>
<span class="ml-1.5"> Leaflow 利飞 </span>
<span class="ml-1.5 mt-0.5"> Leaflow 利飞 </span>
</div>
<!-- 更新状态 -->

View File

@ -1,6 +1,13 @@
<template>
<div>
<h1>请稍等片刻</h1>
<div class="flex items-center align-center justify-center h-screen">
<div class="text-center">
<div class="mt-5 !ml-2">
<n-h1>正在验证 Token</n-h1>
<n-text italic></n-text>
</div>
<br />
<n-p></n-p>
</div>
</div>
</template>

View File

@ -1,6 +1,13 @@
<template>
<div>
<h1>请稍后...</h1>
<div class="flex items-center align-center justify-center h-screen">
<div class="text-center">
<div class="mt-5 !ml-2">
<n-h1>生成式 AI 的颠覆性只会越来越大</n-h1>
<n-text italic> 全球第三大富豪Gautam Adani高塔姆·阿达尼 </n-text>
</div>
<br />
<n-p>正在载入</n-p>
</div>
</div>
</template>
@ -8,7 +15,7 @@
import config from "../../config/config";
import axios from "axios";
import { useUserStore } from "../../stores/user";
import router from "../../router";
const userStore = useUserStore();
function generateRandomString(length: number) {

View File

@ -1,9 +1,14 @@
<template>
<div>
正在退出
</div>
<div></div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router';
</script>
import router from "@/router";
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();
userStore.logout();
router.push("/");
</script>

View File

@ -1,14 +1,14 @@
<template>
<div class="flex items-center align-center justify-center h-full">
<div class="flex items-center align-center justify-center h-screen">
<div class="text-center">
<div class="mt-5 !ml-2">
<n-h1> 满身星光不负众望 </n-h1>
<n-p> </n-p>
</div>
<br />
<n-button v-if="!userStore.logined" type="primary" @click="login"> 登录 </n-button>
<n-button v-if="!userStore.logined" type="primary" @click="login">
登录
</n-button>
</div>
</div>
</template>
@ -21,4 +21,4 @@ const userStore = useUserStore();
const login = () => {
router.push("/auth/login");
};
</script>
</script>