init
This commit is contained in:
161
src/app.ts
Normal file
161
src/app.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { QueryRouterServer } from '@kevisual/router'
|
||||
import { use } from '@kevisual/context'
|
||||
import { Query } from '@kevisual/query'
|
||||
import { Kevisual, BailianChat } from '@kevisual/ai'
|
||||
import mitt from 'mitt';
|
||||
const isBrowser = typeof window !== 'undefined'
|
||||
type AppOptions = {
|
||||
router?: QueryRouterServer
|
||||
query?: Query
|
||||
queryOptions?: { url?: string }
|
||||
token?: string
|
||||
initAI?: boolean
|
||||
}
|
||||
export class App {
|
||||
#router: QueryRouterServer
|
||||
use = use;
|
||||
query: Query;
|
||||
#token = '';
|
||||
ai!: Kevisual;
|
||||
loading = false;
|
||||
emitter = mitt();
|
||||
constructor(opts?: AppOptions) {
|
||||
this.#router = opts?.router || new QueryRouterServer()
|
||||
const queryOptions = opts?.queryOptions || {}
|
||||
this.query = opts?.query || new Query({ url: queryOptions.url || 'https://kevisual.cn/api/router' })
|
||||
const initAI = opts?.initAI ?? true;
|
||||
if (opts?.token) {
|
||||
this.#token = opts.token
|
||||
if (initAI) {
|
||||
this.loading = true;
|
||||
this.initAI().finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
async initAI() {
|
||||
try {
|
||||
const config = await this.getConfig('ai.json');
|
||||
if (config.token) {
|
||||
this.ai = new Kevisual(config);
|
||||
}
|
||||
} catch (e) { }
|
||||
this.emitter.emit('ai-inited');
|
||||
}
|
||||
async loadAI() {
|
||||
if (!this.ai) {
|
||||
const that = this;
|
||||
return new Promise<Kevisual>(resolve => {
|
||||
const listen = () => {
|
||||
resolve(that.ai);
|
||||
this.emitter.off('ai-inited', listen);
|
||||
}
|
||||
this.emitter.on('ai-inited', listen);
|
||||
});
|
||||
}
|
||||
return this.ai;
|
||||
}
|
||||
get token() {
|
||||
if (isBrowser && !this.#token) {
|
||||
this.#token = localStorage.getItem('token') || ''
|
||||
return this.#token;
|
||||
}
|
||||
return this.#token;
|
||||
}
|
||||
set token(value: string) {
|
||||
this.#token = value;
|
||||
}
|
||||
get router() {
|
||||
return this.#router;
|
||||
}
|
||||
set router(value: QueryRouterServer) {
|
||||
this.#router = value;
|
||||
}
|
||||
async getConfig(key: string) {
|
||||
if (isBrowser) {
|
||||
const config = sessionStorage.getItem(`config_${key}`)
|
||||
if (config) {
|
||||
return Promise.resolve(JSON.parse(config))
|
||||
}
|
||||
}
|
||||
const res = await this.query.post({
|
||||
path: 'config',
|
||||
key: 'get',
|
||||
token: this.token,
|
||||
data: { key }
|
||||
})
|
||||
if (res.code !== 200) {
|
||||
throw new Error(res.message || '获取配置失败')
|
||||
}
|
||||
const data = res.data || {}
|
||||
const config = data.data || {}
|
||||
if (isBrowser) {
|
||||
sessionStorage.setItem(`config_${key}`, JSON.stringify(config))
|
||||
}
|
||||
return config;
|
||||
}
|
||||
async chat(message: string) {
|
||||
const routes = this.router.getList();
|
||||
let v = '';
|
||||
|
||||
if (routes.length > 0) {
|
||||
const toolsList = routes.map((r, index) =>
|
||||
`${index + 1}. 工具名称: ${r.id}\n 描述: ${r.description}`
|
||||
).join('\n\n');
|
||||
|
||||
v = `你是一个 AI 助手,你可以使用以下工具来帮助用户完成任务:
|
||||
|
||||
${toolsList}
|
||||
|
||||
## 回复规则
|
||||
1. 如果用户的请求可以使用上述工具完成,请返回 JSON 格式数据
|
||||
2. 如果没有合适的工具,请直接分析并回答用户问题
|
||||
|
||||
## JSON 数据格式
|
||||
\`\`\`json
|
||||
{
|
||||
"id": "工具的id",
|
||||
"payload": {
|
||||
// 工具所需的参数(如果需要)
|
||||
// 例如: "id": "xxx", "name": "xxx"
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
注意:
|
||||
- payload 中包含工具执行所需的所有参数
|
||||
- 如果工具不需要参数,payload 可以为空对象 {}
|
||||
- 确保返回的 id 与上述工具列表中的工具名称完全匹配`
|
||||
}
|
||||
await this.ai.chat([
|
||||
{
|
||||
role: 'system',
|
||||
content: v
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: message
|
||||
}
|
||||
])
|
||||
const json = this.ai.utils.extractJsonFromMarkdown(this.ai.responseText);
|
||||
if (json.id) {
|
||||
const callRes = await this.router.call(json)
|
||||
const data = {
|
||||
code: callRes.code,
|
||||
data: callRes.body,
|
||||
message: callRes.message
|
||||
}
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
return Promise.resolve({
|
||||
code: 200,
|
||||
data: {
|
||||
id: 'ai_response',
|
||||
description: 'AI 直接回复',
|
||||
response: this.ai.responseText
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user