generated from template/apps-template
优化noco-agent功能和修复相关问题
- 修复Core类中的类型定义和拼写错误 - 添加tableId参数支持到NocoLifeService - 优化认证逻辑,支持环境变量配置 - 增强配置功能,返回当前配置信息 - 改进任务完成功能,支持批量操作 - 添加记录创建和更新功能 - 更新依赖包版本 - 修复导出类型定义 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,6 @@ export type CoreOptions<T = {}> = {
|
|||||||
baseId?: string
|
baseId?: string
|
||||||
} & T
|
} & T
|
||||||
|
|
||||||
type CoreItem = ColumnItem
|
|
||||||
export class Core {
|
export class Core {
|
||||||
nocoApi: NocoApi;
|
nocoApi: NocoApi;
|
||||||
baseId?: string;
|
baseId?: string;
|
||||||
@@ -76,19 +75,19 @@ export class Core {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getItem(id: number): Promise<ReponseData<CoreItem>> {
|
getItem(id: number): Promise<ReponseData<ColumnItem>> {
|
||||||
return this.nocoApi.record.read(id);
|
return this.nocoApi.record.read(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getList(params: any): Promise<ReponseData<{ list: CoreItem[] }>> {
|
getList(params: any): Promise<ReponseData<{ list: ColumnItem[] }>> {
|
||||||
return this.nocoApi.record.list({
|
return this.nocoApi.record.list({
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
updateItem(data: Partial<CoreItem>) {
|
updateItem(data: Partial<ColumnItem>) {
|
||||||
return this.nocoApi.record.update(data);
|
return this.nocoApi.record.update(data);
|
||||||
}
|
}
|
||||||
creatItem(data: Partial<CoreItem>) {
|
createItem(data: Partial<ColumnItem>) {
|
||||||
return this.nocoApi.record.create(data);
|
return this.nocoApi.record.create(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NocoApi } from "@kevisual/noco";
|
import { NocoApi } from "@kevisual/noco";
|
||||||
import { columns, ColumnItem } from "./common/base-table.ts";
|
import { ColumnItem, columns, } from "./common/base-table.ts";
|
||||||
import { Life } from "../noco/life/index.ts";
|
import { Life } from "../noco/life/index.ts";
|
||||||
import { Control } from "../noco/control/index.ts";
|
import { Control } from "../noco/control/index.ts";
|
||||||
import { Core } from "./common/core.ts";
|
import { Core } from "./common/core.ts";
|
||||||
@@ -8,12 +8,12 @@ import { NocoWehookPayload } from "./callback/index.ts";
|
|||||||
export {
|
export {
|
||||||
NocoApi,
|
NocoApi,
|
||||||
columns,
|
columns,
|
||||||
ColumnItem,
|
|
||||||
Control,
|
Control,
|
||||||
Life,
|
Life,
|
||||||
Core,
|
Core,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
NocoWehookPayload
|
NocoWehookPayload,
|
||||||
|
ColumnItem
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
"packageManager": "pnpm@10.24.0",
|
"packageManager": "pnpm@10.24.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kevisual/app": "^0.0.1",
|
||||||
|
"@kevisual/context": "^0.0.4",
|
||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/noco-auto": "../",
|
"@kevisual/noco-auto": "../",
|
||||||
"@kevisual/query": "^0.0.31",
|
"@kevisual/query": "^0.0.31",
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ if (!hasAuth) {
|
|||||||
id: 'auth'
|
id: 'auth'
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
// 这里可以添加实际的认证逻辑
|
// 这里可以添加实际的认证逻辑
|
||||||
ctx.query.token = process.env.TOKEN || ' ';
|
if (!ctx.query.token) {
|
||||||
console.log('本地测试认证通过,设置 token');
|
ctx.query.token = process.env.KEVISUAL_API_TOKEN || ' ';
|
||||||
|
console.log('本地测试认证通过,设置 token');
|
||||||
|
}
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
}
|
}
|
||||||
@@ -13,11 +13,16 @@ app.route({
|
|||||||
const token = ctx.query.token || '';
|
const token = ctx.query.token || '';
|
||||||
const question = ctx.query.question || '';
|
const question = ctx.query.question || '';
|
||||||
let data = ctx.query.data || {};
|
let data = ctx.query.data || {};
|
||||||
|
|
||||||
|
const nocoLifeService = new NocoLifeService({ token });
|
||||||
|
const config = await nocoLifeService.getLifeConfig()
|
||||||
if (question) {
|
if (question) {
|
||||||
const ai: BaseChat = useContextKey('ai');
|
const ai: BaseChat = useContextKey('ai');
|
||||||
|
const originConfig = JSON.stringify(config);
|
||||||
await ai.chat([
|
await ai.chat([
|
||||||
{ role: 'system', content: `你是一个多维表格配置助理,你的任务是帮助用户解析多维表格的配置信息。用户会提供配置信息,你需要从中提取出 baseURL, token, baseId, tableId 等字段,并以 JSON 格式返回。如果某个字段缺失,可以不返回该字段。请确保返回的 JSON 格式正确且易于解析。` },
|
{ role: 'system', content: `你是一个多维表格配置助理,你的任务是帮助用户解析多维表格的配置信息。用户会提供配置信息,你需要从中提取出 baseURL, token, baseId, tableId 等字段,并以 JSON 格式返回。如果某个字段缺失,可以不返回该字段。请确保返回的 JSON 格式正确且易于解析。` },
|
||||||
{ role: 'user', content: question }
|
{ role: 'user', content: question },
|
||||||
|
{ role: 'user', content: `当前已有的多维表格配置信息是: ${originConfig}` }
|
||||||
])
|
])
|
||||||
let msg = AIUtils.extractJsonFromMarkdown(ai.responseText || '');
|
let msg = AIUtils.extractJsonFromMarkdown(ai.responseText || '');
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
@@ -25,12 +30,9 @@ app.route({
|
|||||||
}
|
}
|
||||||
data = msg;
|
data = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data?.baseURL || !data?.token || !data?.baseId) {
|
if (!data?.baseURL || !data?.token || !data?.baseId) {
|
||||||
ctx.throw(400, '缺少参数 baseURL, token, baseId, tableId');
|
ctx.throw(400, '缺少参数 baseURL, token, baseId, tableId');
|
||||||
}
|
}
|
||||||
const nocoLifeService = new NocoLifeService({ token });
|
|
||||||
const config = await nocoLifeService.getLifeConfig()
|
|
||||||
if (data.baseURL) {
|
if (data.baseURL) {
|
||||||
config.baseURL = data.baseURL;
|
config.baseURL = data.baseURL;
|
||||||
}
|
}
|
||||||
@@ -48,7 +50,7 @@ app.route({
|
|||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
ctx.throw(500, '保存配置失败');
|
ctx.throw(500, '保存配置失败');
|
||||||
}
|
}
|
||||||
ctx.body = { content: '配置更新成功' };
|
ctx.body = { content: '配置更新成功,当前配置是: ' + (JSON.stringify(config)), data: config };
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ app.route({
|
|||||||
ctx.throw(400, '缺少参数 question');
|
ctx.throw(400, '缺少参数 question');
|
||||||
}
|
}
|
||||||
const token = ctx.query.token || '';
|
const token = ctx.query.token || '';
|
||||||
|
const tableId = ctx.query.tableId || '';
|
||||||
const slicedQuestion = question.slice(0, 10);
|
const slicedQuestion = question.slice(0, 10);
|
||||||
if (slicedQuestion.startsWith('配置多维表格')) {
|
if (slicedQuestion.startsWith('配置多维表格')) {
|
||||||
const res = await ctx.call({
|
const res = await ctx.call({
|
||||||
@@ -27,11 +28,12 @@ app.route({
|
|||||||
ctx.body = res.body;
|
ctx.body = res.body;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nocoLifeService = new NocoLifeService({ token });
|
const nocoLifeService = new NocoLifeService({ token, tableId });
|
||||||
await nocoLifeService.initConfig()
|
await nocoLifeService.initConfig()
|
||||||
const routes = ctx.app.getList().filter(r => r.path.startsWith('noco-life') && r.key !== 'chat');
|
const routes = ctx.app.getList().filter(r => r.path.startsWith('noco-life') && r.key !== 'chat');
|
||||||
const v = `${routes.map((r, index) => `${index + 1}工具名称: ${r.id}\n描述: ${r.description}\n`).join('\n')}\n\n当用户询问时,如果拥有工具,请返回 JSON 数据,不存在工具,则返回分析判断,数据JSON数据类型是{id,payload},外面的id是工具的id。如果工具有参数,在 payload 当中,默认不需要参数,如果工具内部需要id,在payload当中。`
|
const v = `${routes.map((r, index) => `${index + 1}工具名称: ${r.id}\n描述: ${r.description}\n`).join('\n')}\n\n当用户询问时,如果拥有工具,请返回 JSON 数据,不存在工具,则返回分析判断,数据JSON数据类型是{id,payload},外面的id是工具的id。如果工具有参数,在 payload 当中,默认不需要参数,如果工具内部需要id,在payload当中。`
|
||||||
const ai: BaseChat = useContextKey('ai');
|
const ai: BaseChat = useContextKey('ai');
|
||||||
|
const slicedQuestion2 = question.slice(0, 1000);
|
||||||
const answer = await ai.chat([
|
const answer = await ai.chat([
|
||||||
{ role: 'system', content: `你是一个多维表格助理,你的任务是帮助用户操作和查询多维表格的数据。你可以使用以下工具来完成任务:\n\n${v}` },
|
{ role: 'system', content: `你是一个多维表格助理,你的任务是帮助用户操作和查询多维表格的数据。你可以使用以下工具来完成任务:\n\n${v}` },
|
||||||
{ role: 'user', content: question }
|
{ role: 'user', content: question }
|
||||||
@@ -64,7 +66,8 @@ app.route({
|
|||||||
middleware: ['auth']
|
middleware: ['auth']
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const token = ctx.query.token || '';
|
const token = ctx.query.token || '';
|
||||||
const nocoLifeService = new NocoLifeService({ token });
|
const tableId = ctx.query.tableId || '';
|
||||||
|
const nocoLifeService = new NocoLifeService({ token, tableId });
|
||||||
await nocoLifeService.initConfig()
|
await nocoLifeService.initConfig()
|
||||||
const life = nocoLifeService.life;
|
const life = nocoLifeService.life;
|
||||||
|
|
||||||
@@ -100,49 +103,66 @@ app.route({
|
|||||||
app.route({
|
app.route({
|
||||||
path: 'noco-life',
|
path: 'noco-life',
|
||||||
key: 'done',
|
key: 'done',
|
||||||
description: `完成某件事情,然后判断下一次运行时间。参数是id,数据类型是number。`,
|
description: `完成某件事情,然后判断下一次运行时间。参数是id,数据类型是number。如果多个存在,则是ids的number数组`,
|
||||||
middleware: ['auth']
|
middleware: ['auth']
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const id = ctx.query.id;
|
const id = ctx.query.id;
|
||||||
if (!id) {
|
const ids = ctx.query.ids || [];
|
||||||
|
if (!id || ids.length === 0) {
|
||||||
ctx.throw(400, '缺少参数 id');
|
ctx.throw(400, '缺少参数 id');
|
||||||
}
|
}
|
||||||
console.log('id', id);
|
if (ids.length === 0 && id) {
|
||||||
|
ids.push(Number(id));
|
||||||
|
}
|
||||||
|
console.log('id', id, ids);
|
||||||
const token = ctx.query.token || '';
|
const token = ctx.query.token || '';
|
||||||
const nocoLifeService = new NocoLifeService({ token });
|
const tableId = ctx.query.tableId || '';
|
||||||
|
const nocoLifeService = new NocoLifeService({ token, tableId });
|
||||||
await nocoLifeService.initConfig()
|
await nocoLifeService.initConfig()
|
||||||
const life = nocoLifeService.life;
|
const messages = [];
|
||||||
// 获取记录详情
|
const changeItem = async (id: number) => {
|
||||||
const recordRes = await life.getItem(id);
|
const life = nocoLifeService.life;
|
||||||
if (recordRes.code !== 200) {
|
// 获取记录详情
|
||||||
ctx.throw(500, '获取记录详情失败');
|
const recordRes = await life.getItem(id);
|
||||||
}
|
if (recordRes.code !== 200) {
|
||||||
const record = recordRes.data;
|
// ctx.throw(500, '获取记录详情失败');
|
||||||
|
messages.push({
|
||||||
|
id,
|
||||||
|
content: `获取记录 ${id} 详情失败`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const record = recordRes.data;
|
||||||
|
|
||||||
// 检查启动时间是否大于今天
|
// 检查启动时间是否大于今天
|
||||||
const startTime = record['启动时间'];
|
const startTime = record['启动时间'];
|
||||||
const today = dayjs().startOf('day');
|
const today = dayjs().startOf('day');
|
||||||
const startDate = dayjs(startTime).startOf('day');
|
const startDate = dayjs(startTime).startOf('day');
|
||||||
|
|
||||||
if (startDate.isAfter(today)) {
|
if (startDate.isAfter(today)) {
|
||||||
ctx.throw(400, '还没到今天呢,到时候再做吧');
|
// ctx.throw(400, '还没到今天呢,到时候再做吧');
|
||||||
}
|
messages.push({
|
||||||
// 计算下一次运行时间
|
id,
|
||||||
// 1. 知道当前时间
|
content: `记录 ${id} 的启动时间是 ${dayjs(startTime).format('YYYY-MM-DD HH:mm:ss')},还没到今天呢,到时候再做吧`,
|
||||||
// 2. 知道任务类型,如果是每日,则加一天;如果是每周,则加七天;如果是每月,则加一个月,如果是每年农历,需要转为新的,如果是其他,需要智能判断
|
});
|
||||||
// 3. 更新记录
|
return;
|
||||||
const strTime = (time: string) => {
|
}
|
||||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
// 计算下一次运行时间
|
||||||
}
|
// 1. 知道当前时间
|
||||||
const currentTime = strTime(new Date().toISOString());
|
// 2. 知道任务类型,如果是每日,则加一天;如果是每周,则加七天;如果是每月,则加一个月,如果是每年农历,需要转为新的,如果是其他,需要智能判断
|
||||||
const isLuar = record['类型']?.includes?.('农历');
|
// 3. 更新记录
|
||||||
let summay = record['总结'] || '无';
|
const strTime = (time: string) => {
|
||||||
if (summay.length > 200) {
|
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
||||||
summay = summay.substring(0, 200) + '...';
|
}
|
||||||
}
|
const currentTime = strTime(new Date().toISOString());
|
||||||
const prompt = record['提示词'] || '';
|
const isLuar = record['类型']?.includes?.('农历');
|
||||||
const type = record['类型'] || '';
|
let summay = record['总结'] || '无';
|
||||||
const content = `上一次执行的时间是${strTime(startTime)},当前时间是${currentTime},请帮我计算下一次的运行时间,如果时间不存在,默认在8点启动。
|
if (summay.length > 200) {
|
||||||
|
summay = summay.substring(0, 200) + '...';
|
||||||
|
}
|
||||||
|
const prompt = record['提示词'] || '';
|
||||||
|
const type = record['类型'] || '';
|
||||||
|
const content = `上一次执行的时间是${strTime(startTime)},当前时间是${currentTime},请帮我计算下一次的运行时间,如果时间不存在,默认在8点启动。
|
||||||
${prompt ? `这是我给你的提示词,帮你更好地理解我的需求:${prompt}` : ''}
|
${prompt ? `这是我给你的提示词,帮你更好地理解我的需求:${prompt}` : ''}
|
||||||
|
|
||||||
相关资料是
|
相关资料是
|
||||||
@@ -150,43 +170,115 @@ ${prompt ? `这是我给你的提示词,帮你更好地理解我的需求:${
|
|||||||
总结:${summay}
|
总结:${summay}
|
||||||
类型: ${type}
|
类型: ${type}
|
||||||
`
|
`
|
||||||
const ai = useContextKey('ai');
|
const ai = useContextKey('ai');
|
||||||
await ai.chat([
|
await ai.chat([
|
||||||
{ role: 'system', content: `你是一个时间计算专家,擅长根据任务类型和时间计算下一次运行时间。只返回我对应的日期的结果,格式是:YYYY-MM-DD HH:mm:ss。` },
|
{ role: 'system', content: `你是一个时间计算专家,擅长根据任务类型和时间计算下一次运行时间。只返回我对应的日期的结果,格式是:YYYY-MM-DD HH:mm:ss。` },
|
||||||
{ role: 'user', content }
|
{ role: 'user', content }
|
||||||
])
|
])
|
||||||
let nextTime = ai.responseText?.trim();
|
let nextTime = ai.responseText?.trim();
|
||||||
try {
|
try {
|
||||||
// 判断返回的时间是否可以格式化
|
// 判断返回的时间是否可以格式化
|
||||||
if (nextTime && dayjs(nextTime).isValid()) {
|
if (nextTime && dayjs(nextTime).isValid()) {
|
||||||
const time = dayjs(nextTime);
|
const time = dayjs(nextTime);
|
||||||
if (isLuar) {
|
if (isLuar) {
|
||||||
const festival = createLunarDate({ year: time.year(), month: time.month() + 1, day: time.date() });
|
const festival = createLunarDate({ year: time.year(), month: time.month() + 1, day: time.date() });
|
||||||
const { date } = toGregorian(festival);
|
const { date } = toGregorian(festival);
|
||||||
nextTime = dayjs(date).toISOString();
|
nextTime = dayjs(date).toISOString();
|
||||||
|
} else {
|
||||||
|
nextTime = time.toISOString();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nextTime = time.toISOString();
|
messages.push({
|
||||||
|
id,
|
||||||
|
content: `记录 ${id} 的任务 "${record['标题']}",AI 返回的时间格式无效,无法格式化,返回内容是:${ai.responseText}`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
ctx.throw(500, 'AI 返回的时间格式无效,无法格式化');
|
messages.push({
|
||||||
|
id,
|
||||||
|
content: `记录 ${id} 的任务 "${record['标题']}",AI 返回结果解析失败,返回内容是:${ai.responseText}`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
const update = await life.updateItem({ Id: id, '启动时间': nextTime });
|
||||||
ctx.throw(500, 'AI 返回结果解析失败');
|
if (update.code !== 200) {
|
||||||
|
messages.push({
|
||||||
|
id,
|
||||||
|
content: `记录 ${id} 的任务 "${record['标题']}",更新记录失败`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const msg = {
|
||||||
|
id,
|
||||||
|
nextTime,
|
||||||
|
showCNTime: dayjs(nextTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
content: `任务 "${record['标题']}" 已标记为完成。下一次运行时间是 ${dayjs(nextTime).format('YYYY-MM-DD HH:mm:ss')}`
|
||||||
|
};
|
||||||
|
messages.push(msg);
|
||||||
}
|
}
|
||||||
const update = await life.updateItem({ Id: id, '启动时间': nextTime });
|
|
||||||
if (update.code !== 200) {
|
for (const _id of ids) {
|
||||||
ctx.throw(500, '更新记录失败');
|
await changeItem(Number(_id));
|
||||||
}
|
}
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
id,
|
content: messages.map(m => m.content).join('\n'),
|
||||||
nextTime,
|
list: messages
|
||||||
showCNTime: dayjs(nextTime).format('YYYY-MM-DD HH:mm:ss'),
|
|
||||||
content: `任务 "${record['标题']}" 已标记为完成。下一次运行时间是 ${dayjs(nextTime).format('YYYY-MM-DD HH:mm:ss')}`
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|
||||||
|
app.route({
|
||||||
|
path: 'noco-life',
|
||||||
|
key: 'record',
|
||||||
|
description: `创建或者更新一条新的记录,参数是 question 和 id, 如果id存在,则更新记录,否则创建新的记录`,
|
||||||
|
middleware: ['auth']
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const { id, question } = ctx.query;
|
||||||
|
let summary = '空'
|
||||||
|
const token = ctx.query.token || '';
|
||||||
|
const tableId = ctx.query.tableId || '';
|
||||||
|
const nocoLifeService = new NocoLifeService({ token, tableId });
|
||||||
|
await nocoLifeService.initConfig()
|
||||||
|
const life = nocoLifeService.life;
|
||||||
|
const ai = useContextKey('ai');
|
||||||
|
let record = null;
|
||||||
|
if (id) {
|
||||||
|
record = await life.getItem(id);
|
||||||
|
if (record.code !== 200) {
|
||||||
|
// 获取记录失败
|
||||||
|
} else {
|
||||||
|
summary = record.data['总结'] || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const prompt = `对当前的内容进行总结,要求简洁扼要,200字以内。如果内容已经很简洁,则不需要修改。当前内容是:${question}\n历史总结内容是:${summary}`;
|
||||||
|
await ai.chat([
|
||||||
|
{ role: 'system', content: `你是一个总结专家,擅长将冗长的信息进行提炼和总结。` },
|
||||||
|
{ role: 'user', content: prompt }
|
||||||
|
])
|
||||||
|
const newSummary = ai.responseText?.trim() || '';
|
||||||
|
if (record) {
|
||||||
|
// 更新记录
|
||||||
|
const updateRes = await life.updateItem({ Id: id, '总结': newSummary });
|
||||||
|
if (updateRes.code !== 200) {
|
||||||
|
ctx.throw(500, '更新记录失败');
|
||||||
|
}
|
||||||
|
ctx.body = {
|
||||||
|
id: id,
|
||||||
|
content: `已更新记录 ${id} 的总结内容为:${newSummary}`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 创建记录
|
||||||
|
const createRes = await life.createItem({ '标题': question.slice(0, 50), '总结': newSummary, '任务': '运行中', '启动时间': new Date().toISOString() });
|
||||||
|
if (createRes.code !== 200) {
|
||||||
|
ctx.throw(500, '创建记录失败');
|
||||||
|
}
|
||||||
|
ctx.body = {
|
||||||
|
id: createRes.data.Id,
|
||||||
|
content: `已创建新的记录,ID 是 ${createRes.data.Id}\n内容是:${newSummary}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).addTo(app);
|
||||||
app.route({
|
app.route({
|
||||||
path: 'noco-life',
|
path: 'noco-life',
|
||||||
key: 'how-to-use',
|
key: 'how-to-use',
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { Query } from "@kevisual/query/query";
|
|||||||
import { CustomError } from '@kevisual/router'
|
import { CustomError } from '@kevisual/router'
|
||||||
type NocoLifeServiceOpts = {
|
type NocoLifeServiceOpts = {
|
||||||
token: string;
|
token: string;
|
||||||
|
/**
|
||||||
|
* 不使用默认的视图配置,使用当前的表
|
||||||
|
*/
|
||||||
|
tableId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NocoLifeConfig = {
|
export type NocoLifeConfig = {
|
||||||
@@ -17,9 +21,11 @@ export class NocoLifeService {
|
|||||||
nocoApi: NocoApi;
|
nocoApi: NocoApi;
|
||||||
life: Life;
|
life: Life;
|
||||||
queryConfig: QueryConfig;
|
queryConfig: QueryConfig;
|
||||||
|
tableId: string;
|
||||||
constructor(opts: NocoLifeServiceOpts) {
|
constructor(opts: NocoLifeServiceOpts) {
|
||||||
this.token = opts.token;
|
this.token = opts.token;
|
||||||
|
const tableId = opts.tableId;
|
||||||
|
this.tableId = tableId || '';
|
||||||
this.initEnv();
|
this.initEnv();
|
||||||
}
|
}
|
||||||
initEnv() {
|
initEnv() {
|
||||||
@@ -31,7 +37,7 @@ export class NocoLifeService {
|
|||||||
async getLifeConfig(): Promise<NocoLifeConfig> {
|
async getLifeConfig(): Promise<NocoLifeConfig> {
|
||||||
const res = await this.queryConfig.getByKey('life.json', { token: this.token });
|
const res = await this.queryConfig.getByKey('life.json', { token: this.token });
|
||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
return {} as NocoLifeConfig;
|
return { 'baseId': '', baseURL: '', token: '', tableId: '' } as NocoLifeConfig;
|
||||||
}
|
}
|
||||||
return res.data?.data as NocoLifeConfig;
|
return res.data?.data as NocoLifeConfig;
|
||||||
}
|
}
|
||||||
@@ -42,13 +48,17 @@ export class NocoLifeService {
|
|||||||
}, { token: this.token });
|
}, { token: this.token });
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
async createLife(data: NocoLifeConfig) {
|
createLife(data: NocoLifeConfig) {
|
||||||
|
if (!data.tableId && this.tableId) {
|
||||||
|
data.tableId = this.tableId;
|
||||||
|
}
|
||||||
const nocoApi = new NocoApi({
|
const nocoApi = new NocoApi({
|
||||||
baseURL: data.baseURL || '',
|
baseURL: data.baseURL || '',
|
||||||
token: data.token || '',
|
token: data.token || '',
|
||||||
table: data.tableId || '',
|
table: data.tableId || '',
|
||||||
});
|
});
|
||||||
const life = new Life({ nocoApi, baseId: data.baseId });
|
const life = new Life({ nocoApi, baseId: data.baseId });
|
||||||
|
this.life = life;
|
||||||
return life;
|
return life;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -71,24 +81,23 @@ export class NocoLifeService {
|
|||||||
|
|
||||||
this.nocoApi = nocoApi;
|
this.nocoApi = nocoApi;
|
||||||
const life = new Life({ nocoApi, baseId: lifeConfig.baseId });
|
const life = new Life({ nocoApi, baseId: lifeConfig.baseId });
|
||||||
const tableId = lifeConfig.tableId || '';
|
let tableId = this.tableId || lifeConfig.tableId || '';
|
||||||
if (!tableId) {
|
if (!tableId) {
|
||||||
const newTable = await life.createTable()
|
const newTable = await life.createTable()
|
||||||
if (newTable.code !== 200) {
|
if (newTable.code !== 200) {
|
||||||
throw new CustomError(500, `创建默认表失败: ${newTable.message}`);
|
throw new CustomError(500, `创建默认表失败: ${newTable.message}`);
|
||||||
}
|
}
|
||||||
lifeConfig.tableId = newTable.data?.id;
|
tableId = newTable.data?.id;
|
||||||
// 保存 tableId 到配置中
|
// 保存 tableId 到配置中
|
||||||
const res = await this.queryConfig.updateConfig({
|
const res = await this.queryConfig.updateConfig({
|
||||||
key: 'life.json',
|
key: 'life.json',
|
||||||
data: lifeConfig,
|
data: { ...lifeConfig, tableId },
|
||||||
}, { token: this.token });
|
}, { token: this.token });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
console.log('默认表创建成功,配置已更新');
|
console.log('默认表创建成功,配置已更新');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
life.tableId = lifeConfig.tableId || '';
|
life.tableId = tableId || '';
|
||||||
nocoApi.record.table = life.tableId;
|
|
||||||
this.life = life;
|
this.life = life;
|
||||||
return lifeConfig;
|
return lifeConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { app, sleep } from './common';
|
import { app, sleep, token } from './common.ts';
|
||||||
|
|
||||||
|
|
||||||
const res = await app.call({
|
const res = await app.call({
|
||||||
@@ -8,8 +8,13 @@ const res = await app.call({
|
|||||||
// question: '今天我需要做什么事情?',
|
// question: '今天我需要做什么事情?',
|
||||||
// question: '任务5 完成了,帮我判断下一次运行时间应该是什么时候?',
|
// question: '任务5 完成了,帮我判断下一次运行时间应该是什么时候?',
|
||||||
// question: '任务59 完成了',
|
// question: '任务59 完成了',
|
||||||
question: '我的多维表格配置'
|
// question: '我的多维表格配置'
|
||||||
}
|
// question: '记录一下,今天洗了澡',
|
||||||
|
// question: '编辑任务123,进行补充, 对opencode进行描述介绍。',
|
||||||
|
// question: '编辑任务94,对内容注释',
|
||||||
|
question: '任务59和124完成了',
|
||||||
|
token: token,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('res', res.code, res.body, res.message);
|
console.log('res', res.code, res.body, res.message);
|
||||||
@@ -6,13 +6,15 @@ import { BailianProvider } from '@kevisual/ai';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
console.log('process.env.BAILIAN_API_KEY', process.env.BAILIAN_API_KEY);
|
console.log('process.env.BAILIAN_API_KEY', process.env.BAILIAN_API_KEY);
|
||||||
|
const token = process.env.KEVISUAL_API_TOKEN || '';
|
||||||
const ai = useContextKey('ai', () => {
|
const ai = useContextKey('ai', () => {
|
||||||
return new BailianProvider({
|
return new BailianProvider({
|
||||||
apiKey: process.env.BAILIAN_API_KEY || '',
|
apiKey: process.env.BAILIAN_API_KEY || '',
|
||||||
model: 'qwen-turbo'
|
model: 'qwen-plus'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
export {
|
export {
|
||||||
app,
|
app,
|
||||||
ai,
|
ai,
|
||||||
|
token,
|
||||||
}
|
}
|
||||||
35
pnpm-lock.yaml
generated
35
pnpm-lock.yaml
generated
@@ -30,6 +30,12 @@ importers:
|
|||||||
|
|
||||||
backend:
|
backend:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@kevisual/app':
|
||||||
|
specifier: ^0.0.1
|
||||||
|
version: 0.0.1(dotenv@17.2.3)
|
||||||
|
'@kevisual/context':
|
||||||
|
specifier: ^0.0.4
|
||||||
|
version: 0.0.4
|
||||||
'@kevisual/local-proxy':
|
'@kevisual/local-proxy':
|
||||||
specifier: ^0.0.8
|
specifier: ^0.0.8
|
||||||
version: 0.0.8
|
version: 0.0.8
|
||||||
@@ -670,6 +676,12 @@ packages:
|
|||||||
'@kevisual/ai@0.0.16':
|
'@kevisual/ai@0.0.16':
|
||||||
resolution: {integrity: sha512-K5KYm+dwHCnB61BhVFh9UcWiOS/FeS29ijvgwE/cQR8RonfPtX/oI7WhAu0jCGGSxTI6cel2LjrpU4JoVzWgnA==}
|
resolution: {integrity: sha512-K5KYm+dwHCnB61BhVFh9UcWiOS/FeS29ijvgwE/cQR8RonfPtX/oI7WhAu0jCGGSxTI6cel2LjrpU4JoVzWgnA==}
|
||||||
|
|
||||||
|
'@kevisual/ai@0.0.19':
|
||||||
|
resolution: {integrity: sha512-AFc8m6OcHZNxCb88bvzhvwWTZ4EVYyPupBzPUsLKLpdNBvsqm9TRboKCM2brJj2cqHnm+H+RbAk9AcGJkYhRCA==}
|
||||||
|
|
||||||
|
'@kevisual/app@0.0.1':
|
||||||
|
resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==}
|
||||||
|
|
||||||
'@kevisual/cache@0.0.3':
|
'@kevisual/cache@0.0.3':
|
||||||
resolution: {integrity: sha512-BWEck69KYL96/ywjYVkML974RHjDJTj2ITQND1zFPR+hlBV1H1p55QZgSYRJCObg3EAV1S9Zic/fR2T4pfe8yg==}
|
resolution: {integrity: sha512-BWEck69KYL96/ywjYVkML974RHjDJTj2ITQND1zFPR+hlBV1H1p55QZgSYRJCObg3EAV1S9Zic/fR2T4pfe8yg==}
|
||||||
|
|
||||||
@@ -2472,6 +2484,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
|
||||||
|
mitt@3.0.1:
|
||||||
|
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||||
|
|
||||||
mrmime@2.0.1:
|
mrmime@2.0.1:
|
||||||
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -3820,6 +3835,24 @@ snapshots:
|
|||||||
'@kevisual/permission': 0.0.3
|
'@kevisual/permission': 0.0.3
|
||||||
'@kevisual/query': 0.0.30
|
'@kevisual/query': 0.0.30
|
||||||
|
|
||||||
|
'@kevisual/ai@0.0.19':
|
||||||
|
dependencies:
|
||||||
|
'@kevisual/logger': 0.0.4
|
||||||
|
'@kevisual/permission': 0.0.3
|
||||||
|
'@kevisual/query': 0.0.31
|
||||||
|
|
||||||
|
'@kevisual/app@0.0.1(dotenv@17.2.3)':
|
||||||
|
dependencies:
|
||||||
|
'@kevisual/ai': 0.0.19
|
||||||
|
'@kevisual/context': 0.0.4
|
||||||
|
'@kevisual/query': 0.0.31
|
||||||
|
'@kevisual/router': 0.0.36
|
||||||
|
'@kevisual/use-config': 1.0.21(dotenv@17.2.3)
|
||||||
|
mitt: 3.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- dotenv
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@kevisual/cache@0.0.3':
|
'@kevisual/cache@0.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
idb-keyval: 6.2.2
|
idb-keyval: 6.2.2
|
||||||
@@ -6207,6 +6240,8 @@ snapshots:
|
|||||||
|
|
||||||
minipass@7.1.2: {}
|
minipass@7.1.2: {}
|
||||||
|
|
||||||
|
mitt@3.0.1: {}
|
||||||
|
|
||||||
mrmime@2.0.1: {}
|
mrmime@2.0.1: {}
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user