forked from Leaf/amber-ui
Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
29f650c83d | ||
af70f11e9b | |||
07547899ef | |||
|
9aba890b46 | ||
38b870438e | |||
|
1f8238aabe | ||
1cf70e6bb4 | |||
|
b0f52ca420 | ||
|
25190adaaf | ||
|
6cde2335f5 | ||
0e8b8aad9b | |||
|
99a1736d26 | ||
75d5f8db66 | |||
0bcb10c810 | |||
|
d2889a8bcc | ||
629ae9300f | |||
5e5f7cd76e | |||
|
84f643f271 | ||
66290ea1d0 | |||
bbfb41f706 | |||
|
3f60f29806 | ||
fc604a9117 | |||
74a35b1f11 | |||
|
19e51a6bf3 | ||
1826dab66b | |||
6d676afac6 | |||
f3c7c40f1e | |||
a53f1b1710 | |||
|
ea7a2aa883 | ||
3935e8c179 | |||
65bbced587 | |||
|
b133042d77 | ||
71cfbb722a | |||
809405f3d9 | |||
|
deab452156 | ||
|
7fc0dac915 | ||
|
fb922e24ae | ||
|
79b7687b09 | ||
f46254b323 | |||
3d259b7331 | |||
81a5e85a3a |
@ -68,6 +68,9 @@
|
|||||||
"onWatcherCleanup": true,
|
"onWatcherCleanup": true,
|
||||||
"useId": true,
|
"useId": true,
|
||||||
"useModel": true,
|
"useModel": true,
|
||||||
"useTemplateRef": true
|
"useTemplateRef": true,
|
||||||
|
"DirectiveBinding": true,
|
||||||
|
"MaybeRef": true,
|
||||||
|
"MaybeRefOrGetter": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
200
api/swagger.yaml
200
api/swagger.yaml
@ -9,6 +9,8 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
disable_memory:
|
disable_memory:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
disable_web_browsing:
|
||||||
|
type: boolean
|
||||||
enable_memory_for_assistant_api:
|
enable_memory_for_assistant_api:
|
||||||
type: boolean
|
type: boolean
|
||||||
id:
|
id:
|
||||||
@ -245,6 +247,24 @@ definitions:
|
|||||||
user_id:
|
user_id:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
entity.ScenePrompt:
|
||||||
|
properties:
|
||||||
|
assistant:
|
||||||
|
$ref: '#/definitions/entity.Assistant'
|
||||||
|
assistant_id:
|
||||||
|
type: integer
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
description: Id schema.EntityId `gorm:"primarykey" json:"id,string"`
|
||||||
|
type: integer
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
prompt:
|
||||||
|
type: string
|
||||||
|
updated_at:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
entity.Tool:
|
entity.Tool:
|
||||||
properties:
|
properties:
|
||||||
api_key:
|
api_key:
|
||||||
@ -267,8 +287,31 @@ definitions:
|
|||||||
user_id:
|
user_id:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
page.PagedResult-entity_ChatMessageList:
|
||||||
|
properties:
|
||||||
|
count:
|
||||||
|
type: integer
|
||||||
|
data:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/entity.ChatMessageList'
|
||||||
|
type: array
|
||||||
|
page:
|
||||||
|
description: 当前页码
|
||||||
|
type: integer
|
||||||
|
page_size:
|
||||||
|
description: 每页大小
|
||||||
|
type: integer
|
||||||
|
total_count:
|
||||||
|
description: 数据总条数
|
||||||
|
type: integer
|
||||||
|
total_pages:
|
||||||
|
description: 总页数
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
page.PagedResult-schema_AssistantPublic:
|
page.PagedResult-schema_AssistantPublic:
|
||||||
properties:
|
properties:
|
||||||
|
count:
|
||||||
|
type: integer
|
||||||
data:
|
data:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/schema.AssistantPublic'
|
$ref: '#/definitions/schema.AssistantPublic'
|
||||||
@ -374,6 +417,11 @@ definitions:
|
|||||||
- true
|
- true
|
||||||
- false
|
- false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
disable_web_browsing:
|
||||||
|
enum:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
type: boolean
|
||||||
enable_memory_for_assistant_api:
|
enable_memory_for_assistant_api:
|
||||||
enum:
|
enum:
|
||||||
- true
|
- true
|
||||||
@ -488,6 +536,18 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
|
schema.CreateAssistantScenePromptRequest:
|
||||||
|
properties:
|
||||||
|
label:
|
||||||
|
maxLength: 20
|
||||||
|
type: string
|
||||||
|
prompt:
|
||||||
|
maxLength: 512
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- label
|
||||||
|
- prompt
|
||||||
|
type: object
|
||||||
schema.CurrentUserResponse:
|
schema.CurrentUserResponse:
|
||||||
properties:
|
properties:
|
||||||
ip:
|
ip:
|
||||||
@ -1074,6 +1134,104 @@ paths:
|
|||||||
summary: 绑定资料库
|
summary: 绑定资料库
|
||||||
tags:
|
tags:
|
||||||
- assistant
|
- assistant
|
||||||
|
/api/v1/assistants/{id}/scene_prompts:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/schema.ResponseBody'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/entity.ScenePrompt'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/schema.ResponseBody'
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: 列出当前助理的场景 Prompt
|
||||||
|
tags:
|
||||||
|
- assistant
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: CreateAssistantScenePromptRequest
|
||||||
|
in: body
|
||||||
|
name: CreateAssistantScenePromptRequest
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/schema.CreateAssistantScenePromptRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/schema.ResponseBody'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
$ref: '#/definitions/entity.ScenePrompt'
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/schema.ResponseBody'
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: 创建场景 Prompt
|
||||||
|
tags:
|
||||||
|
- assistant
|
||||||
|
/api/v1/assistants/{id}/scene_prompts/{scene_id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- in: path
|
||||||
|
name: scene_id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/schema.ResponseBody'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/schema.ResponseBody'
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: 删除场景 Prompt
|
||||||
|
tags:
|
||||||
|
- assistant
|
||||||
/api/v1/assistants/{id}/tools:
|
/api/v1/assistants/{id}/tools:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
@ -1913,6 +2071,48 @@ paths:
|
|||||||
summary: 添加聊天记录
|
summary: 添加聊天记录
|
||||||
tags:
|
tags:
|
||||||
- chat_message
|
- chat_message
|
||||||
|
/api/v1/chats/{id}/messages/paginate:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 获取一个对话的所有聊天记录
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: page
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/schema.ResponseBody'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
$ref: '#/definitions/page.PagedResult-entity_ChatMessageList'
|
||||||
|
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_message
|
||||||
/api/v1/files/download/{hash}:
|
/api/v1/files/download/{hash}:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
@ -17,7 +17,7 @@ spec:
|
|||||||
- name: leaf
|
- name: leaf
|
||||||
containers:
|
containers:
|
||||||
- name: amber
|
- name: amber
|
||||||
image: leafdev.top/leaf/amber-ui:dbdc39f
|
image: leafdev.top/leaf/amber-ui:af70f11
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
|
@ -11,18 +11,19 @@
|
|||||||
"gen": "openapi-generator-cli generate -i ./api/swagger.yaml -g typescript-axios -o ./src/api"
|
"gen": "openapi-generator-cli generate -i ./api/swagger.yaml -g typescript-axios -o ./src/api"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kangc/v-md-editor": "^2.3.18",
|
"@iktakahiro/markdown-it-katex": "^4.0.1",
|
||||||
"@notable/html2markdown": "^2.0.3",
|
"@notable/html2markdown": "^2.0.3",
|
||||||
"@traptitech/markdown-it-katex": "^3.6.0",
|
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"highlight.js": "^11.10.0",
|
"highlight.js": "^11.10.0",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
"katex": "^0.16.11",
|
"katex": "^0.16.11",
|
||||||
"lottie-web": "^5.12.2",
|
"lottie-web": "^5.12.2",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
"pinia-plugin-persistedstate": "^4.0.0",
|
"pinia-plugin-persistedstate": "^4.0.0",
|
||||||
"vooks": "^0.2.12"
|
"vooks": "^0.2.12",
|
||||||
|
"vue-i18n": "10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "^7.18.10",
|
"@babel/types": "^7.18.10",
|
||||||
@ -47,6 +48,7 @@
|
|||||||
"naive-ui": "^2.39.0",
|
"naive-ui": "^2.39.0",
|
||||||
"postcss": "^8.4.45",
|
"postcss": "^8.4.45",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
"sass-embedded": "^1.79.5",
|
||||||
"tailwindcss": "^3.4.10",
|
"tailwindcss": "^3.4.10",
|
||||||
"typescript": "^5.5.2",
|
"typescript": "^5.5.2",
|
||||||
"unplugin-auto-import": "^0.18.2",
|
"unplugin-auto-import": "^0.18.2",
|
||||||
|
534
src/api/api.ts
534
src/api/api.ts
@ -147,6 +147,68 @@ export interface ApiV1AssistantsIdKeysPost200Response {
|
|||||||
*/
|
*/
|
||||||
'success'?: boolean;
|
'success'?: boolean;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ApiV1AssistantsIdScenePromptsGet200Response
|
||||||
|
*/
|
||||||
|
export interface ApiV1AssistantsIdScenePromptsGet200Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Array<EntityScenePrompt>}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsGet200Response
|
||||||
|
*/
|
||||||
|
'data'?: Array<EntityScenePrompt>;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsGet200Response
|
||||||
|
*/
|
||||||
|
'error'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsGet200Response
|
||||||
|
*/
|
||||||
|
'message'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsGet200Response
|
||||||
|
*/
|
||||||
|
'success'?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ApiV1AssistantsIdScenePromptsPost200Response
|
||||||
|
*/
|
||||||
|
export interface ApiV1AssistantsIdScenePromptsPost200Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {EntityScenePrompt}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsPost200Response
|
||||||
|
*/
|
||||||
|
'data'?: EntityScenePrompt;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsPost200Response
|
||||||
|
*/
|
||||||
|
'error'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsPost200Response
|
||||||
|
*/
|
||||||
|
'message'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof ApiV1AssistantsIdScenePromptsPost200Response
|
||||||
|
*/
|
||||||
|
'success'?: boolean;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@ -476,6 +538,37 @@ export interface ApiV1ChatsIdMessagesGet200Response {
|
|||||||
*/
|
*/
|
||||||
'success'?: boolean;
|
'success'?: boolean;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ApiV1ChatsIdMessagesPaginateGet200Response
|
||||||
|
*/
|
||||||
|
export interface ApiV1ChatsIdMessagesPaginateGet200Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {PagePagedResultEntityChatMessageList}
|
||||||
|
* @memberof ApiV1ChatsIdMessagesPaginateGet200Response
|
||||||
|
*/
|
||||||
|
'data'?: PagePagedResultEntityChatMessageList;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1ChatsIdMessagesPaginateGet200Response
|
||||||
|
*/
|
||||||
|
'error'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ApiV1ChatsIdMessagesPaginateGet200Response
|
||||||
|
*/
|
||||||
|
'message'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof ApiV1ChatsIdMessagesPaginateGet200Response
|
||||||
|
*/
|
||||||
|
'success'?: boolean;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@ -754,6 +847,12 @@ export interface EntityAssistant {
|
|||||||
* @memberof EntityAssistant
|
* @memberof EntityAssistant
|
||||||
*/
|
*/
|
||||||
'disable_memory'?: boolean;
|
'disable_memory'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof EntityAssistant
|
||||||
|
*/
|
||||||
|
'disable_web_browsing'?: boolean;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@ -1377,6 +1476,55 @@ export interface EntityMemory {
|
|||||||
*/
|
*/
|
||||||
'user_id'?: string;
|
'user_id'?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface EntityScenePrompt
|
||||||
|
*/
|
||||||
|
export interface EntityScenePrompt {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {EntityAssistant}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'assistant'?: EntityAssistant;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'assistant_id'?: number;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'created_at'?: string;
|
||||||
|
/**
|
||||||
|
* Id schema.EntityId `gorm:\"primarykey\" json:\"id,string\"`
|
||||||
|
* @type {number}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'id'?: number;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'label'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'prompt'?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof EntityScenePrompt
|
||||||
|
*/
|
||||||
|
'updated_at'?: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@ -1438,12 +1586,61 @@ export interface EntityTool {
|
|||||||
*/
|
*/
|
||||||
'user_id'?: string;
|
'user_id'?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
export interface PagePagedResultEntityChatMessageList {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'count'?: number;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Array<EntityChatMessageList>}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'data'?: Array<EntityChatMessageList>;
|
||||||
|
/**
|
||||||
|
* 当前页码
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'page'?: number;
|
||||||
|
/**
|
||||||
|
* 每页大小
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'page_size'?: number;
|
||||||
|
/**
|
||||||
|
* 数据总条数
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'total_count'?: number;
|
||||||
|
/**
|
||||||
|
* 总页数
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultEntityChatMessageList
|
||||||
|
*/
|
||||||
|
'total_pages'?: number;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @interface PagePagedResultSchemaAssistantPublic
|
* @interface PagePagedResultSchemaAssistantPublic
|
||||||
*/
|
*/
|
||||||
export interface PagePagedResultSchemaAssistantPublic {
|
export interface PagePagedResultSchemaAssistantPublic {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof PagePagedResultSchemaAssistantPublic
|
||||||
|
*/
|
||||||
|
'count'?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {Array<SchemaAssistantPublic>}
|
* @type {Array<SchemaAssistantPublic>}
|
||||||
@ -1618,6 +1815,12 @@ export interface SchemaAssistantUpdateRequest {
|
|||||||
* @memberof SchemaAssistantUpdateRequest
|
* @memberof SchemaAssistantUpdateRequest
|
||||||
*/
|
*/
|
||||||
'disable_memory'?: boolean;
|
'disable_memory'?: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof SchemaAssistantUpdateRequest
|
||||||
|
*/
|
||||||
|
'disable_web_browsing'?: boolean;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@ -1818,6 +2021,25 @@ export interface SchemaChatUpdateRequest {
|
|||||||
*/
|
*/
|
||||||
'prompt'?: string;
|
'prompt'?: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface SchemaCreateAssistantScenePromptRequest
|
||||||
|
*/
|
||||||
|
export interface SchemaCreateAssistantScenePromptRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof SchemaCreateAssistantScenePromptRequest
|
||||||
|
*/
|
||||||
|
'label': string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof SchemaCreateAssistantScenePromptRequest
|
||||||
|
*/
|
||||||
|
'prompt': string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
@ -2769,6 +2991,127 @@ export const AssistantApiAxiosParamCreator = function (configuration?: Configura
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 列出当前助理的场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsGet: async (id: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'id' is not null or undefined
|
||||||
|
assertParamExists('apiV1AssistantsIdScenePromptsGet', 'id', id)
|
||||||
|
const localVarPath = `/api/v1/assistants/{id}/scene_prompts`
|
||||||
|
.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 创建场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {SchemaCreateAssistantScenePromptRequest} createAssistantScenePromptRequest CreateAssistantScenePromptRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsPost: async (id: number, createAssistantScenePromptRequest: SchemaCreateAssistantScenePromptRequest, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'id' is not null or undefined
|
||||||
|
assertParamExists('apiV1AssistantsIdScenePromptsPost', 'id', id)
|
||||||
|
// verify required parameter 'createAssistantScenePromptRequest' is not null or undefined
|
||||||
|
assertParamExists('apiV1AssistantsIdScenePromptsPost', 'createAssistantScenePromptRequest', createAssistantScenePromptRequest)
|
||||||
|
const localVarPath = `/api/v1/assistants/{id}/scene_prompts`
|
||||||
|
.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(createAssistantScenePromptRequest, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 删除场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} sceneId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsSceneIdDelete: async (id: number, sceneId: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'id' is not null or undefined
|
||||||
|
assertParamExists('apiV1AssistantsIdScenePromptsSceneIdDelete', 'id', id)
|
||||||
|
// verify required parameter 'sceneId' is not null or undefined
|
||||||
|
assertParamExists('apiV1AssistantsIdScenePromptsSceneIdDelete', 'sceneId', sceneId)
|
||||||
|
const localVarPath = `/api/v1/assistants/{id}/scene_prompts/{scene_id}`
|
||||||
|
.replace(`{${"id"}}`, encodeURIComponent(String(id)))
|
||||||
|
.replace(`{${"scene_id"}}`, encodeURIComponent(String(sceneId)));
|
||||||
|
// 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: 'DELETE', ...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 获取 Assistant 所绑定的 Tool
|
* @summary 获取 Assistant 所绑定的 Tool
|
||||||
@ -3181,6 +3524,47 @@ export const AssistantApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarOperationServerBasePath = operationServerMap['AssistantApi.apiV1AssistantsIdPut']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['AssistantApi.apiV1AssistantsIdPut']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 列出当前助理的场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiV1AssistantsIdScenePromptsGet(id: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ApiV1AssistantsIdScenePromptsGet200Response>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1AssistantsIdScenePromptsGet(id, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['AssistantApi.apiV1AssistantsIdScenePromptsGet']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 创建场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {SchemaCreateAssistantScenePromptRequest} createAssistantScenePromptRequest CreateAssistantScenePromptRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiV1AssistantsIdScenePromptsPost(id: number, createAssistantScenePromptRequest: SchemaCreateAssistantScenePromptRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ApiV1AssistantsIdScenePromptsPost200Response>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1AssistantsIdScenePromptsPost(id, createAssistantScenePromptRequest, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['AssistantApi.apiV1AssistantsIdScenePromptsPost']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 删除场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} sceneId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiV1AssistantsIdScenePromptsSceneIdDelete(id: number, sceneId: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1AssistantsIdScenePromptsSceneIdDelete(id, sceneId, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['AssistantApi.apiV1AssistantsIdScenePromptsSceneIdDelete']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取 Assistant 所绑定的 Tool
|
* @summary 获取 Assistant 所绑定的 Tool
|
||||||
@ -3386,6 +3770,38 @@ export const AssistantApiFactory = function (configuration?: Configuration, base
|
|||||||
apiV1AssistantsIdPut(id: number, assistantUpdateRequest: SchemaAssistantUpdateRequest, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1AssistantsPost200Response> {
|
apiV1AssistantsIdPut(id: number, assistantUpdateRequest: SchemaAssistantUpdateRequest, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1AssistantsPost200Response> {
|
||||||
return localVarFp.apiV1AssistantsIdPut(id, assistantUpdateRequest, options).then((request) => request(axios, basePath));
|
return localVarFp.apiV1AssistantsIdPut(id, assistantUpdateRequest, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 列出当前助理的场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsGet(id: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1AssistantsIdScenePromptsGet200Response> {
|
||||||
|
return localVarFp.apiV1AssistantsIdScenePromptsGet(id, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 创建场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {SchemaCreateAssistantScenePromptRequest} createAssistantScenePromptRequest CreateAssistantScenePromptRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsPost(id: number, createAssistantScenePromptRequest: SchemaCreateAssistantScenePromptRequest, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1AssistantsIdScenePromptsPost200Response> {
|
||||||
|
return localVarFp.apiV1AssistantsIdScenePromptsPost(id, createAssistantScenePromptRequest, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 删除场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} sceneId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1AssistantsIdScenePromptsSceneIdDelete(id: number, sceneId: number, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.apiV1AssistantsIdScenePromptsSceneIdDelete(id, sceneId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取 Assistant 所绑定的 Tool
|
* @summary 获取 Assistant 所绑定的 Tool
|
||||||
@ -3590,6 +4006,44 @@ export class AssistantApi extends BaseAPI {
|
|||||||
return AssistantApiFp(this.configuration).apiV1AssistantsIdPut(id, assistantUpdateRequest, options).then((request) => request(this.axios, this.basePath));
|
return AssistantApiFp(this.configuration).apiV1AssistantsIdPut(id, assistantUpdateRequest, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 列出当前助理的场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof AssistantApi
|
||||||
|
*/
|
||||||
|
public apiV1AssistantsIdScenePromptsGet(id: number, options?: RawAxiosRequestConfig) {
|
||||||
|
return AssistantApiFp(this.configuration).apiV1AssistantsIdScenePromptsGet(id, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 创建场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {SchemaCreateAssistantScenePromptRequest} createAssistantScenePromptRequest CreateAssistantScenePromptRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof AssistantApi
|
||||||
|
*/
|
||||||
|
public apiV1AssistantsIdScenePromptsPost(id: number, createAssistantScenePromptRequest: SchemaCreateAssistantScenePromptRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return AssistantApiFp(this.configuration).apiV1AssistantsIdScenePromptsPost(id, createAssistantScenePromptRequest, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 删除场景 Prompt
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} sceneId
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof AssistantApi
|
||||||
|
*/
|
||||||
|
public apiV1AssistantsIdScenePromptsSceneIdDelete(id: number, sceneId: number, options?: RawAxiosRequestConfig) {
|
||||||
|
return AssistantApiFp(this.configuration).apiV1AssistantsIdScenePromptsSceneIdDelete(id, sceneId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取 Assistant 所绑定的 Tool
|
* @summary 获取 Assistant 所绑定的 Tool
|
||||||
@ -4286,6 +4740,48 @@ export const ChatMessageApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 {number} [page]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1ChatsIdMessagesPaginateGet: async (id: number, page?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'id' is not null or undefined
|
||||||
|
assertParamExists('apiV1ChatsIdMessagesPaginateGet', 'id', id)
|
||||||
|
const localVarPath = `/api/v1/chats/{id}/messages/paginate`
|
||||||
|
.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)
|
||||||
|
|
||||||
|
if (page !== undefined) {
|
||||||
|
localVarQueryParameter['page'] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
@ -4427,6 +4923,20 @@ export const ChatMessageApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarOperationServerBasePath = operationServerMap['ChatMessageApi.apiV1ChatsIdMessagesGet']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['ChatMessageApi.apiV1ChatsIdMessagesGet']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 获取一个对话的所有聊天记录
|
||||||
|
* @summary 分页获取聊天记录
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} [page]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiV1ChatsIdMessagesPaginateGet(id: number, page?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ApiV1ChatsIdMessagesPaginateGet200Response>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.apiV1ChatsIdMessagesPaginateGet(id, page, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['ChatMessageApi.apiV1ChatsIdMessagesPaginateGet']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 添加一条消息
|
* 添加一条消息
|
||||||
* @summary 添加聊天记录
|
* @summary 添加聊天记录
|
||||||
@ -4496,6 +5006,17 @@ export const ChatMessageApiFactory = function (configuration?: Configuration, ba
|
|||||||
apiV1ChatsIdMessagesGet(id: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1ChatsIdMessagesGet200Response> {
|
apiV1ChatsIdMessagesGet(id: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1ChatsIdMessagesGet200Response> {
|
||||||
return localVarFp.apiV1ChatsIdMessagesGet(id, options).then((request) => request(axios, basePath));
|
return localVarFp.apiV1ChatsIdMessagesGet(id, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 获取一个对话的所有聊天记录
|
||||||
|
* @summary 分页获取聊天记录
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} [page]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiV1ChatsIdMessagesPaginateGet(id: number, page?: number, options?: RawAxiosRequestConfig): AxiosPromise<ApiV1ChatsIdMessagesPaginateGet200Response> {
|
||||||
|
return localVarFp.apiV1ChatsIdMessagesPaginateGet(id, page, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 添加一条消息
|
* 添加一条消息
|
||||||
* @summary 添加聊天记录
|
* @summary 添加聊天记录
|
||||||
@ -4565,6 +5086,19 @@ export class ChatMessageApi extends BaseAPI {
|
|||||||
return ChatMessageApiFp(this.configuration).apiV1ChatsIdMessagesGet(id, options).then((request) => request(this.axios, this.basePath));
|
return ChatMessageApiFp(this.configuration).apiV1ChatsIdMessagesGet(id, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一个对话的所有聊天记录
|
||||||
|
* @summary 分页获取聊天记录
|
||||||
|
* @param {number} id
|
||||||
|
* @param {number} [page]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof ChatMessageApi
|
||||||
|
*/
|
||||||
|
public apiV1ChatsIdMessagesPaginateGet(id: number, page?: number, options?: RawAxiosRequestConfig) {
|
||||||
|
return ChatMessageApiFp(this.configuration).apiV1ChatsIdMessagesPaginateGet(id, page, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一条消息
|
* 添加一条消息
|
||||||
* @summary 添加聊天记录
|
* @summary 添加聊天记录
|
||||||
|
2
src/components.d.ts
vendored
2
src/components.d.ts
vendored
@ -9,7 +9,6 @@ declare module 'vue' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AccountSettings: typeof import('./components/settings/AccountSettings.vue')['default']
|
AccountSettings: typeof import('./components/settings/AccountSettings.vue')['default']
|
||||||
AssistantMenu: typeof import('./components/AssistantMenu.vue')['default']
|
AssistantMenu: typeof import('./components/AssistantMenu.vue')['default']
|
||||||
AssistantPublistSettings: typeof import('./components/settings/AssistantPublistSettings.vue')['default']
|
|
||||||
AssistantSettings: typeof import('./components/settings/AssistantSettings.vue')['default']
|
AssistantSettings: typeof import('./components/settings/AssistantSettings.vue')['default']
|
||||||
Chat: typeof import('./components/chat/Chat.vue')['default']
|
Chat: typeof import('./components/chat/Chat.vue')['default']
|
||||||
ChatMenu: typeof import('./components/ChatMenu.vue')['default']
|
ChatMenu: typeof import('./components/ChatMenu.vue')['default']
|
||||||
@ -18,6 +17,7 @@ declare module 'vue' {
|
|||||||
LeftSettings: typeof import('./components/settings/LeftSettings.vue')['default']
|
LeftSettings: typeof import('./components/settings/LeftSettings.vue')['default']
|
||||||
LibrarySettings: typeof import('./components/settings/LibrarySettings.vue')['default']
|
LibrarySettings: typeof import('./components/settings/LibrarySettings.vue')['default']
|
||||||
Lottie: typeof import('./components/Lottie.vue')['default']
|
Lottie: typeof import('./components/Lottie.vue')['default']
|
||||||
|
Markdown: typeof import('./components/markdown/index.vue')['default']
|
||||||
Mask: typeof import('./components/Mask.vue')['default']
|
Mask: typeof import('./components/Mask.vue')['default']
|
||||||
MemorySettings: typeof import('./components/settings/MemorySettings.vue')['default']
|
MemorySettings: typeof import('./components/settings/MemorySettings.vue')['default']
|
||||||
Menu: typeof import('./components/Menu.vue')['default']
|
Menu: typeof import('./components/Menu.vue')['default']
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
<n-text depth="3">
|
<n-text depth="3">
|
||||||
我们有一些预设提示词,您可以点击来一键输入。
|
我们有一些预设提示词,您可以点击来一键输入。
|
||||||
</n-text>
|
</n-text>
|
||||||
<n-scrollbar style="max-height: 400px">
|
<n-scrollbar style="max-height: 400px" class="mt-3">
|
||||||
<n-grid cols="1 s:2 l:3" responsive="screen">
|
<n-grid cols="1 m:2 l:3" responsive="screen">
|
||||||
<n-gi v-for="p in prompts" class="rounded-lg p-2">
|
<n-gi v-for="p in prompts" class="rounded-lg p-2">
|
||||||
<n-card
|
<n-card
|
||||||
:title="p.act"
|
:title="p.act"
|
||||||
@ -60,7 +60,7 @@
|
|||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="min-w-full pt-2 relative " style="max-height: 120px">
|
<div class="min-w-full pt-2 relative" style="max-height: 120px">
|
||||||
<div class="relative bottom-0 pr-2 pl-2 min-w-full" ref="textContainer">
|
<div class="relative bottom-0 pr-2 pl-2 min-w-full" ref="textContainer">
|
||||||
<div
|
<div
|
||||||
class="mx-auto w-2xl max-w-2xl text-center mb-3 animate__animated animate__pulse text-lg"
|
class="mx-auto w-2xl max-w-2xl text-center mb-3 animate__animated animate__pulse text-lg"
|
||||||
@ -674,11 +674,36 @@ function streamChat(streamId: String, redirect = false) {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "tool_calling":
|
case "tool_calling":
|
||||||
|
if (data.tool_call_message.function_name.startsWith("builtin_")) {
|
||||||
|
if (data.tool_call_message.function_name === "builtin_browser") {
|
||||||
|
let url = data.tool_call_message.args.query_or_url;
|
||||||
|
// 如果是 URL
|
||||||
|
if (url.startsWith("http")) {
|
||||||
|
chatStore.toolName = "正在浏览 " + url;
|
||||||
|
} else {
|
||||||
|
chatStore.toolName = "正在搜索 " + url;
|
||||||
|
}
|
||||||
|
} else if (data.tool_call_message.function_name === "builtin_calculator") {
|
||||||
|
chatStore.toolName = "正在计算";
|
||||||
|
} else if (
|
||||||
|
data.tool_call_message.function_name === "builtin_generate_image"
|
||||||
|
) {
|
||||||
|
chatStore.toolName = "生成图片中";
|
||||||
|
} else if (
|
||||||
|
data.tool_call_message.function_name === "builtin_describe_image"
|
||||||
|
) {
|
||||||
|
chatStore.toolName = "正在理解图片";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chatStore.toolName =
|
||||||
|
"正在执行 " +
|
||||||
|
data.tool_call_message.tool_name +
|
||||||
|
" 中的 " +
|
||||||
|
data.tool_call_message.function_name;
|
||||||
|
}
|
||||||
|
|
||||||
// toolCalling.value = true;
|
// toolCalling.value = true;
|
||||||
chatStore.toolName =
|
|
||||||
data.tool_call_message.tool_name +
|
|
||||||
" 中的 " +
|
|
||||||
data.tool_call_message.function_name;
|
|
||||||
// toolName.value =
|
// toolName.value =
|
||||||
// data.tool_call_message.tool_name +
|
// data.tool_call_message.tool_name +
|
||||||
// " 中的 " +
|
// " 中的 " +
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
</n-thing>
|
</n-thing>
|
||||||
</n-list-item>
|
</n-list-item>
|
||||||
</n-list>
|
</n-list>
|
||||||
<div v-else>
|
<div v-else class="mt-8">
|
||||||
<n-result
|
<n-result
|
||||||
status="404"
|
status="404"
|
||||||
title="你还没有对话"
|
title="你还没有对话"
|
||||||
@ -99,6 +99,9 @@ const deleteChat = async (chatId: number) => {
|
|||||||
onPositiveClick: async () => {
|
onPositiveClick: async () => {
|
||||||
await getApi().Chat.apiV1ChatsIdDelete(chatId);
|
await getApi().Chat.apiV1ChatsIdDelete(chatId);
|
||||||
await getChats();
|
await getChats();
|
||||||
|
if (parseInt(router.currentRoute.value.params.id) === chatId) {
|
||||||
|
router.push("/")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -35,7 +35,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="(message.role === 'user' || message.role === 'user_hide' || message.role === 'user_later') && message.content">
|
<div
|
||||||
|
v-else-if="
|
||||||
|
(message.role === 'user' ||
|
||||||
|
message.role === 'user_hide' ||
|
||||||
|
message.role === 'user_later') &&
|
||||||
|
message.content
|
||||||
|
"
|
||||||
|
>
|
||||||
<!-- 用户消息 -->
|
<!-- 用户消息 -->
|
||||||
<n-flex justify="end">
|
<n-flex justify="end">
|
||||||
<div class="flex items-center flex-nowrap">
|
<div class="flex items-center flex-nowrap">
|
||||||
@ -51,11 +58,14 @@
|
|||||||
{{ userStore.user.name }}
|
{{ userStore.user.name }}
|
||||||
</n-divider>
|
</n-divider>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<!-- <div
|
||||||
v-if="mdInited"
|
v-if="mdInited"
|
||||||
class="break-all break-words markdown-body"
|
class="break-all break-words markdown-body"
|
||||||
v-html="mdIt.render(message.content)"
|
v-html="mdIt.render(message.content)"
|
||||||
></div>
|
></div> -->
|
||||||
|
<div>
|
||||||
|
<Markdown :typing="false" :content="message.content" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative h-full">
|
<div class="relative h-full">
|
||||||
@ -103,11 +113,10 @@
|
|||||||
{{ message.assistant?.name }}
|
{{ message.assistant?.name }}
|
||||||
</n-divider>
|
</n-divider>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="mdInited"
|
<div>
|
||||||
class="break-all break-words markdown-body"
|
<Markdown :typing="false" :content="message.content" />
|
||||||
v-html="mdIt.render(message.content)"
|
</div>
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div v-html="mdIt.render(message.content)"></div> -->
|
<!-- <div v-html="mdIt.render(message.content)"></div> -->
|
||||||
|
|
||||||
@ -126,50 +135,9 @@ import { Ref } from "vue";
|
|||||||
import { EntityChatMessage } from "@/api";
|
import { EntityChatMessage } from "@/api";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import leaflowPng from "@/assets/images/leaflow.png";
|
import leaflowPng from "@/assets/images/leaflow.png";
|
||||||
import markdownKatex from "@traptitech/markdown-it-katex";
|
import Markdown from "@/components/markdown/index.vue";
|
||||||
import markdownIt from "markdown-it";
|
|
||||||
// highlightjs
|
|
||||||
import hljs from "highlight.js";
|
|
||||||
import config from "@/config/config";
|
import config from "@/config/config";
|
||||||
|
|
||||||
const mdIt = markdownIt();
|
|
||||||
const mdInited = ref(true);
|
|
||||||
|
|
||||||
const unsupportedLanguages = ["assembly", "blade", "vue"];
|
|
||||||
mdIt.options.highlight = function (str: string, lang: string) {
|
|
||||||
// TODO: 前面的区域以后再来探索吧
|
|
||||||
lang = "text"
|
|
||||||
if (!lang || unsupportedLanguages.includes(lang)) {
|
|
||||||
// return str;
|
|
||||||
lang = "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
return hljs.highlight(str, { language: lang }).value;
|
|
||||||
};
|
|
||||||
mdIt.use(markdownKatex, {
|
|
||||||
throwOnError: false,
|
|
||||||
errorColor: "#cc0000",
|
|
||||||
output: "html",
|
|
||||||
});
|
|
||||||
|
|
||||||
// async function initMD() {
|
|
||||||
// mdIt.use(
|
|
||||||
// await Shiki({
|
|
||||||
// themes: {
|
|
||||||
// light: "vitesse-light",
|
|
||||||
// dark: "vitesse-dark",
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
|
|
||||||
// mdIt.use(markdownKatex, {
|
|
||||||
// throwOnError: false,
|
|
||||||
// errorColor: "#cc0000",
|
|
||||||
// output: "html",
|
|
||||||
// });
|
|
||||||
|
|
||||||
// mdInited.value = true;
|
|
||||||
// }
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -182,7 +150,4 @@ const props = defineProps({
|
|||||||
const chat_messages = toRef(props, "chat_messages") as Ref<EntityChatMessage[]>;
|
const chat_messages = toRef(props, "chat_messages") as Ref<EntityChatMessage[]>;
|
||||||
const fileBaseUrl = config.backend + "/api/v1/files";
|
const fileBaseUrl = config.backend + "/api/v1/files";
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// initMD();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
17
src/components/markdown/aPlugin/index.ts
Normal file
17
src/components/markdown/aPlugin/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { PluginWithOptions } from 'markdown-it'
|
||||||
|
|
||||||
|
export interface APluginOptions {}
|
||||||
|
|
||||||
|
export const aPlugin: PluginWithOptions<APluginOptions> = (
|
||||||
|
md,
|
||||||
|
options = {}
|
||||||
|
): void => {
|
||||||
|
md.renderer.rules.link_open = (tokens, idx, options, env, slf) => {
|
||||||
|
const aIndex = tokens[idx].attrIndex('href')
|
||||||
|
|
||||||
|
if (aIndex !== -1) {
|
||||||
|
tokens[idx].attrs.push(['target', '_blank'])
|
||||||
|
}
|
||||||
|
return slf.renderToken(tokens, idx, options)
|
||||||
|
}
|
||||||
|
}
|
52
src/components/markdown/codePlugin/index.ts
Normal file
52
src/components/markdown/codePlugin/index.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import type { PluginWithOptions } from 'markdown-it'
|
||||||
|
|
||||||
|
import { resolveLanguage } from './resolveLanguage.js'
|
||||||
|
import { resolveLineNumbers } from './resolveLineNumbers.js'
|
||||||
|
|
||||||
|
export interface CodePluginOptions {
|
||||||
|
lineNumbers?: boolean | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const codePlugin: PluginWithOptions<CodePluginOptions> = (
|
||||||
|
md,
|
||||||
|
{ lineNumbers = true } = {}
|
||||||
|
): void => {
|
||||||
|
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
|
||||||
|
const token = tokens[idx]
|
||||||
|
const info = token.info ? md.utils.unescapeAll(token.info).trim() : ''
|
||||||
|
const language = resolveLanguage(info)
|
||||||
|
const languageClass = `${options.langPrefix}${language.name}`
|
||||||
|
|
||||||
|
const code =
|
||||||
|
options.highlight?.(token.content, language.name, '') ||
|
||||||
|
md.utils.escapeHtml(token.content)
|
||||||
|
|
||||||
|
token.attrJoin('class', languageClass)
|
||||||
|
let result = code.startsWith('<pre')
|
||||||
|
? code
|
||||||
|
: `<pre${slf.renderAttrs(token)}><code>${code}</code></pre>`
|
||||||
|
result = `<div data-ext="${language.ext}" v-pre class="code-copy-line">
|
||||||
|
<div class="code-copy-btn">复制代码</div>
|
||||||
|
</div>${result}`
|
||||||
|
const lines = code.split('\n').slice(0, -1)
|
||||||
|
|
||||||
|
const useLineNumbers =
|
||||||
|
resolveLineNumbers(info) ??
|
||||||
|
(typeof lineNumbers === 'number'
|
||||||
|
? lines.length >= lineNumbers
|
||||||
|
: lineNumbers)
|
||||||
|
if (useLineNumbers) {
|
||||||
|
const lineNumbersCode = lines
|
||||||
|
.map(() => `<div class="line-number"></div>`)
|
||||||
|
.join('')
|
||||||
|
|
||||||
|
result = `<div class="line-numbers" aria-hidden="true">${lineNumbersCode}</div>${result}`
|
||||||
|
}
|
||||||
|
|
||||||
|
result = `<div><div class="${languageClass}${
|
||||||
|
useLineNumbers ? ' line-numbers-mode' : ''
|
||||||
|
}"><div class="pre-code-scroll">${result}</div></div></div>`
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
105
src/components/markdown/codePlugin/languages.ts
Normal file
105
src/components/markdown/codePlugin/languages.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Language type for syntax highlight
|
||||||
|
*/
|
||||||
|
export interface HighlightLanguage {
|
||||||
|
/**
|
||||||
|
* Name of the language
|
||||||
|
*
|
||||||
|
* The name to be used for the class name,
|
||||||
|
* e.g. `class="language-typescript"`
|
||||||
|
*/
|
||||||
|
name: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of the language
|
||||||
|
*
|
||||||
|
* The file extension, which will be used for the
|
||||||
|
* class name, e.g. `class="ext-ts"`
|
||||||
|
*/
|
||||||
|
ext: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases that point to this language
|
||||||
|
*
|
||||||
|
* Do not conflict with other languages
|
||||||
|
*/
|
||||||
|
aliases: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageBash: HighlightLanguage = {
|
||||||
|
name: 'bash',
|
||||||
|
ext: 'sh',
|
||||||
|
aliases: ['bash', 'sh', 'shell', 'zsh']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageCsharp: HighlightLanguage = {
|
||||||
|
name: 'csharp',
|
||||||
|
ext: 'cs',
|
||||||
|
aliases: ['cs', 'csharp']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageDocker: HighlightLanguage = {
|
||||||
|
name: 'docker',
|
||||||
|
ext: 'docker',
|
||||||
|
aliases: ['docker', 'dockerfile']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageFsharp: HighlightLanguage = {
|
||||||
|
name: 'fsharp',
|
||||||
|
ext: 'fs',
|
||||||
|
aliases: ['fs', 'fsharp']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageJavascript: HighlightLanguage = {
|
||||||
|
name: 'javascript',
|
||||||
|
ext: 'js',
|
||||||
|
aliases: ['javascript', 'js']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageKotlin: HighlightLanguage = {
|
||||||
|
name: 'kotlin',
|
||||||
|
ext: 'kt',
|
||||||
|
aliases: ['kotlin', 'kt']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageMarkdown: HighlightLanguage = {
|
||||||
|
name: 'markdown',
|
||||||
|
ext: 'md',
|
||||||
|
aliases: ['markdown', 'md']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languagePython: HighlightLanguage = {
|
||||||
|
name: 'python',
|
||||||
|
ext: 'py',
|
||||||
|
aliases: ['py', 'python']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageRuby: HighlightLanguage = {
|
||||||
|
name: 'ruby',
|
||||||
|
ext: 'rb',
|
||||||
|
aliases: ['rb', 'ruby']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageRust: HighlightLanguage = {
|
||||||
|
name: 'rust',
|
||||||
|
ext: 'rs',
|
||||||
|
aliases: ['rs', 'rust']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageStylus: HighlightLanguage = {
|
||||||
|
name: 'stylus',
|
||||||
|
ext: 'styl',
|
||||||
|
aliases: ['styl', 'stylus']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageTypescript: HighlightLanguage = {
|
||||||
|
name: 'typescript',
|
||||||
|
ext: 'ts',
|
||||||
|
aliases: ['ts', 'typescript']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const languageYaml: HighlightLanguage = {
|
||||||
|
name: 'yaml',
|
||||||
|
ext: 'yml',
|
||||||
|
aliases: ['yaml', 'yml']
|
||||||
|
}
|
46
src/components/markdown/codePlugin/resolveLanguage.ts
Normal file
46
src/components/markdown/codePlugin/resolveLanguage.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import * as languages from './languages.js'
|
||||||
|
import type { HighlightLanguage } from './languages.js'
|
||||||
|
|
||||||
|
type LanguagesMap = Record<string, HighlightLanguage>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key-value map to get language info from alias
|
||||||
|
*
|
||||||
|
* - key: alias
|
||||||
|
* - value: language
|
||||||
|
*/
|
||||||
|
let languagesMap: LanguagesMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazy generate languages map
|
||||||
|
*/
|
||||||
|
const getLanguagesMap = (): LanguagesMap => {
|
||||||
|
if (!languagesMap) {
|
||||||
|
languagesMap = Object.values(languages).reduce((result, item) => {
|
||||||
|
item.aliases.forEach((alias) => {
|
||||||
|
result[alias] = item
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}, {} as LanguagesMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
return languagesMap
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve language for highlight from token info
|
||||||
|
*/
|
||||||
|
export const resolveLanguage = (info: string): HighlightLanguage => {
|
||||||
|
// get user-defined language alias
|
||||||
|
const alias = info.match(/^([^ :[{]+)/)?.[1] || ''
|
||||||
|
|
||||||
|
// if the alias does not have a match in the map
|
||||||
|
// fallback to the alias itself
|
||||||
|
return (
|
||||||
|
getLanguagesMap()[alias] ?? {
|
||||||
|
name: alias,
|
||||||
|
ext: alias,
|
||||||
|
aliases: [alias]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
14
src/components/markdown/codePlugin/resolveLineNumbers.ts
Normal file
14
src/components/markdown/codePlugin/resolveLineNumbers.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Resolve the `:line-numbers` / `:no-line-numbers` mark from token info
|
||||||
|
*/
|
||||||
|
export const resolveLineNumbers = (info: string): boolean | null => {
|
||||||
|
if (/:line-numbers\b/.test(info)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/:no-line-numbers\b/.test(info)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
76
src/components/markdown/customLink/index.ts
Normal file
76
src/components/markdown/customLink/index.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import type { PluginWithOptions } from 'markdown-it'
|
||||||
|
|
||||||
|
const defaultMarker = '#'
|
||||||
|
interface CustomLinkPluginOptions {
|
||||||
|
marker: string
|
||||||
|
}
|
||||||
|
export const customLinkPlugin: PluginWithOptions<
|
||||||
|
Partial<CustomLinkPluginOptions>
|
||||||
|
> = (md, options = {}): void => {
|
||||||
|
const marker = options.marker || defaultMarker
|
||||||
|
|
||||||
|
md.block.ruler.before(
|
||||||
|
'paragraph',
|
||||||
|
'custom_link',
|
||||||
|
function (state, startLine, endLine, silent) {
|
||||||
|
const pos = state.bMarks[startLine] + state.tShift[startLine]
|
||||||
|
const max = state.eMarks[startLine]
|
||||||
|
|
||||||
|
if (pos >= max) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (silent) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const text = state.src.substring(pos, max)
|
||||||
|
const start = text.indexOf(marker)
|
||||||
|
const end = text.lastIndexOf(marker)
|
||||||
|
if (start < 0 || end < 0 || start == end) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//#...#规则前面的内容
|
||||||
|
const startContent = text.substring(0, start)
|
||||||
|
//#...#规则后面的内容
|
||||||
|
const endContent = text.substring(end + 1)
|
||||||
|
//#...#规则中间的内容
|
||||||
|
const content = text.substring(start + 1, end)
|
||||||
|
|
||||||
|
//插入<div>
|
||||||
|
const token_div_o = state.push('div_open', 'div', 1)
|
||||||
|
token_div_o.map = [startLine, state.line]
|
||||||
|
|
||||||
|
//插入#...#规则前面的内容
|
||||||
|
const token_s = state.push('inline', '', 0)
|
||||||
|
token_s.content = startContent
|
||||||
|
token_s.children = []
|
||||||
|
|
||||||
|
//插入<a class="markdown-custom-link">
|
||||||
|
const token_a_o = state.push('link_open', 'a', 1)
|
||||||
|
token_a_o.attrs = [['class', 'markdown-custom-link']]
|
||||||
|
token_a_o.map = [startLine, state.line]
|
||||||
|
|
||||||
|
//插入#...#规则中间的内容
|
||||||
|
const token = state.push('inline', '', 0)
|
||||||
|
token.content = content
|
||||||
|
token.children = []
|
||||||
|
|
||||||
|
//闭合a标签
|
||||||
|
state.push('link_close', 'a', -1)
|
||||||
|
const token_e = state.push('inline', '', 0)
|
||||||
|
|
||||||
|
//插入#...#规则后面的内容
|
||||||
|
token_e.content = endContent
|
||||||
|
token_e.children = []
|
||||||
|
|
||||||
|
//闭合div标签
|
||||||
|
state.push('div_close', 'div', -1)
|
||||||
|
|
||||||
|
state.line = startLine + 1
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alt: ['paragraph', 'reference', 'blockquote']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
1102
src/components/markdown/github-markdown.css
Normal file
1102
src/components/markdown/github-markdown.css
Normal file
File diff suppressed because it is too large
Load Diff
166
src/components/markdown/index.vue
Normal file
166
src/components/markdown/index.vue
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="markdown-it-container">
|
||||||
|
<div
|
||||||
|
ref="markdownBodyRef"
|
||||||
|
class="markdown-body"
|
||||||
|
@click="handleClick($event)"
|
||||||
|
v-html="result"
|
||||||
|
/>
|
||||||
|
<div v-if="typing" class="markdown-typing" :style="cursorPosition"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import MarkdownIt from 'markdown-it'
|
||||||
|
import hljs from 'highlight.js'
|
||||||
|
// import 'highlight.js/styles/atom-one-dark.css'
|
||||||
|
// import './github-markdown.css'
|
||||||
|
// @ts-ignore
|
||||||
|
import markdownItMath from '@iktakahiro/markdown-it-katex'
|
||||||
|
import type {CodePluginOptions} from './codePlugin'
|
||||||
|
import {codePlugin} from './codePlugin'
|
||||||
|
import {customLinkPlugin} from './customLink'
|
||||||
|
import {aPlugin} from './aPlugin'
|
||||||
|
|
||||||
|
interface Options extends Partial<MarkdownIt.Options> {
|
||||||
|
lineNumbers?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
content: string
|
||||||
|
html?: boolean
|
||||||
|
breaks?: boolean
|
||||||
|
linkify?: boolean
|
||||||
|
typographer?: boolean
|
||||||
|
// 是否显示代码行
|
||||||
|
lineNumbers?: boolean
|
||||||
|
// 是否显示打字效果
|
||||||
|
typing: boolean
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
content: '',
|
||||||
|
html: true,
|
||||||
|
breaks: true,
|
||||||
|
typographer: true,
|
||||||
|
linkify: true,
|
||||||
|
lineNumbers: true,
|
||||||
|
typing: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: 'click-custom-link', value: string): void
|
||||||
|
}>()
|
||||||
|
const result = ref('')
|
||||||
|
const markdownBodyRef = shallowRef<HTMLDivElement>()
|
||||||
|
const createMarkdown = (options: Options) => {
|
||||||
|
const md = new MarkdownIt({
|
||||||
|
...options,
|
||||||
|
langPrefix: 'language-',
|
||||||
|
highlight(str: any, lang: any) {
|
||||||
|
try {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
return hljs.highlight(lang, str, true).value
|
||||||
|
}
|
||||||
|
return hljs.highlightAuto(str).value
|
||||||
|
} catch (error) {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
md.use<CodePluginOptions>(codePlugin, {
|
||||||
|
lineNumbers: options.lineNumbers
|
||||||
|
})
|
||||||
|
md.use(markdownItMath, {
|
||||||
|
output: 'mathml'
|
||||||
|
})
|
||||||
|
md.use(aPlugin)
|
||||||
|
md.use(customLinkPlugin)
|
||||||
|
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
let md: MarkdownIt
|
||||||
|
|
||||||
|
const findLastTextNode = (parent: Node): Node | undefined => {
|
||||||
|
const children = parent.childNodes
|
||||||
|
for (let i = children.length - 1; i >= 0; i--) {
|
||||||
|
const node = children[i]
|
||||||
|
if (node.nodeType === Node.TEXT_NODE && /\S/.test(node.nodeValue!)) {
|
||||||
|
node.nodeValue?.replace(/\S+$/, '')
|
||||||
|
return node
|
||||||
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
const lastNode = findLastTextNode(node)
|
||||||
|
if (lastNode) {
|
||||||
|
return lastNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cursorPosition = reactive({
|
||||||
|
top: 'auto',
|
||||||
|
left: 'auto'
|
||||||
|
})
|
||||||
|
const updateCursor = () => {
|
||||||
|
if (markdownBodyRef.value) {
|
||||||
|
const lastTextNode = findLastTextNode(markdownBodyRef.value)
|
||||||
|
const textNode = document.createTextNode('\u200B')
|
||||||
|
if (lastTextNode) {
|
||||||
|
lastTextNode.parentElement?.appendChild(textNode)
|
||||||
|
} else {
|
||||||
|
markdownBodyRef.value?.appendChild(textNode)
|
||||||
|
}
|
||||||
|
const range = document.createRange()
|
||||||
|
range.setStart(textNode, 0)
|
||||||
|
range.setEnd(textNode, 0)
|
||||||
|
const textRect = range.getBoundingClientRect()
|
||||||
|
const markdownBodyRect = markdownBodyRef.value?.getBoundingClientRect()
|
||||||
|
cursorPosition.left = `${textRect.left - markdownBodyRect.left}px`
|
||||||
|
cursorPosition.top = `${textRect.top - markdownBodyRect.top}px`
|
||||||
|
textNode.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const preprocessContent = (content: string) => {
|
||||||
|
return content.replace(/\n(#.*#)/g, '\n\n$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
md = createMarkdown({
|
||||||
|
html: props.html,
|
||||||
|
breaks: props.breaks,
|
||||||
|
typographer: props.typographer,
|
||||||
|
linkify: props.linkify,
|
||||||
|
lineNumbers: props.lineNumbers
|
||||||
|
})
|
||||||
|
result.value = md.render(preprocessContent(props.content))
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.content,
|
||||||
|
async (value) => {
|
||||||
|
result.value = md?.render(preprocessContent(value))
|
||||||
|
await nextTick()
|
||||||
|
updateCursor()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const handleClick = async (e: any) => {
|
||||||
|
console.log(e.target)
|
||||||
|
const target: HTMLElement = e.target
|
||||||
|
if (target.className === 'code-copy-btn') {
|
||||||
|
const text = e.target.parentElement.nextElementSibling.textContent
|
||||||
|
// copy text to clipboard
|
||||||
|
await navigator.clipboard.writeText(text)
|
||||||
|
}
|
||||||
|
if (target.className === 'markdown-custom-link') {
|
||||||
|
emit('click-custom-link', target.textContent!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use 'markdown.scss';
|
||||||
|
</style>
|
212
src/components/markdown/markdown.scss
Normal file
212
src/components/markdown/markdown.scss
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
$line-height: 1.375;
|
||||||
|
:root {
|
||||||
|
--code-bg-color: #35373f;
|
||||||
|
--code-hl-bg-color: rgba(0, 0, 0, 0.66);
|
||||||
|
--code-ln-color: #6e6e7f;
|
||||||
|
--code-ln-wrapper-width: 3.5rem;
|
||||||
|
}
|
||||||
|
@keyframes blink {
|
||||||
|
from,
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.markdown-it-container {
|
||||||
|
.markdown-body {
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: 15px;
|
||||||
|
.markdown-custom-link {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position: relative;
|
||||||
|
.markdown-typing {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 14px;
|
||||||
|
transform: translate(4px, 2px) scaleY(1.3);
|
||||||
|
color: #1a202c;
|
||||||
|
background-color: currentColor;
|
||||||
|
animation: blink 0.6s infinite;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
padding: 0.25rem;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.85em;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
color: #ccc;
|
||||||
|
background: none;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
pre[class*='language-'] {
|
||||||
|
padding: 20px 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre) > code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
font-size: 0.85em;
|
||||||
|
background: #35373f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
:not(pre) > code[class*='language-'] {
|
||||||
|
border-radius: 0.3em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
pre[class*='language-'] {
|
||||||
|
line-height: $line-height;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: visible;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px;
|
||||||
|
code {
|
||||||
|
color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-radius: 0;
|
||||||
|
overflow-wrap: unset;
|
||||||
|
-webkit-font-smoothing: auto;
|
||||||
|
-moz-osx-font-smoothing: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div[class*='language-'] {
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--code-bg-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding-top: 32px;
|
||||||
|
margin: 0.85rem 0;
|
||||||
|
overflow: hidden;
|
||||||
|
.code-copy-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #595b63;
|
||||||
|
color: #e0e0e0;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
font-size: 12px;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 12px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: attr(data-ext);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
top: 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
.code-copy-btn {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
top: 0;
|
||||||
|
right: 1rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #e0e0e0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
pre[class*='language-'] {
|
||||||
|
// force override the background color to be compatible with shiki
|
||||||
|
background: transparent !important;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.pre-code-scroll {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.line-numbers-mode) {
|
||||||
|
.line-numbers {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line-numbers-mode {
|
||||||
|
padding-left: var(--code-ln-wrapper-width);
|
||||||
|
pre {
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 20px 20px 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers {
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: var(--code-ln-wrapper-width);
|
||||||
|
text-align: center;
|
||||||
|
color: var(--code-ln-color);
|
||||||
|
padding-top: 52px;
|
||||||
|
line-height: $line-height;
|
||||||
|
counter-reset: line-number;
|
||||||
|
|
||||||
|
.line-number {
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
user-select: none;
|
||||||
|
height: #{$line-height - 0.2}em;
|
||||||
|
&::before {
|
||||||
|
display: block;
|
||||||
|
counter-increment: line-number;
|
||||||
|
content: counter(line-number);
|
||||||
|
font-size: 0.8em;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// &::after {
|
||||||
|
// content: "";
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
// width: var(--code-ln-wrapper-width);
|
||||||
|
// height: 100%;
|
||||||
|
// border-radius: 6px 0 0 6px;
|
||||||
|
// border-right: 1px solid var(--code-hl-bg-color);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -93,6 +93,14 @@
|
|||||||
禁用默认提示词
|
禁用默认提示词
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<n-switch
|
||||||
|
v-model:value="currentAssistant.disable_web_browsing"
|
||||||
|
>
|
||||||
|
</n-switch>
|
||||||
|
禁用联网
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<n-switch v-model:value="currentAssistant.disable_memory">
|
<n-switch v-model:value="currentAssistant.disable_memory">
|
||||||
</n-switch>
|
</n-switch>
|
||||||
@ -110,10 +118,10 @@
|
|||||||
允许助理 API 读取记忆
|
允许助理 API 读取记忆
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<!-- <div>
|
||||||
<n-switch v-model:value="currentAssistant.public"> </n-switch>
|
<n-switch v-model:value="currentAssistant.public"> </n-switch>
|
||||||
公开分享助理(弃用)
|
公开分享助理(弃用)
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
话语随机性 (Temperature)
|
话语随机性 (Temperature)
|
||||||
@ -160,6 +168,82 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<n-divider v-if="!scenePrompts.length" />
|
||||||
|
<div v-else class="mt-10"></div>
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between align-middle items-center">
|
||||||
|
<div>
|
||||||
|
<n-h3 class="inline">场景提示词</n-h3>
|
||||||
|
<n-popover trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-icon size="16"><HelpCircleOutline /></n-icon>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<n-text
|
||||||
|
>Amber 可以根据不同的上下文场景来自动附加系统提示词</n-text
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-popover>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<n-button
|
||||||
|
tertiary
|
||||||
|
@click="showCreateScenePromptForm = !showCreateScenePromptForm"
|
||||||
|
>
|
||||||
|
新场景提示词
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="showCreateScenePromptForm" class="mt-3">
|
||||||
|
<n-card title="新场景提示词" role="dialog">
|
||||||
|
<n-input
|
||||||
|
v-model:value="newScenePrompt.label"
|
||||||
|
type="text"
|
||||||
|
placeholder="标签"
|
||||||
|
/>
|
||||||
|
<n-input
|
||||||
|
class="mt-3"
|
||||||
|
v-model:value="newScenePrompt.prompt"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="提示词"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="text-right mt-3">
|
||||||
|
<n-button type="primary" @click="createAssistantScenePrompt"
|
||||||
|
>创建</n-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<n-list hoverable clickable v-if="scenePrompts.length" class="mt-3">
|
||||||
|
<n-list-item v-for="c in scenePrompts" :key="c.id">
|
||||||
|
<n-thing :title="c.label">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>{{ c.prompt }}</div>
|
||||||
|
<div>
|
||||||
|
<n-popconfirm
|
||||||
|
@positive-click="deleteAssistantScenePrompt(c.id ?? 0)"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<n-button quaternary circle type="warning">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon size="16" class="cursor-pointer">
|
||||||
|
<TrashBinOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<div>删除后,这条规则将不再生效</div>
|
||||||
|
</n-popconfirm>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-thing>
|
||||||
|
</n-list-item>
|
||||||
|
</n-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<n-divider v-if="!userTools.length" />
|
<n-divider v-if="!userTools.length" />
|
||||||
<div v-else class="mt-10"></div>
|
<div v-else class="mt-10"></div>
|
||||||
<div>
|
<div>
|
||||||
@ -178,7 +262,8 @@
|
|||||||
<n-text>
|
<n-text>
|
||||||
我们的 API 端点是:{{
|
我们的 API 端点是:{{
|
||||||
config.backend
|
config.backend
|
||||||
}}/api/openai-compatible/v1 。密钥为下方的 API Key,OpenAI 格式不支持智能上下文(不支持近乎无限的上下文)
|
}}/api/openai-compatible/v1 。密钥为下方的 API Key,OpenAI
|
||||||
|
格式不支持智能上下文(不支持近乎无限的上下文)
|
||||||
</n-text>
|
</n-text>
|
||||||
</div>
|
</div>
|
||||||
</n-popover>
|
</n-popover>
|
||||||
@ -194,11 +279,20 @@
|
|||||||
等做一个请求限制),来防止 API Key 滥用。
|
等做一个请求限制),来防止 API Key 滥用。
|
||||||
<br />
|
<br />
|
||||||
当然,如果您在自己的私有应用中使用,可以忽略此建议。
|
当然,如果您在自己的私有应用中使用,可以忽略此建议。
|
||||||
|
<br />
|
||||||
|
!! 注意: Amber Assistant Public API 不需要在前面加 sk- !!
|
||||||
</div>
|
</div>
|
||||||
</n-popconfirm>
|
</n-popconfirm>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
|
<n-p
|
||||||
|
>我们更新了计费系统,在使用此功能之前,请前往
|
||||||
|
<n-a target="_blank" href="https://auth.leaflow.cn/balances"
|
||||||
|
>UserLand</n-a
|
||||||
|
>
|
||||||
|
来添加余额。我们正在且长期会处于测试阶段,不会对您发起真实付费(也就是说完全免费!)</n-p
|
||||||
|
>
|
||||||
<n-list hoverable clickable v-if="assistantApiKeys.length">
|
<n-list hoverable clickable v-if="assistantApiKeys.length">
|
||||||
<n-list-item v-for="c in assistantApiKeys" :key="c.id">
|
<n-list-item v-for="c in assistantApiKeys" :key="c.id">
|
||||||
<n-thing>
|
<n-thing>
|
||||||
@ -282,10 +376,11 @@ import {
|
|||||||
EntityAssistantKey,
|
EntityAssistantKey,
|
||||||
EntityAssistantTool,
|
EntityAssistantTool,
|
||||||
EntityLibrary,
|
EntityLibrary,
|
||||||
|
EntityScenePrompt,
|
||||||
EntityTool,
|
EntityTool,
|
||||||
} from "@/api";
|
} from "@/api";
|
||||||
import { useIsMobile } from "@/utils/composables";
|
import { useIsMobile } from "@/utils/composables";
|
||||||
import { AxiosError } from "axios";
|
import { Axios, AxiosError } from "axios";
|
||||||
import config from "@/config/config";
|
import config from "@/config/config";
|
||||||
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
@ -300,6 +395,13 @@ const assistants: Ref<EntityAssistant[]> = ref([]);
|
|||||||
const librarySelects: any = ref([]);
|
const librarySelects: any = ref([]);
|
||||||
const libraries: Ref<EntityLibrary[]> = ref([]);
|
const libraries: Ref<EntityLibrary[]> = ref([]);
|
||||||
const assistantApiKeys: Ref<EntityAssistantKey[]> = ref([]);
|
const assistantApiKeys: Ref<EntityAssistantKey[]> = ref([]);
|
||||||
|
const showCreateScenePromptForm = ref(false);
|
||||||
|
const scenePrompts: Ref<EntityScenePrompt[]> = ref([]);
|
||||||
|
|
||||||
|
const newScenePrompt = ref({
|
||||||
|
label: "",
|
||||||
|
prompt: "",
|
||||||
|
});
|
||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const drawerWidth = computed(() => {
|
const drawerWidth = computed(() => {
|
||||||
@ -338,6 +440,7 @@ const showEditAssistant = async (id: number) => {
|
|||||||
await getAssistantsKeys();
|
await getAssistantsKeys();
|
||||||
|
|
||||||
getTools();
|
getTools();
|
||||||
|
getAssistantScenePrompts();
|
||||||
};
|
};
|
||||||
|
|
||||||
const editAssistant = async () => {
|
const editAssistant = async () => {
|
||||||
@ -463,7 +566,83 @@ const bindOrUnbind = async (id: number) => {
|
|||||||
getTools();
|
getTools();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAssistantScenePrompts = async () => {
|
||||||
|
scenePrompts.value =
|
||||||
|
(
|
||||||
|
await getApi().Assistant.apiV1AssistantsIdScenePromptsGet(
|
||||||
|
currentAssistantId.value
|
||||||
|
)
|
||||||
|
).data.data ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAssistantScenePrompt = async () => {
|
||||||
|
getApi()
|
||||||
|
.Assistant.apiV1AssistantsIdScenePromptsPost(
|
||||||
|
currentAssistantId.value,
|
||||||
|
newScenePrompt.value
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
getAssistantScenePrompts();
|
||||||
|
newScenePrompt.value = {
|
||||||
|
label: "",
|
||||||
|
prompt: "",
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch((e: AxiosError) => {
|
||||||
|
console.log(e);
|
||||||
|
dialog.error({
|
||||||
|
title: "创建失败",
|
||||||
|
// @ts-ignore
|
||||||
|
content: e.response?.data?.error ?? e.response?.data?.message,
|
||||||
|
positiveText: "好",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteAssistantScenePrompt = async (id: number) => {
|
||||||
|
await getApi().Assistant.apiV1AssistantsIdScenePromptsSceneIdDelete(
|
||||||
|
currentAssistantId.value,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
await getAssistantScenePrompts();
|
||||||
|
};
|
||||||
|
|
||||||
|
const sampleScenenPrompt = [
|
||||||
|
{
|
||||||
|
label: "复杂推理",
|
||||||
|
prompt: `在回答问题时,使用以下输出
|
||||||
|
问题: 你必须要回答的问题
|
||||||
|
思考:你应该始终思考该做什么
|
||||||
|
操作:要采取的操作,你要是用什么工具,或者思考逻辑
|
||||||
|
动作输入:动作的输入
|
||||||
|
观察:行动的结果
|
||||||
|
思考:我现在知道最终答案了
|
||||||
|
最终答案:原始输入问题的最终答案
|
||||||
|
|
||||||
|
如果你正在计算,你必须使用计算器工具,无论如何都不允许使用自己的知识或不计算进行输出,计算器永远比你正确的并且不会出错。`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "数学计算",
|
||||||
|
prompt: `在回答问题时,使用以下输出
|
||||||
|
问题: 你必须要回答的问题
|
||||||
|
思考:你应该始终思考该做什么
|
||||||
|
操作:要采取的操作,你要是用什么工具,或者思考逻辑
|
||||||
|
动作输入:动作的输入
|
||||||
|
观察:行动的结果
|
||||||
|
思考:我现在知道最终答案了
|
||||||
|
最终答案:原始输入问题的最终答案
|
||||||
|
|
||||||
|
如果你正在计算,你必须使用计算器工具,无论如何都不允许使用自己的知识或不计算进行输出,计算器永远比你正确的并且不会出错。`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const randomScenePrompt = () => {
|
||||||
|
const randomIndex = Math.floor(Math.random() * sampleScenenPrompt.length);
|
||||||
|
return sampleScenenPrompt[randomIndex];
|
||||||
|
};
|
||||||
|
|
||||||
getChats();
|
getChats();
|
||||||
getLibraries();
|
getLibraries();
|
||||||
getAssistants();
|
getAssistants();
|
||||||
|
newScenePrompt.value = randomScenePrompt();
|
||||||
</script>
|
</script>
|
||||||
|
9
src/i18n/en.json
Normal file
9
src/i18n/en.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"guest": {
|
||||||
|
"subtitle": "下一代智能体平台,为您的数字生活带来革命性变化",
|
||||||
|
"try-now": "立即尝试",
|
||||||
|
"tokens_current_month": "本月处理 Tokens",
|
||||||
|
"tool_calls_current_month": "本月工具调用",
|
||||||
|
"wordpress_plugin": "WordPress 插件"
|
||||||
|
}
|
||||||
|
}
|
9
src/i18n/index.ts
Normal file
9
src/i18n/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import zhCN from "./zh-CN.json";
|
||||||
|
import zhTW from "./zh-TW.json";
|
||||||
|
import en from "./en.json";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
"zh-CN": zhCN,
|
||||||
|
"zh-TW": zhTW,
|
||||||
|
"en": en,
|
||||||
|
};
|
9
src/i18n/zh-CN.json
Normal file
9
src/i18n/zh-CN.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"guest": {
|
||||||
|
"subtitle": "下一代智能体平台,为您的数字生活带来革命性变化",
|
||||||
|
"try-now": "立即尝试",
|
||||||
|
"tokens_current_month": "本月处理 Tokens",
|
||||||
|
"tool_calls_current_month": "本月工具调用",
|
||||||
|
"wordpress_plugin": "WordPress 插件"
|
||||||
|
}
|
||||||
|
}
|
9
src/i18n/zh-TW.json
Normal file
9
src/i18n/zh-TW.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"guest": {
|
||||||
|
"subtitle": "下一代智能体平台,为您的数字生活带来革命性变化",
|
||||||
|
"try-now": "立即尝试",
|
||||||
|
"tokens_current_month": "本月处理 Tokens",
|
||||||
|
"tool_calls_current_month": "本月工具调用",
|
||||||
|
"wordpress_plugin": "WordPress 插件"
|
||||||
|
}
|
||||||
|
}
|
@ -83,7 +83,7 @@ const onScroll = (e: Event) => {
|
|||||||
|
|
||||||
<n-layout :native-scrollbar="isMobile">
|
<n-layout :native-scrollbar="isMobile">
|
||||||
<div class="!pt-2">
|
<div class="!pt-2">
|
||||||
<div v-if="userStore.logined">
|
<div v-if="userStore.logined && !userStore.isExpired()">
|
||||||
<ChatLayout>
|
<ChatLayout>
|
||||||
<router-view :key="route.path"> </router-view>
|
<router-view :key="route.path"> </router-view>
|
||||||
</ChatLayout>
|
</ChatLayout>
|
||||||
@ -101,17 +101,4 @@ const onScroll = (e: Event) => {
|
|||||||
</div> -->
|
</div> -->
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
|
|
||||||
<n-watermark
|
|
||||||
content="测试版本,不代表最终品质"
|
|
||||||
cross
|
|
||||||
fullscreen
|
|
||||||
:font-size="16"
|
|
||||||
:line-height="16"
|
|
||||||
:width="384"
|
|
||||||
:height="384"
|
|
||||||
:x-offset="12"
|
|
||||||
:y-offset="60"
|
|
||||||
:rotate="-15"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
<div v-else-if="chatStore.toolName != ''">
|
<div v-else-if="chatStore.toolName != ''">
|
||||||
<n-gradient-text type="info">
|
<n-gradient-text type="info">
|
||||||
正在执行 {{ chatStore.toolName }}
|
{{ chatStore.toolName }}
|
||||||
</n-gradient-text>
|
</n-gradient-text>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
11
src/main.ts
11
src/main.ts
@ -6,22 +6,19 @@ import "./styles/style.css";
|
|||||||
import "./styles/color.less";
|
import "./styles/color.less";
|
||||||
import "animate.css";
|
import "animate.css";
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from "vue";
|
||||||
import App from './App.vue'
|
import App from "./App.vue";
|
||||||
|
|
||||||
import naive from 'naive-ui'
|
|
||||||
|
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import { registerPlugins } from "./plugins";
|
import { registerPlugins } from "./plugins";
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(naive)
|
|
||||||
|
|
||||||
registerPlugins(app);
|
registerPlugins(app);
|
||||||
|
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "production") {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const appContainer = document.getElementById("app");
|
const appContainer = document.getElementById("app");
|
||||||
|
@ -4,49 +4,77 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Spotlight 区域 -->
|
<!-- Spotlight 区域 -->
|
||||||
<n-card class="spotlight" :bordered="false">
|
<n-card class="spotlight" :bordered="false">
|
||||||
<div class="background-pattern"></div>
|
|
||||||
<div class="background-text">Leaflow <span class="background-amber">Amber</span></div>
|
|
||||||
<div class="spotlight-content">
|
<div class="spotlight-content">
|
||||||
<h1 class="title">
|
<h1 class="title break-normal">
|
||||||
Leaflow <span class="amber-text">Amber</span>
|
Leaflow <span class="amber-text">Amber</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
下一代智能体平台,为您的数字生活带来革命性变化
|
<span>{{ $t('guest.subtitle') }}</span>
|
||||||
<br class="mobile-break">
|
<br class="mobile-break" />
|
||||||
<a href="#" class="cta-link">立即体验 🚀</a>
|
<a @click="gotoLogin" class="cta-link cursor-pointer"
|
||||||
|
>{{ $t('guest.try-now') }}</a
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
<div class="stats" v-if="siteUsage.month_tokens && siteUsage.month_tool_calls">
|
<div
|
||||||
|
class="stats"
|
||||||
|
v-if="siteUsage.month_tokens && siteUsage.month_tool_calls"
|
||||||
|
>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<n-statistic tabular-nums>
|
<n-statistic tabular-nums>
|
||||||
<n-number-animation
|
<n-number-animation
|
||||||
ref="tokenAnimationRef"
|
ref="tokenAnimationRef"
|
||||||
:from="siteUsage.month_tokens < 1000 ? 0 : siteUsage.month_tokens - 800"
|
:from="
|
||||||
|
siteUsage.month_tokens < 1000
|
||||||
|
? 0
|
||||||
|
: siteUsage.month_tokens - 800
|
||||||
|
"
|
||||||
:to="siteUsage.month_tokens"
|
:to="siteUsage.month_tokens"
|
||||||
/>
|
/>
|
||||||
<template #suffix> Tokens </template>
|
<template #suffix> Tokens </template>
|
||||||
</n-statistic>
|
</n-statistic>
|
||||||
<div class="stat-label">本月处理 Tokens</div>
|
<div class="stat-label">{{ $t('guest.tokens_current_month') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<n-statistic tabular-nums>
|
<n-statistic tabular-nums>
|
||||||
<n-number-animation
|
<n-number-animation
|
||||||
ref="callsAnimationRef"
|
ref="callsAnimationRef"
|
||||||
:from="siteUsage.month_tool_calls < 1000 ? 0 : siteUsage.month_tool_calls - 800"
|
:from="
|
||||||
|
siteUsage.month_tool_calls < 1000
|
||||||
|
? 0
|
||||||
|
: siteUsage.month_tool_calls - 800
|
||||||
|
"
|
||||||
:to="siteUsage.month_tool_calls"
|
:to="siteUsage.month_tool_calls"
|
||||||
/>
|
/>
|
||||||
<template #suffix> Calls </template>
|
<template #suffix> Calls </template>
|
||||||
</n-statistic>
|
</n-statistic>
|
||||||
<div class="stat-label">本月工具调用</div>
|
<div class="stat-label">{{ $t('guest.tool_calls_current_month') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<n-button class="transparent-button spotlight-button" ghost tag="a" href="https://github.com/ivampiresp/wp-amber" target="_blank">
|
<n-button
|
||||||
WordPress 插件
|
class="transparent-button spotlight-button"
|
||||||
</n-button>
|
ghost
|
||||||
<n-button class="transparent-button spotlight-button" ghost tag="a" href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=e6RgLkc7pXr57968mYSg5X7H3puFi79b&authKey=xbG43mkYovgs%2BNW3BOG7oo%2BJZK0dbXjzyIfwW9a8himqRC6AlXOkCmb3G%2FcwOt6Y&noverify=0&group_code=439747955" target="_blank">
|
tag="a"
|
||||||
|
href="https://github.com/ivampiresp/wp-amber"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ $t('guest.wordpress_plugin') }} </n-button>
|
||||||
|
<n-button
|
||||||
|
class="transparent-button spotlight-button"
|
||||||
|
ghost
|
||||||
|
tag="a"
|
||||||
|
href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=e6RgLkc7pXr57968mYSg5X7H3puFi79b&authKey=xbG43mkYovgs%2BNW3BOG7oo%2BJZK0dbXjzyIfwW9a8himqRC6AlXOkCmb3G%2FcwOt6Y&noverify=0&group_code=439747955"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
加入官方 QQ 群
|
加入官方 QQ 群
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-button class="transparent-button spotlight-button" ghost tag="a" href="https://amber-api.leaflow.cn/swagger/index.html" target="_blank">
|
<n-button
|
||||||
|
class="transparent-button spotlight-button"
|
||||||
|
ghost
|
||||||
|
tag="a"
|
||||||
|
href="https://amber-api.leaflow.cn/swagger/index.html"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
Amber API 文档
|
Amber API 文档
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
@ -56,15 +84,27 @@
|
|||||||
<!-- 功能特点展示 -->
|
<!-- 功能特点展示 -->
|
||||||
<div class="features-section">
|
<div class="features-section">
|
||||||
<h2 class="section-title">Amber 核心特性</h2>
|
<h2 class="section-title">Amber 核心特性</h2>
|
||||||
<n-grid :cols="3" :x-gap="24" :y-gap="24" responsive="screen">
|
<n-grid
|
||||||
<n-gi span="3 m:1" v-for="(feature, index) in features" :key="index">
|
cols="1 m:2 l:3 xl:3 2xl:3"
|
||||||
<div class="feature-card" @click="toggleFeatureDescription(feature)">
|
:x-gap="24"
|
||||||
<div class="feature-content">
|
:y-gap="24"
|
||||||
|
responsive="screen"
|
||||||
|
>
|
||||||
|
<n-gi v-for="(feature, index) in features" :key="index">
|
||||||
|
<div
|
||||||
|
class="feature-card"
|
||||||
|
@click="toggleFeatureDescription(feature)"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
<div class="feature-icon">{{ feature.icon }}</div>
|
<div class="feature-icon">{{ feature.icon }}</div>
|
||||||
<div class="feature-title">{{ feature.title }}</div>
|
<div class="feature-title">{{ feature.title }}</div>
|
||||||
<transition name="fade-height" mode="out-in">
|
<transition name="fade-height" mode="out-in">
|
||||||
<p class="feature-description" :key="feature.showLong">
|
<p class="feature-description" :key="feature.showLong">
|
||||||
{{ feature.showLong ? feature.longDescription : feature.shortDescription }}
|
{{
|
||||||
|
feature.showLong
|
||||||
|
? feature.longDescription
|
||||||
|
: feature.shortDescription
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@ -77,13 +117,23 @@
|
|||||||
<div class="partners-section">
|
<div class="partners-section">
|
||||||
<h2 class="section-title">合作伙伴</h2>
|
<h2 class="section-title">合作伙伴</h2>
|
||||||
<div class="partner-grid">
|
<div class="partner-grid">
|
||||||
<div v-for="partner in partners" :key="partner.name" class="partner-card">
|
<div
|
||||||
|
v-for="partner in partners"
|
||||||
|
:key="partner.name"
|
||||||
|
class="partner-card"
|
||||||
|
>
|
||||||
<div class="partner-logo-container">
|
<div class="partner-logo-container">
|
||||||
<img :src="partner.logo" :alt="partner.name" class="partner-logo">
|
<img
|
||||||
|
:src="partner.logo"
|
||||||
|
:alt="partner.name"
|
||||||
|
class="partner-logo"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="partner-name">{{ partner.name }}</h3>
|
<h3 class="partner-name">{{ partner.name }}</h3>
|
||||||
<p class="partner-description">{{ partner.description }}</p>
|
<p class="partner-description">{{ partner.description }}</p>
|
||||||
<a :href="partner.link" target="_blank" class="partner-link">了解更多</a>
|
<a :href="partner.link" target="_blank" class="partner-link"
|
||||||
|
>了解更多</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -93,73 +143,92 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from "vue";
|
||||||
import { useOsTheme, darkTheme, NConfigProvider, NLayout, NButton, NCard, NStatistic, NNumberAnimation } from 'naive-ui';
|
import {
|
||||||
|
useOsTheme,
|
||||||
|
darkTheme,
|
||||||
|
NConfigProvider,
|
||||||
|
NLayout,
|
||||||
|
NButton,
|
||||||
|
NCard,
|
||||||
|
NStatistic,
|
||||||
|
NNumberAnimation,
|
||||||
|
} from "naive-ui";
|
||||||
import { SchemaSiteUsageResponse } from "@/api";
|
import { SchemaSiteUsageResponse } from "@/api";
|
||||||
import getApi from "@/plugins/api";
|
import getApi from "@/plugins/api";
|
||||||
import grouppng from "@/assets/images/group.png";
|
import router from "@/router";
|
||||||
|
|
||||||
const osTheme = useOsTheme();
|
const osTheme = useOsTheme();
|
||||||
const theme = computed(() => (osTheme.value === 'dark' ? darkTheme : null));
|
const theme = computed(() => (osTheme.value === "dark" ? darkTheme : null));
|
||||||
|
|
||||||
const siteUsage = ref<SchemaSiteUsageResponse>({});
|
const siteUsage = ref<SchemaSiteUsageResponse>({});
|
||||||
|
|
||||||
|
const gotoLogin = () => {
|
||||||
|
router.push("/auth/login");
|
||||||
|
};
|
||||||
|
|
||||||
const features = ref([
|
const features = ref([
|
||||||
{
|
{
|
||||||
icon: '💬',
|
icon: "💬",
|
||||||
title: '对话优化引擎',
|
title: "对话优化引擎",
|
||||||
shortDescription: '独特的多助理并行工作系统,提供流畅一致的对话体验。',
|
shortDescription: "独特的多助理并行工作系统,提供流畅一致的对话体验。",
|
||||||
longDescription: 'Amber 的对话优化引擎无与伦比。我们独特的对话功能支持多个助理并行工作,您可以通过输入 @ 或点击右上角的"切换助理"选项,轻松指定下一个回复的助理。所有助理共享一个上下文,彼此了解每个操作,为您提供流畅一致的对话体验。与一些只能处理单一对话的竞品相比,Amber 的多助理协作系统显得更为智能和高效。在重大决策型的使用场景中,你可以通过 Amber 对话引擎去得到 N 个 Second Opinion。 Amber 为聊天场景做了很多的优化,它将更能处理您日常生活中的问题。',
|
longDescription:
|
||||||
showLong: false
|
'Amber 的对话优化引擎无与伦比。我们独特的对话功能支持多个助理并行工作,您可以通过输入 @ 或点击右上角的"切换助理"选项,轻松指定下一个回复的助理。所有助理共享一个上下文,彼此了解每个操作,为您提供流畅一致的对话体验。与一些只能处理单一对话的竞品相比,Amber 的多助理协作系统显得更为智能和高效。在重大决策型的使用场景中,你可以通过 Amber 对话引擎去得到 N 个 Second Opinion。 Amber 为聊天场景做了很多的优化,它将更能处理您日常生活中的问题。',
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '📖',
|
icon: "📖",
|
||||||
title: '智能上下文',
|
title: "智能上下文",
|
||||||
shortDescription: '自动调整对话上下文,提升对话流畅性并节省资源。',
|
shortDescription: "自动调整对话上下文,提升对话流畅性并节省资源。",
|
||||||
longDescription: 'Amber 拥有独特的智能上下文技术,能够根据对话场景自动调整上下文。这一过程对用户是透明的,您无需手动干预,系统会智能识别何时需要移除或添加上下文信息。这种灵活性不仅提升了对话的流畅性,还能显著降低 Token 的消耗,节省从几千到几万不等的费用,帮助用户更高效地利用资源。需要注意的是,OpenAI 兼容模式不支持智能上下文功能,因此在使用该模式时,您将无法享受到这一创新技术带来的便利。我们建议您在适用的情况下,充分利用 Amber 的智能上下文,以优化您的对话体验和资源使用。',
|
longDescription:
|
||||||
showLong: false
|
"Amber 拥有独特的智能上下文技术,能够根据对话场景自动调整上下文。这一过程对用户是透明的,您无需手动干预,系统会智能识别何时需要移除或添加上下文信息。这种灵活性不仅提升了对话的流畅性,还能显著降低 Token 的消耗,节省从几千到几万不等的费用,帮助用户更高效地利用资源。需要注意的是,OpenAI 兼容模式不支持智能上下文功能,因此在使用该模式时,您将无法享受到这一创新技术带来的便利。我们建议您在适用的情况下,充分利用 Amber 的智能上下文,以优化您的对话体验和资源使用。",
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🛠️',
|
icon: "🛠️",
|
||||||
title: '高度客制化',
|
title: "高度客制化",
|
||||||
shortDescription: '自定义提示词和工具绑定,轻松完成复杂任务。',
|
shortDescription: "自定义提示词和工具绑定,轻松完成复杂任务。",
|
||||||
longDescription: 'Amber 具备了目前主流 LLM 对话平台都拥有的高自由度智能体自定义功能,用户可以自定义提示词,绑定工具,以完成复杂任务并优化工作流。例如,您可以设置助理在每天早上自动为您生成当天的工作清单,或者在您需要时快速调用数据分析工具。我们的助理不仅能执行简单的任务,还能实现多步骤的复杂操作,并与知识库无缝集成,说它是您高效工作的得力助手,绝不为过。 💪',
|
longDescription:
|
||||||
showLong: false
|
"Amber 具备了目前主流 LLM 对话平台都拥有的高自由度智能体自定义功能,用户可以自定义提示词,绑定工具,以完成复杂任务并优化工作流。例如,您可以设置助理在每天早上自动为您生成当天的工作清单,或者在您需要时快速调用数据分析工具。我们的助理不仅能执行简单的任务,还能实现多步骤的复杂操作,并与知识库无缝集成,说它是您高效工作的得力助手,绝不为过。 💪",
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🧠',
|
icon: "🧠",
|
||||||
title: '智能记忆',
|
title: "智能记忆",
|
||||||
shortDescription: '生成对话记忆,实现更个性化和连贯的交互体验。',
|
shortDescription: "生成对话记忆,实现更个性化和连贯的交互体验。",
|
||||||
longDescription: 'Amber 通过采样您的对话内容生成记忆,这些记忆是碎片化的,但对话中共享。您可以随时清除所有记忆,确保数据的灵活管理。Amber 会收集您的消息,并且根据消息推断您的喜好。记忆的内容您完全可以控制,甚至禁用助理的记忆。助理将会根据您的记忆来改变响应的结果,您喜欢什么,您直接在对话中说明即可(Amber 会从第二条消息开始学习记忆) ❤️',
|
longDescription:
|
||||||
showLong: false
|
"Amber 通过采样您的对话内容生成记忆,这些记忆是碎片化的,但对话中共享。您可以随时清除所有记忆,确保数据的灵活管理。Amber 会收集您的消息,并且根据消息推断您的喜好。记忆的内容您完全可以控制,甚至禁用助理的记忆。助理将会根据您的记忆来改变响应的结果,您喜欢什么,您直接在对话中说明即可(Amber 会从第二条消息开始学习记忆) ❤️",
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🔗',
|
icon: "🔗",
|
||||||
title: 'API 集成',
|
title: "API 集成",
|
||||||
shortDescription: '强大的 API 支持,轻松将 Amber 集成到您的应用中。',
|
shortDescription: "强大的 API 支持,轻松将 Amber 集成到您的应用中。",
|
||||||
longDescription: '我们提供强大的助理 API,支持兼容 OpenAI 格式的应用接入 Amber。通过 Chat Completion API,您可以直接调用 Amber 的工具、记忆以及知识库功能。例如,一个开发者可以轻松地将 Amber 集成到他们的客服系统中,自动处理常见问题并提供高效的解决方案。相较于其他平台,我们的 API 更具灵活性和扩展性,让您的应用赋予更多可能。不仅仅在 Amber 系统的本身,您也可以通过我们 Leaflow 平台的 UserLand,解锁更多高阶 API 玩法! 🚀',
|
longDescription:
|
||||||
showLong: false
|
"我们提供强大的助理 API,支持兼容 OpenAI 格式的应用接入 Amber。通过 Chat Completion API,您可以直接调用 Amber 的工具、记忆以及知识库功能。例如,一个开发者可以轻松地将 Amber 集成到他们的客服系统中,自动处理常见问题并提供高效的解决方案。相较于其他平台,我们的 API 更具灵活性和扩展性,让您的应用赋予更多可能。不仅仅在 Amber 系统的本身,您也可以通过我们 Leaflow 平台的 UserLand,解锁更多高阶 API 玩法! 🚀",
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '📚',
|
icon: "📚",
|
||||||
title: '知识管理',
|
title: "知识管理",
|
||||||
shortDescription: '高效的文档管理和知识库功能,让信息检索更便捷。',
|
shortDescription: "高效的文档管理和知识库功能,让信息检索更便捷。",
|
||||||
longDescription: '文档管理是 Amber 知识库的核心功能之一。对话中上传的文件将自动保存至知识库,您只需设置助理关联知识库,即可实现快速检索和使用。假设您是一位项目经理,您可以在对话中上传项目计划书,并在需要时快速检索相关内容。Amber 在您发送消息时,将会自动搜索资料库。此外,我们正在开发桌面端软件,该软件可以根据您的需要同步文档至 Amber,以便随时调用🗂️。',
|
longDescription:
|
||||||
showLong: false
|
"文档管理是 Amber 知识库的核心功能之一。对话中上传的文件将自动保存至知识库,您只需设置助理关联知识库,即可实现快速检索和使用。假设您是一位项目经理,您可以在对话中上传项目计划书,并在需要时快速检索相关内容。Amber 在您发送消息时,将会自动搜索资料库。此外,我们正在开发桌面端软件,该软件可以根据您的需要同步文档至 Amber,以便随时调用🗂️。",
|
||||||
|
showLong: false,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const partners = ref([
|
const partners = ref([
|
||||||
{
|
{
|
||||||
name: 'HiMCBBS 我的世界中文论坛',
|
name: "HiMCBBS 我的世界中文论坛",
|
||||||
logo: 'https://www.himcbbs.com/data/assets/favicon/himcbbs-favicon-black-6x.png',
|
logo: "https://www.himcbbs.com/data/assets/favicon/himcbbs-favicon-black-6x.png",
|
||||||
link: 'https://www.himcbbs.com/',
|
link: "https://www.himcbbs.com/",
|
||||||
description: '中国最大的我的世界玩家社区,提供游戏资讯、模组下载和创意分享。'
|
description: "中国我的世界玩家社区,提供游戏资讯、模组下载和创意分享。",
|
||||||
}
|
},
|
||||||
// 可以在这里添加更多合作伙伴
|
// 可以在这里添加更多合作伙伴
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const toggleFeatureDescription = (feature) => {
|
const toggleFeatureDescription = (feature: any) => {
|
||||||
feature.showLong = !feature.showLong;
|
feature.showLong = !feature.showLong;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -176,11 +245,13 @@ onMounted(async () => {
|
|||||||
--primary-color: #4ebbc0;
|
--primary-color: #4ebbc0;
|
||||||
--text-color: v-bind('theme ? "#ffffff" : "#333333"');
|
--text-color: v-bind('theme ? "#ffffff" : "#333333"');
|
||||||
--background-color: v-bind('theme ? "#1a1a1a" : "#f5f5f5"');
|
--background-color: v-bind('theme ? "#1a1a1a" : "#f5f5f5"');
|
||||||
--card-background: v-bind('theme ? "rgba(255, 255, 255, 0.1)" : "rgba(255, 255, 255, 0.8)"');
|
--card-background: v-bind(
|
||||||
|
'theme ? "rgba(255, 255, 255, 0.1)" : "rgba(255, 255, 255, 0.8)"'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Arial', sans-serif;
|
font-family: "Arial", sans-serif;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
@ -194,9 +265,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spotlight {
|
.spotlight {
|
||||||
background-color: v-bind('theme ? "rgba(0, 0, 0, 0.5)" : "rgba(78, 187, 192, 0.1)"');
|
background-color: v-bind(
|
||||||
|
'theme ? "rgba(0, 0, 0, 0.5)" : "rgba(78, 187, 192, 0.1)"'
|
||||||
|
);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
height: 70vh;
|
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -205,7 +277,9 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: v-bind('theme ? "0 4px 6px rgba(0, 0, 0, 0.1)" : "0 4px 6px rgba(78, 187, 192, 0.2)"');
|
box-shadow: v-bind(
|
||||||
|
'theme ? "0 4px 6px rgba(0, 0, 0, 0.1)" : "0 4px 6px rgba(78, 187, 192, 0.2)"'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.background-text {
|
.background-text {
|
||||||
@ -216,13 +290,15 @@ body {
|
|||||||
font-size: 20vw;
|
font-size: 20vw;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
-webkit-text-stroke: 1px v-bind('theme ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)"');
|
-webkit-text-stroke: 1px
|
||||||
|
v-bind('theme ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)"');
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.background-amber {
|
.background-amber {
|
||||||
-webkit-text-stroke: 1px v-bind('theme ? "rgba(78, 187, 192, 0.2)" : "rgba(78, 187, 192, 0.3)"');
|
-webkit-text-stroke: 1px
|
||||||
|
v-bind('theme ? "rgba(78, 187, 192, 0.2)" : "rgba(78, 187, 192, 0.3)"');
|
||||||
}
|
}
|
||||||
|
|
||||||
.spotlight-content {
|
.spotlight-content {
|
||||||
@ -288,8 +364,11 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.transparent-button {
|
.transparent-button {
|
||||||
background-color: v-bind('theme ? "rgba(255, 255, 255, 0.2)" : "rgba(78, 187, 192, 0.1)"');
|
background-color: v-bind(
|
||||||
border: 1px solid v-bind('theme ? "rgba(255, 255, 255, 0.5)" : "rgba(78, 187, 192, 0.3)"');
|
'theme ? "rgba(255, 255, 255, 0.2)" : "rgba(78, 187, 192, 0.1)"'
|
||||||
|
);
|
||||||
|
border: 1px solid
|
||||||
|
v-bind('theme ? "rgba(255, 255, 255, 0.5)" : "rgba(78, 187, 192, 0.3)"');
|
||||||
color: v-bind('theme ? "white" : "rgba(0, 0, 0, 0.7)"');
|
color: v-bind('theme ? "white" : "rgba(0, 0, 0, 0.7)"');
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@ -307,7 +386,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spotlight-button::before {
|
.spotlight-button::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@ -316,7 +395,9 @@ body {
|
|||||||
background-color: rgba(78, 187, 192, 0.3);
|
background-color: rgba(78, 187, 192, 0.3);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
transition: width 0.6s ease, height 0.6s ease;
|
transition:
|
||||||
|
width 0.6s ease,
|
||||||
|
height 0.6s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spotlight-button:hover::before {
|
.spotlight-button:hover::before {
|
||||||
@ -325,7 +406,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spotlight-button:hover {
|
.spotlight-button:hover {
|
||||||
background-color: v-bind('theme ? "rgba(255, 255, 255, 0.3)" : "transparent"');
|
background-color: v-bind(
|
||||||
|
'theme ? "rgba(255, 255, 255, 0.3)" : "transparent"'
|
||||||
|
);
|
||||||
border-color: #4ebbc0;
|
border-color: #4ebbc0;
|
||||||
color: v-bind('theme ? "white" : "#4ebbc0"');
|
color: v-bind('theme ? "white" : "#4ebbc0"');
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
|
@ -23,6 +23,11 @@ axios.get(config.oauth_discovery_url).then((discovery) => {
|
|||||||
|
|
||||||
const code: any = router.currentRoute.value.query.code;
|
const code: any = router.currentRoute.value.query.code;
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
// console.log("无法获取当前 url 中的 code")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 从当前页面请求中获取 code
|
// 从当前页面请求中获取 code
|
||||||
const q = new URLSearchParams({
|
const q = new URLSearchParams({
|
||||||
client_id: config.oauth_client_id,
|
client_id: config.oauth_client_id,
|
||||||
@ -43,12 +48,13 @@ axios.get(config.oauth_discovery_url).then((discovery) => {
|
|||||||
r.data.id_token,
|
r.data.id_token,
|
||||||
r.data.access_token,
|
r.data.access_token,
|
||||||
r.data.refresh_token,
|
r.data.refresh_token,
|
||||||
r.data.expires_in,
|
r.data.expires_in
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e);
|
console.error(e);
|
||||||
alert("登录失败");
|
|
||||||
|
// alert("登录失败");
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
// 跳转到 /
|
// 跳转到 /
|
||||||
|
@ -5,6 +5,7 @@ import error401 from "@/pages/errors/401.vue";
|
|||||||
import error404 from "@/pages/errors/404.vue";
|
import error404 from "@/pages/errors/404.vue";
|
||||||
import error400 from "@/pages/errors/400.vue";
|
import error400 from "@/pages/errors/400.vue";
|
||||||
import error500 from "@/pages/errors/500.vue";
|
import error500 from "@/pages/errors/500.vue";
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
|
|
||||||
const osThemeRef = useOsTheme();
|
const osThemeRef = useOsTheme();
|
||||||
|
|
||||||
@ -19,13 +20,19 @@ const { dialog, loadingBar } = createDiscreteApi(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
onFulfilled: (config: any) => {
|
onFulfilled: async (config: any) => {
|
||||||
if (config.headers === undefined) {
|
if (config.headers === undefined) {
|
||||||
config.headers = {};
|
config.headers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingBar.start();
|
loadingBar.start();
|
||||||
|
|
||||||
|
// const userStore = useUserStore();
|
||||||
|
|
||||||
|
// if (userStore.logined) {
|
||||||
|
// userStore.checkAndRefresh();
|
||||||
|
// }
|
||||||
|
|
||||||
return Promise.resolve(config);
|
return Promise.resolve(config);
|
||||||
},
|
},
|
||||||
onRejected: (error: any) => {
|
onRejected: (error: any) => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import pinia from "../stores";
|
import pinia from "../stores";
|
||||||
import naive from "naive-ui";
|
import naive from "naive-ui";
|
||||||
|
import { createI18n } from "vue-i18n";
|
||||||
|
import i18nMessages from "@/i18n"
|
||||||
// Types
|
// Types
|
||||||
import type { App } from "vue";
|
import type { App } from "vue";
|
||||||
// 通用字体
|
// 通用字体
|
||||||
@ -8,6 +9,28 @@ import "vfonts/Lato.css";
|
|||||||
// 等宽字体
|
// 等宽字体
|
||||||
import "vfonts/FiraCode.css";
|
import "vfonts/FiraCode.css";
|
||||||
|
|
||||||
|
// 自动根据用户的浏览器设置选择语言
|
||||||
|
const getLocate = () => {
|
||||||
|
const languages = navigator.languages || [navigator.language];
|
||||||
|
|
||||||
|
for (const lang of languages) {
|
||||||
|
if (lang.startsWith('zh-CN')) {
|
||||||
|
return 'zh-CN'; // 简体中文
|
||||||
|
} else if (lang.startsWith('zh-TW')) {
|
||||||
|
return 'zh-TW'; // 繁体中文
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return languages[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const userLocale = getLocate();
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: userLocale || 'zh-CN', // 如果没有匹配,默认返回简体中文
|
||||||
|
fallbackLocale: "zh-CN",
|
||||||
|
messages: i18nMessages,
|
||||||
|
});
|
||||||
|
|
||||||
export function registerPlugins(app: App) {
|
export function registerPlugins(app: App) {
|
||||||
app.use(naive).use(pinia);
|
app.use(i18n).use(naive).use(pinia);
|
||||||
}
|
}
|
||||||
|
@ -42,10 +42,15 @@ export const useUserStore = defineStore("user", {
|
|||||||
this.logined = true;
|
this.logined = true;
|
||||||
},
|
},
|
||||||
checkAndRefresh() {
|
checkAndRefresh() {
|
||||||
if (this.logined) {
|
// 检测是否过期
|
||||||
if (this.expired_at - Date.now() < 60000) {
|
if (this.expired_at - Date.now() < 0) {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
} else if (
|
||||||
|
this.logined &&
|
||||||
|
this.expired_at - Date.now() > 600 &&
|
||||||
|
this.expired_at - Date.now() < 1000
|
||||||
|
) {
|
||||||
|
this.refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setupTimer() {
|
setupTimer() {
|
||||||
@ -80,6 +85,7 @@ export const useUserStore = defineStore("user", {
|
|||||||
if (error.response.status === 401) {
|
if (error.response.status === 401) {
|
||||||
console.log("Refresh token failed");
|
console.log("Refresh token failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// logout
|
// logout
|
||||||
this.logout();
|
this.logout();
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
@ -94,5 +100,8 @@ export const useUserStore = defineStore("user", {
|
|||||||
getIdToken() {
|
getIdToken() {
|
||||||
return this.id_token;
|
return this.id_token;
|
||||||
},
|
},
|
||||||
|
isExpired() {
|
||||||
|
return this.expired_at - Date.now() < 0;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -10,6 +10,13 @@ import AutoImport from "unplugin-auto-import/vite";
|
|||||||
import { fileURLToPath, URL } from "node:url";
|
import { fileURLToPath, URL } from "node:url";
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
api: "modern-compiler", // or "modern", "legacy"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||||
|
Loading…
Reference in New Issue
Block a user