clear: old code

This commit is contained in:
熊潇 2025-02-18 18:10:02 +08:00
parent d9fe68d3fe
commit 84edde385e
67 changed files with 288 additions and 6897 deletions

2
.gitignore vendored
View File

@ -2,8 +2,6 @@ node_modules
dist
# dist/app.cjs
app.config.json5
apps.config.json

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "packages/ai-graph"]
path = packages/ai-graph
url = git@git.xiongxiao.me:kevisual/kevisual-ai-graph.git
[submodule "packages/var-proxy"]
path = packages/var-proxy
url = git@git.xiongxiao.me:kevisual/var-proxy.git

2
.npmrc
View File

@ -1,3 +1 @@
@abearxiong:registry=https://npm.pkg.github.com
@build:registry=https://npm.xiongxiao.me
@kevisual:registry=https://npm.xiongxiao.me

View File

@ -1,7 +1,7 @@
module.exports = {
apps: [
{
name: 'codeflow', // 应用名称
name: 'codecenter', // 应用名称
script: './dist/app.mjs', // 入口文件
// cwd: '.', // 设置当前工作目录
output: './logs/codflow.log',

View File

@ -1,7 +1,7 @@
{
"name": "@build/code-flow",
"version": "0.0.2",
"description": "code的flow流程成图",
"name": "@kevisual/code-center",
"version": "0.0.1",
"description": "code center",
"type": "module",
"main": "index.js",
"author": "abearxiong",
@ -12,14 +12,14 @@
"test": "tsx test/**/*.ts",
"dev:watch": "cross-env NODE_ENV=development concurrently -n \"Watch,Dev\" -c \"green,blue\" \"npm run watch\" \"sleep 1 && npm run dev\" ",
"build": "rimraf dist && rollup -c rollup.config.mjs",
"deploy": "rsync -avz --delete ./dist/ --exclude='app.config.json5' light:~/apps/codeflow/backend",
"deploy": "rsync -avz --delete ./dist/ --exclude='app.config.json5' light:~/apps/codecenter/dist",
"clean": "rm -rf dist",
"reload": "ssh light pm2 restart codeflow",
"reload": "ssh light pm2 restart codecenter",
"pub": "npm run build && npm run deploy && npm run reload",
"deploy:nova": "rsync -avz --delete ./dist/ --exclude='app.config.json5' nova:~/apps/codeflow/backend",
"deploy:nova": "rsync -avz --delete ./dist/ --exclude='app.config.json5' nova:~/apps/codecenter/dist",
"apps:build": "rollup -c rollup.apps.config.mjs",
"apps:watch": "rollup -c rollup.apps.config.mjs -w",
"start": "pm2 start dist/app.mjs --name codeflow"
"start": "pm2 start dist/app.mjs --name codecenter"
},
"keywords": [],
"types": "types/index.d.ts",
@ -30,41 +30,29 @@
],
"license": "UNLICENSED",
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@kevisual/ai-graph": "workspace:^",
"@kevisual/ai-lang": "workspace:^",
"@kevisual/auth": "1.0.5",
"@kevisual/local-app-manager": "0.1.6",
"@kevisual/router": "^0.0.6-alpha-5",
"@types/semver": "^7.5.8",
"archiver": "^7.0.1",
"bullmq": "^5.34.6",
"dayjs": "^1.11.13",
"dts-bundle-generator": "^9.5.1",
"formidable": "^3.5.2",
"ioredis": "^5.4.2",
"ioredis": "^5.5.0",
"json5": "^2.2.3",
"jsonwebtoken": "^9.0.2",
"lodash-es": "^4.17.21",
"minio": "^8.0.3",
"nanoid": "^5.0.9",
"neo4j-driver": "^5.27.0",
"neode": "^0.4.9",
"minio": "^8.0.4",
"nanoid": "^5.1.0",
"node-fetch": "^3.3.2",
"ollama": "^0.5.11",
"p-queue": "^8.0.1",
"pg": "^8.13.1",
"rollup-plugin-esbuild": "^6.1.1",
"semver": "^7.6.3",
"p-queue": "^8.1.0",
"pg": "^8.13.3",
"rollup-plugin-esbuild": "^6.2.0",
"semver": "^7.7.1",
"sequelize": "^6.37.5",
"socket.io": "^4.8.1",
"sqlite3": "^5.1.7",
"strip-ansi": "^7.1.0",
"tar": "^7.4.3",
"uuid": "^11.0.3",
"zod": "^3.24.1"
"uuid": "^11.0.5",
"zod": "^3.24.2"
},
"devDependencies": {
"@kevisual/use-config": "^1.0.7",
@ -77,23 +65,21 @@
"@types/archiver": "^6.0.3",
"@types/crypto-js": "^4.2.2",
"@types/formidable": "^3.4.5",
"@types/jsonwebtoken": "^9.0.7",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.10.5",
"@types/react": "^19.0.2",
"@types/node": "^22.13.4",
"@types/react": "^19.0.10",
"@types/uuid": "^10.0.0",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"nodemon": "^3.1.9",
"pm2": "^5.4.3",
"pm2-dev": "^5.4.1",
"rimraf": "^6.0.1",
"rollup": "^4.29.1",
"rollup": "^4.34.8",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-dts": "^6.1.1",
"tape": "^5.9.0",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
"typescript": "^5.7.3"
},
"resolutions": {
"inflight": "latest",

@ -1 +0,0 @@
Subproject commit f15a9035a5ad615e15d196c933e508968276cf58

View File

@ -1,35 +0,0 @@
{
"name": "@kevisual/ai-lang",
"version": "0.0.1",
"description": "",
"main2": "dist/index.js",
"main": "src/index.ts",
"type": "module",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@abearxiong/router": "0.0.1-alpha.36",
"@abearxiong/use-config": "^0.0.2",
"@langchain/core": "^0.3.3",
"@langchain/langgraph": "^0.2.9",
"@langchain/langgraph-checkpoint-mongodb": "^0.0.3",
"@langchain/ollama": "^0.1.0",
"@langchain/openai": "^0.3.2",
"mongodb": "^6.9.0",
"nanoid": "^5.0.7",
"ws": "^8.18.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.0",
"@types/node": "^22.7.2",
"rollup": "^4.22.4",
"ts-lib": "^0.0.5"
}
}

View File

@ -1,24 +0,0 @@
// rollup.config.js
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
/**
* @type {import('rollup').RollupOptions}
*/
export default {
input: 'src/index.ts', // TypeScript 入口文件
output: {
file: 'dist/index.js', // 输出文件
format: 'es', // 输出格式设置为 ES 模块
},
plugins: [
resolve(), // 使用 @rollup/plugin-node-resolve 解析 node_modules 中的模块
// commonjs(),
typescript({
allowImportingTsExtensions: true,
noEmit: true,
}), // 使用 @rollup/plugin-typescript 处理 TypeScript 文件
],
external: ['ws']
};

View File

@ -1,11 +0,0 @@
import { App } from '@abearxiong/router';
import { useConfig } from '@abearxiong/use-config';
const config = useConfig();
export const app = new App({
serverOptions: {
path: '/api/lang',
},
});

View File

@ -1,4 +0,0 @@
export * from './app.ts';
import './routes/agent.ts';
import { agentManger } from './module/agent.ts';
export { agentManger };

View File

@ -1,51 +0,0 @@
import { AiAgent, AiAgentOpts } from './create-agent.ts';
export enum AgentMangerStatus {
init = 'i',
ready = 'r',
error = 'e',
}
export class AgentManger {
agents: AiAgent[] = [];
staus: AgentMangerStatus = AgentMangerStatus.init;
constructor() {}
addAgent(agent: AiAgent) {
this.agents.push(agent);
}
getAgent(id: string) {
const agent = this.agents.find((agent) => agent.id === id);
return agent;
}
removeAgent(id: string) {
this.agents = this.agents.filter((agent) => agent.id !== id);
}
createAgent(opts: AiAgentOpts) {
if (!opts.id) {
const agent = new AiAgent(opts);
this.addAgent(agent);
return agent;
}
const agent = this.agents.find((agent) => agent.id === opts.id);
if (!agent) {
const agent = new AiAgent(opts);
this.addAgent(agent);
return agent;
}
return agent;
}
/**
* agent
* @param opts
* @returns
*/
newAgent(opts: AiAgentOpts) {
return new AiAgent(opts);
}
createAgentList(opts: AiAgentOpts[]) {
if (this.staus === AgentMangerStatus.init) {
return;
}
this.staus = AgentMangerStatus.ready;
return opts.map((opt) => this.createAgent(opt));
}
}
export const agentManger = new AgentManger();

View File

@ -1,142 +0,0 @@
import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { MemorySaver } from '@langchain/langgraph';
import { ChatOllama } from '@langchain/ollama';
import { ChatOpenAI } from '@langchain/openai';
import { client } from './mongo.ts';
import { MongoDBSaver } from '@langchain/langgraph-checkpoint-mongodb';
import { nanoid } from 'nanoid';
import { HumanMessage } from '@langchain/core/messages';
export { HumanMessage };
export const agentModelList = ['qwen2.5:14b', 'qwen2.5-coder:7b', 'llama3.1:8b', 'bakllava:latest', 'gpt-4o'] as const;
export type AiAgentModel = (typeof agentModelList)[number];
export type AiAgentCache = 'memory' | 'mongodb';
export type AiAgentOpts = {
id: string;
type: 'ollama' | 'openai';
model: AiAgentModel;
baseUrl: string;
apiKey?: string;
temperature?: number;
cache?: AiAgentCache;
cacheName?: string;
};
export type AiAgentStatus = 'ready' | 'loading' | 'error';
// export const CreateAgent = (opts: CreateAgentOptions) => {
// const;
// };
export class AiAgent {
agent: ReturnType<typeof createReactAgent>;
agentModel: ChatOllama | ChatOpenAI;
memorySaver: MemorySaver | MongoDBSaver;
id: string;
baseUrl: string;
type: 'ollama' | 'openai';
model: AiAgentModel;
apiKey: string;
temperature = 0;
cache?: AiAgentCache;
cacheName?: string;
status?: 'ready' | 'loading' | 'error';
constructor(opts?: AiAgentOpts) {
this.type = opts?.type || 'ollama';
this.baseUrl = opts?.baseUrl || 'http://localhost:11434';
this.model = opts?.model;
this.apiKey = opts?.apiKey;
this.temperature = opts?.temperature || 0;
this.cache = opts?.cache || 'mongodb';
this.cacheName = opts?.cacheName || 'checkpointer';
this.id = opts?.id || nanoid(8);
if (this.type === 'openai') {
if (!this.apiKey) {
throw new Error('apiKey is required for openai agent');
}
}
this.status = 'loading';
this.createAgent();
}
createAgent() {
this.createAgentModel();
this.createMemoerSaver();
if (this.status === 'error') {
return;
}
const agentModel = this.agentModel;
const memorySaver = this.memorySaver;
this.agent = createReactAgent({
llm: agentModel,
tools: [],
checkpointSaver: memorySaver,
});
this.status = 'ready';
}
createAgentModel() {
const type = this.type;
const model = this.model;
const temperature = this.temperature;
const apiKey = this.apiKey;
const baseUrl = this.baseUrl;
let agentModel;
try {
if (type === 'ollama') {
agentModel = new ChatOllama({ temperature, model, baseUrl });
} else if (type === 'openai') {
agentModel = new ChatOpenAI(
{ temperature, model, apiKey },
{
baseURL: baseUrl,
},
);
}
} catch (e) {
console.error('loading model error', e);
this.status = 'error';
return;
}
this.agentModel = agentModel;
return this;
}
createMemoerSaver() {
const cache = this.cache;
const cacheName = this.cacheName;
let memorySaver;
try {
if (cache === 'memory') {
memorySaver = new MemorySaver();
} else if (cache === 'mongodb') {
memorySaver = new MongoDBSaver({ client, dbName: cacheName });
}
} catch (e) {
console.error(e);
this.status = 'error';
return;
}
this.memorySaver = memorySaver;
}
sendHumanMessage(message: string, opts?: { thread_id: string }) {
const mesage = new HumanMessage(message);
return this.agent.invoke({ messages: [mesage] }, { configurable: { thread_id: 'test_human', ...opts } });
}
close() {
// 清除 memory saver
this.memorySaver = null;
this.agentModel = null;
this.agent = null;
}
async testQuery() {
const id = this.id;
try {
const agent = this.agent;
const message = new HumanMessage('你好');
const res = await agent.invoke({ messages: [message] }, { configurable: { thread_id: 'test_ping' } });
if (res) {
return res;
}
} catch (e) {
console.error(`test query [${id}]:`, e);
this.status = 'error';
}
}
}

View File

@ -1,14 +0,0 @@
import { MongoClient } from 'mongodb';
import { useConfig } from '@abearxiong/use-config';
const { mongo } = useConfig<{ host: string; password: string; username: string }>();
export const client = new MongoClient(`mongodb://${mongo.username}:${mongo.password}@${mongo.host}`, {});
// 当连接成功时,打印出连接成功的信息
client
.connect()
.then(() => {
console.log('mongo Connected successfully to server');
})
.catch((err) => {
console.error(err);
});

View File

@ -1,19 +0,0 @@
import { CustomError } from '@abearxiong/router';
import { app } from '../app.ts';
// import { agent, HumanMessage } from '../agent/index.ts';
import { agentManger } from '../module/agent.ts';
app
.route('ai', 'chat')
.define(async (ctx) => {
const { message, agentId, chatId } = ctx.query.data;
// const response = await agent.invoke({ messages: [new HumanMessage(message)] }, { configurable: { thread_id: '44' } });
// ctx.body = response;
//
const agent = agentManger.getAgent(agentId);
if (!agent) {
throw new CustomError('agent not found');
}
})
.addTo(app);
// app.router.parse({})

View File

@ -1,32 +0,0 @@
{
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"noImplicitAny": false,
"outDir": "./dist",
"sourceMap": false,
"allowJs": true,
"newLine": "LF",
"baseUrl": "./",
"typeRoots": [
"node_modules/@types",
],
"declaration": true,
"noEmit": false,
"allowImportingTsExtensions": true,
"emitDeclarationOnly": true,
"moduleResolution": "NodeNext",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"paths": {
"@/*": [
"src/*"
],
}
},
"include": [
"src/**/*.ts"
],
"exclude": [],
}

@ -1 +0,0 @@
Subproject commit 79a9568a87536aa8e467182f371c95b8a2f25b8b

4172
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
import * as dts from 'dts-bundle';
import path from 'path';
const currentPath = process.cwd();
const packagePath = path.join(currentPath, 'script/package/package.json');
const mainPath = path.join(currentPath, 'src/type.ts');
const outPath = path.join(currentPath, 'types/index.d.ts');
// node script/dts/index.mjs
dts.bundle({
name: 'my-library',
main: mainPath,
out: outPath,
removeSource: true,
outputAsModuleFolder: true,
});

View File

@ -8,15 +8,23 @@ fs.writeFileSync(
packagePath,
JSON.stringify(
{
name: 'codeflow',
name: 'codecenter',
version: '1.0.0',
devDependencies: {
'@babel/core': '^7.24.7',
'@babel/preset-env': '^7.24.7',
'@babel/preset-typescript': '^7.24.7',
sequelize: '^6.37.3',
'socket.io': '^4.7.5',
pg: '^8.12.0',
scripts: {
start: 'pm2 start dist/app.mjs --name codecenter',
},
dependencies: {
'@kevisual/router': '^0.0.6-alpha-5',
'@kevisual/use-config': '^1.0.7',
ioredis: '^5.5.0',
minio: '^8.0.4',
pg: '^8.13.3',
sequelize: '^6.37.5',
sqlite3: '^5.1.7',
'socket.io': '^4.8.1',
'@msgpack/msgpack': '3.0.1',
pino: '^9.6.0',
'pino-pretty': '^13.0.0',
},
},
null,

View File

@ -1,17 +1,20 @@
{
"name": "codeflow",
"name": "codecenter",
"version": "1.0.0",
"scripts": {
"start": "pm2 start dist/app.mjs --name codecenter"
},
"dependencies": {
"@kevisual/router": "^0.0.6-alpha-2",
"@kevisual/use-config": "^1.0.3",
"ioredis": "^5.4.1",
"minio": "^8.0.2",
"pg": "^8.13.1",
"@kevisual/router": "^0.0.6-alpha-5",
"@kevisual/use-config": "^1.0.7",
"ioredis": "^5.5.0",
"minio": "^8.0.4",
"pg": "^8.13.3",
"sequelize": "^6.37.5",
"sqlite3": "^5.1.7",
"socket.io": "^4.8.1",
"@msgpack/msgpack": "3.0.0-beta2",
"pino": "^9.5.0",
"@msgpack/msgpack": "3.0.1",
"pino": "^9.6.0",
"pino-pretty": "^13.0.0"
}
}

View File

@ -1,24 +0,0 @@
import { App } from '@kevisual/router';
import { sequelize } from './modules/sequelize.ts';
import { emitter } from './modules/event.ts';
export { sequelize };
export const app = new App();
export const runAppRouterFn = async (key: string, params: any) => {
emitter.emit(`router.fn`, key, params);
};
const runListener = async (app: App) => {
emitter.on('router.fn', (key, params) => {
if (!app.router[key]) {
console.error('router key not found:', key);
} else {
app.router[key](params);
}
});
};
runListener(app);
export const appendTo = (realApp: App) => {
realApp.importApp(app);
runListener(realApp);
};

View File

@ -1,15 +0,0 @@
import { app } from './app.ts';
new app.Route('admin', 'getRouteList')
.define(async (ctx) => {
const list = app.router.getList();
// ctx.body = list.filter((r) => !r.path.startsWith('admin'));
ctx.body = list.map((r) => {
return {
path: r.path,
key: r.key,
};
});
return ctx;
})
.addTo(app);

View File

@ -1 +0,0 @@
export { manager } from './manager.ts';

View File

@ -1,122 +0,0 @@
// import { router } from '../../modules/router.ts';
import { runAppRouterFn } from '../app.ts';
import { Route } from '@kevisual/router';
import { RouterCodeModel, RouterCode } from '../models/code.ts';
export enum CodeStatus {
running = 'running',
stop = 'stop',
fail = 'fail',
}
export type CodeManager = {
fn?: any;
status?: CodeStatus;
errorMsg?: string;
lock?: boolean; // 是否锁定
} & Partial<RouterCode>;
const codeDemoRun = `async function run(ctx) {
ctx.body = 'test js';
return ctx;
}`;
const templateFn = (codeStr: string) => {
return `
${codeStr}
if(run) {
return run(ctx);
}
if(main) {
return main(ctx);
}
return 'no run or main function';
`;
};
export const loadOne = async (item: RouterCodeModel) => {
const { path, key, id, code, exec, project, middleware } = item.toJSON();
const codeStr = exec || code;
try {
const fn: any = new Function('ctx', templateFn(codeStr));
// run code
const codeRunRoute = new Route(path, key, { id });
codeRunRoute.run = fn;
codeRunRoute.middleware = middleware;
runAppRouterFn('removeById', id);
runAppRouterFn('add', codeRunRoute);
return {
...item.toJSON(),
path,
key,
id,
project,
fn,
status: CodeStatus.running,
};
} catch (e) {
console.error('error id:', id, '\n', e);
return {
path,
key,
id,
project,
status: CodeStatus.fail,
errorMsg: e.message.toString(),
};
}
};
export const load = async function () {
const codes = await RouterCodeModel.findAll({
logging: (sql, timing) => {
console.log('manager load database router codeModel');
},
});
const codeManager: CodeManager[] = codes.map((item) => {
const { path, key, id, code, exec, project, active, middleware } = item.toJSON();
if (!active) {
return {
...item.toJSON(),
path,
key,
id,
code,
project,
middleware,
status: CodeStatus.stop,
};
}
try {
const codeStr = exec || code;
const fn: any = new Function('ctx', templateFn(codeStr));
// run code
const codeRunRoute = new Route(path, key, { id });
codeRunRoute.run = fn;
codeRunRoute.middleware = middleware;
runAppRouterFn('add', codeRunRoute);
return {
...item.toJSON(),
path,
key,
id,
code,
project,
type: item.type,
fn,
status: CodeStatus.running,
};
} catch (e) {
console.error('error id:', id, '\n', e);
return {
path,
key,
id,
code,
project,
type: item.type,
status: CodeStatus.fail,
errorMsg: e.message.toString(),
};
}
});
return codeManager;
};

View File

@ -1,86 +0,0 @@
import stream from 'stream'; // 默认导入整个模块
const { once } = stream; // 从中解构出 EventEmitter
import { load, CodeManager, CodeStatus, loadOne } from './load.ts';
import { RouterCodeModel, TableIsExist } from '../models/code.ts';
import { emitter } from '../modules/event.ts';
export enum LoadStatus {
LOADING = 'loading',
LOADED = 'loaded',
ERROR = 'error',
}
export const manager = {
loaded: LoadStatus.LOADING, // 是否已经加载
list: [] as CodeManager[],
shareLocalList: [] as CodeManager[],
};
// 更新
export const updateNewCode = (code: CodeManager) => {
const index = manager.list.findIndex((item) => item.id === code.id);
if (index === -1) {
manager.list.push(code);
} else {
manager.list[index] = code;
}
};
// 删除
export const removeCode = (id: string) => {
const index = manager.list.findIndex((item) => item.id === id);
if (index !== -1) {
manager.list.splice(index, 1);
}
};
export const stopCode = (id: string) => {
const index = manager.list.findIndex((item) => item.id === id);
if (index !== -1) {
manager.list[index].status = CodeStatus.stop;
}
};
export const startCode = async (code: RouterCodeModel) => {
const index = manager.list.findIndex((item) => item.id === code.id);
console.log('index', index, code.toJSON());
if (index !== -1) {
manager.list[index] = await loadOne(code);
} else {
const codeManger = await loadOne(code);
manager.list.push(codeManger);
}
};
once(emitter, 'loaded')
.then(() => {
manager.loaded = LoadStatus.LOADED;
console.log('manager loaded');
})
.catch((e) => {
manager.loaded = LoadStatus.ERROR;
console.error('manager loaded error', e);
});
const init = async function () {
const r = await load();
manager.list = r;
emitter.emit('loaded');
};
TableIsExist().then(async (res) => {
if (res) {
init();
} else {
console.log('TableIsExist not exist, waiting create');
// 3s后再次检测
setTimeout(() => {
TableIsExist().then(async (res) => {
if (res) {
init();
} else {
console.error('TableIsExist not exist, create error');
process.exit(1);
}
});
}, 3000);
}
});
// init();

View File

@ -1,7 +0,0 @@
import './router.ts';
import './manager.ts';
import './npm.ts';
import './core.ts';
import { app, appendTo } from './app.ts';
export { app, appendTo };

View File

@ -1,58 +0,0 @@
// admin 需要最后运行并在route中进行过滤。
import { Route } from '@kevisual/router';
import { app } from './app.ts';
import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts';
// get manager status
export const managerRouter = new Route('admin', 'getManagerStatus');
managerRouter.run = async (ctx) => {
ctx.body = {
status: manager.loaded,
msg: 'system is running, and load manager success.',
};
return ctx;
};
managerRouter.addTo(app);
// get manager list
app
.route({
path: 'admin',
key: 'getManagerList',
})
.define(async (ctx) => {
ctx.body = manager.list;
// TODO: routerList 可以不暴露
const routerList = ctx.queryRouter.getList().filter((r) => !r.path.startsWith('admin'));
ctx.body = {
list: manager.list,
routerList,
};
return ctx;
})
.addTo(app);
// get manager one
export const managerOne = new Route('admin', 'getManagerOne');
managerOne.run = async (ctx) => {
const verfiy = ctx.currentRoute.verify(ctx);
if (verfiy) return;
const { id } = ctx.query;
const code = manager.list.find((c) => c.id === id);
if (code) {
ctx.body = code;
} else {
ctx.body = 'not found';
ctx.code = 404;
}
return ctx;
};
managerOne.validator = {
id: {
type: 'string',
required: true,
},
};
managerOne.addTo(app);

View File

@ -1,121 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
export type RouterCode = {
id: string;
path: string;
key: string;
active: boolean;
project: string;
code: string;
exec: string;
type: RouterCodeType;
middleware: string[];
next: string;
data: any;
validator: any;
};
export enum RouterCodeType {
route = 'route',
middleware = 'middleware',
}
export class RouterCodeModel extends Model {
declare id: string;
declare path: string;
declare key: string;
declare active: boolean;
declare project: string;
declare code: string;
declare exec: string;
declare type: RouterCodeType;
declare middleware: string[];
declare next: string; // 如果是中间件,不存在
declare data: any; // 内容
declare validator: any;
}
RouterCodeModel.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
comment: 'code id',
},
path: {
type: DataTypes.STRING,
allowNull: false,
},
key: {
type: DataTypes.STRING,
allowNull: true,
},
active: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
project: {
type: DataTypes.STRING,
defaultValue: 'default',
},
code: {
type: DataTypes.TEXT,
defaultValue: '',
},
exec: {
type: DataTypes.TEXT, // 对代码进行编译后的代码
defaultValue: '',
},
type: {
type: DataTypes.ENUM(RouterCodeType.route, RouterCodeType.middleware),
defaultValue: RouterCodeType.route,
},
middleware: {
type: DataTypes.JSON,
defaultValue: [],
},
next: {
type: DataTypes.JSON,
defaultValue: {},
},
data: {
type: DataTypes.JSON,
defaultValue: {},
},
validator: {
type: DataTypes.JSON,
defaultValue: {},
},
},
{
sequelize,
tableName: 'cf_router_code', // container flow router code
paranoid: true,
},
);
// RouterCodeModel 检测不存在,不存在则创建
RouterCodeModel.sync({ alter: true, logging: false })
.then((res) => {
console.log('RouterCodeModel sync', res);
})
.catch((e) => {
console.error('RouterCodeModel sync', e.message);
if (!TableIsExist()) {
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
}
});
export const TableIsExist = async () => {
// 判断cf_router_code表是否存在
const tableIsExist = await sequelize.getQueryInterface().showAllTables({
logging: false,
});
return tableIsExist.includes('cf_router_code');
};

View File

@ -1,66 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
type PageNodeData = {
id: string;
type: string;
data: {
label?: string; // 容器 开始 结束
// 容器上的属性
cid?: string; // 容器code id
};
[key: string]: any;
};
export interface RouterGraphData {
edges: any[];
nodes: PageNodeData[];
viewport: any;
[key: string]: any;
}
/**
*
*/
export class RouterGraphModel extends Model {
declare id: string;
declare title: string;
declare description: string;
declare type: string;
declare data: RouterGraphData;
}
RouterGraphModel.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
comment: 'id',
},
title: {
type: DataTypes.STRING,
defaultValue: '',
},
description: {
type: DataTypes.TEXT,
defaultValue: '',
},
type: {
type: DataTypes.STRING,
defaultValue: '',
},
data: {
type: DataTypes.JSON,
defaultValue: {},
},
},
{
sequelize,
tableName: 'cf_router_graph',
paranoid: true,
},
);
RouterGraphModel.sync({ alter: true, logging: false }).catch((e) => {
console.error('RouterGraphModel sync', e);
});

View File

@ -1,21 +0,0 @@
import stream from 'stream'; // 默认导入整个模块
const { EventEmitter, once } = stream; // 从中解构出 EventEmitter
// 事件
export const emitter = new EventEmitter();
type EmitterType = typeof emitter;
// 异步触发事件 demo
export const asyncEmit = (emitter: EmitterType, eventName: string) => {
return new Promise((resolve) => {
emitter.once(eventName, (value: any) => resolve(value));
});
};
async function main() {
setTimeout(() => {
emitter.emit('asyncEvent', '监听器中的值');
}, 1000);
asyncEmit(emitter, 'asyncEvent').then((result) => {
console.log(result); // 监听器中的值
});
}

View File

@ -1,34 +0,0 @@
import { useConfig } from '@kevisual/use-config';
import { Sequelize } from 'sequelize';
import path from 'path';
import os from 'os';
import fs from 'fs';
const checkFileExistsSync = (filePath: string) => {
try {
fs.accessSync(filePath, fs.constants.F_OK);
} catch (err) {
return false;
}
return true;
};
const config = useConfig<{ flowPath: string }>();
export const envisionPath = path.join(os.homedir(), '.config', 'envision');
const configPath = path.join(os.homedir(), '.config', 'envision', 'db.sqlite');
if (!checkFileExistsSync(envisionPath)) {
fs.mkdirSync(envisionPath, { recursive: true });
}
let flowPath = config.flowPath || configPath;
if (!path.isAbsolute(flowPath)) {
flowPath = path.join(process.cwd(), flowPath);
}
if (!flowPath.endsWith('.sqlite')) {
flowPath = path.join(flowPath, 'db.sqlite');
}
// connect to db
export const sequelize = new Sequelize({
dialect: 'sqlite',
storage: flowPath,
// logging: false,
});

View File

@ -1,26 +0,0 @@
import { Route } from '@kevisual/router';
import { app } from './app.ts';
import { getPackage, installPackage } from '../lib/npm.ts';
const install = new Route('admin', 'install');
install.run = async (ctx) => {
const { packageName } = ctx.query;
const data = await installPackage(packageName);
ctx.body = data;
return ctx;
};
install.validator = {
packageName: {
type: 'string',
required: true,
},
};
install.addTo(app);
const getNpm = new Route('admin', 'getNpm');
getNpm.run = async (ctx) => {
const data = await getPackage();
ctx.body = data['dependencies'];
return ctx;
};
getNpm.addTo(app);

View File

@ -1,201 +0,0 @@
// admin router manger
import { CustomError, Route } from '@kevisual/router';
import { app, runAppRouterFn } from './app.ts';
import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts';
import { loadOne } from './dashboard/load.ts';
import { RouterCodeModel } from './models/code.ts';
import { nanoid } from 'nanoid';
import { convertTsToJs as transform } from '../lib/ts2js.ts';
app
.route({
path: 'admin',
key: 'getRouterList',
})
.define(async (ctx) => {
// TODO: routerList 可以不暴露
ctx.body = ctx.queryRouter.getList().filter((r) => !r.path.startsWith('admin'));
// ctx.body = router.getList().filter((r) => r.path.startsWith('admin'));
return ctx;
})
.addTo(app);
// remove router
export const removeRouter = new Route('admin', 'removeRouter');
removeRouter.run = async (ctx) => {
const { path, key } = ctx.query;
runAppRouterFn('remove', { path, key });
const routerCode = await RouterCodeModel.findOne({ where: { path, key } });
if (routerCode) {
const id = routerCode.id;
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
}
ctx.body = 'success';
return ctx;
};
removeRouter.validator = {
path: {
type: 'string',
required: true,
},
key: {
type: 'string',
required: true,
},
};
removeRouter.addTo(app);
// remove router by id
export const removeRouterById = new Route('admin', 'removeRouterById');
removeRouterById.run = async (ctx) => {
const { id } = ctx.query;
app.router.removeById(id);
runAppRouterFn('removeById', id);
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
ctx.body = 'success';
return ctx;
};
removeRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
removeRouterById.addTo(app);
// stop router by id
export const stopRouterById = new Route('admin', 'stopRouterById');
stopRouterById.run = async (ctx) => {
const { id } = ctx.query;
runAppRouterFn('removeById', id);
const routerCode = await RouterCodeModel.findByPk(id);
if (routerCode) {
routerCode.active = false;
await routerCode.save();
}
stopCode(id);
ctx.body = 'success';
return ctx;
};
stopRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
stopRouterById.addTo(app);
// start router by id
export const startRouterById = new Route('admin', 'startRouterById');
startRouterById.run = async (ctx) => {
const { id } = ctx.query;
const routerCode = await RouterCodeModel.findByPk(id);
console.log('routerCode', id, routerCode.toJSON());
if (routerCode) {
routerCode.active = true;
await routerCode.save();
startCode(routerCode);
}
ctx.body = 'success';
return ctx;
};
startRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
startRouterById.addTo(app);
// add or update router
export const updateRouter = new Route('admin', 'updateRouter');
updateRouter.run = async (ctx) => {
let { path, key, id, code, middleware, type = 'route' } = ctx.query;
if (!path && !key) {
ctx.body = 'path and key is required';
ctx.code = 500;
return ctx;
}
let codeRouter: RouterCodeModel | null = null;
const codeRouteCheck = await RouterCodeModel.findOne({ where: { path, key } }); // 检查是否存在
if (codeRouteCheck && codeRouteCheck.id !== id) {
key = `${key}-${nanoid(6)}`;
}
if (id) {
codeRouter = await RouterCodeModel.findByPk(id);
codeRouter.path = path;
codeRouter.key = key;
codeRouter.code = code;
codeRouter.middleware = middleware;
try {
codeRouter.exec = await transform(code);
} catch (e) {
ctx.body = e.message.toString();
ctx.code = 500;
return ctx;
}
codeRouter.type = type;
await codeRouter.save();
} else {
try {
const exec = await transform(code);
const newCodeRouter = new RouterCodeModel({ path, key, code, exec, type, middleware });
await newCodeRouter.save();
codeRouter = newCodeRouter;
} catch (e) {
console.error('updateRouter', e);
throw new CustomError(e.message.toString());
}
}
const codeOne = await loadOne(codeRouter);
updateNewCode(codeOne);
ctx.body = 'success';
return ctx;
};
updateRouter.addTo(app);
app
.route({
path: 'admin',
key: 'getRouterApi',
description: 'get all router api list, and you can use this api to get router detail by path and key',
validator: {
origin: {
type: 'string',
required: false,
},
},
})
.define(async (ctx) => {
const { origin = 'http://localhost:4000' } = ctx.query;
// const routerList = router.getList();
// TODO: routerList 可以不暴露
const routerList = ctx.queryRouter.getList();
const apiList = routerList.map((item: any) => {
return {
path: item.path,
key: item.key,
query: `${origin}/api/router?path=${item.path}&key=${item.key}`,
description: item.description,
validator: item.validator,
};
});
const apiKeyObject = apiList.reduce((pre: any, cur: any) => {
pre[cur.key] = {
path: cur.path,
key: cur.key,
description: cur.description || '',
validator: cur.validator || {},
};
return pre;
}, {});
ctx.body = {
list: apiList,
keyObject: apiKeyObject,
};
return ctx;
})
.addTo(app);

View File

@ -1 +0,0 @@
export * from './ts2js.ts';

View File

@ -1,32 +0,0 @@
import * as babel from '@babel/core';
import stripAnsi from 'strip-ansi';
/**
* ts js
* @param tsCode
* @returns
*/
export const convertTsToJs = async (tsCode: string) => {
const presetEnv = await import('@babel/preset-env');
const presetTypescript = await import('@babel/preset-typescript');
try {
const result = babel.transformSync(tsCode, {
presets: [
presetTypescript.default,
[
presetEnv.default,
{
targets: {
node: 20,
},
},
],
],
filename: 'temp.ts',
});
return result.code;
} catch (e) {
const message = e.message.split('temp.ts:')[1] || e.message;
throw new Error(stripAnsi(message));
}
};

View File

@ -1,94 +0,0 @@
import { sequelize } from '@/modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
export class AiAgent extends Model {
declare id: string;
declare type: string;
declare model: string;
declare baseUrl: string;
declare apiKey: string;
declare temperature: number;
declare cache: string;
declare cacheName: string;
declare status: string;
declare data: any;
declare description: string;
declare key: string;
}
// 获取AIAgent的属性
export type AiProperties = {
id: string;
type: string;
model: string;
baseUrl: string;
apiKey?: string;
temperature?: number;
cache?: string;
cacheName?: string;
data?: any;
description?: string;
};
AiAgent.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
type: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
status: {
type: DataTypes.STRING,
defaultValue: 'open',
},
model: {
type: DataTypes.STRING,
allowNull: false,
},
baseUrl: {
type: DataTypes.STRING,
allowNull: false,
},
apiKey: {
type: DataTypes.STRING,
allowNull: false,
},
key: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
temperature: {
type: DataTypes.FLOAT,
allowNull: true,
},
cache: {
type: DataTypes.STRING,
allowNull: true,
},
cacheName: {
type: DataTypes.STRING,
allowNull: true,
},
data: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: {},
},
},
{
sequelize,
tableName: 'ai_agent',
paranoid: true,
},
);
AiAgent.sync({ alter: true, logging: false }).catch((e) => {
console.error('AiAgent sync error', e);
});

View File

@ -1,66 +0,0 @@
import { chat } from '@/modules/ollama.ts';
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
/**
* chat
*
*/
export class ChatHistory extends Model {
declare id: string;
declare data: string;
declare root: boolean;
declare show: boolean;
declare uid: string;
declare chatId: string;
declare chatPromptId: string;
declare role: string;
}
ChatHistory.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
data: {
type: DataTypes.JSON,
allowNull: true,
},
chatId: {
type: DataTypes.UUID, // 历史属于哪一条会话
allowNull: true,
},
chatPromptId: {
type: DataTypes.UUID, // 属于哪一个prompt
allowNull: true,
},
root: {
type: DataTypes.BOOLEAN, // 是否是根节点
defaultValue: false,
},
role: {
type: DataTypes.STRING, // 角色
allowNull: true,
defaultValue: 'user',
},
show: {
type: DataTypes.BOOLEAN, // 当创建返回的时候,配置是否显示
defaultValue: true,
},
uid: {
type: DataTypes.STRING,
allowNull: true,
},
},
{
sequelize, // 传入 Sequelize 实例
modelName: 'chat_history', // 模型名称
},
);
// force 只能run一次否则会删除表
ChatHistory.sync({ alter: true, logging: false }).catch((e) => {
console.error('History sync error', e);
});

View File

@ -1,64 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
import { Variable } from '@kevisual/ai-graph';
export type ChatPromptData = {
// 使用那个agent, 必须要有
aiAgentId: string;
// 使用那个初始化的prompt如果不存在则纯粹的白对话。
promptId?: string;
chainPromptId?: string;
};
/**
* chat绑定就的agent和prompt
*
*/
export class ChatPrompt extends Model {
declare id: string;
declare title: string;
declare description: string;
declare uid: string;
declare key: string;
declare data: ChatPromptData;
}
ChatPrompt.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
data: {
type: DataTypes.JSON,
allowNull: true,
},
key: {
type: DataTypes.STRING, // 页面属于 /container/edit/list
allowNull: false,
defaultValue: '',
},
uid: {
type: DataTypes.STRING,
allowNull: true,
},
},
{
sequelize, // 传入 Sequelize 实例
modelName: 'chat_prompt', // 模型名称
paranoid: true,
},
);
// force 只能run一次否则会删除表
ChatPrompt.sync({ alter: true, logging: false }).catch((e) => {
console.error('Prompt sync error', e);
});

View File

@ -1,61 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
/**
* chat
*
*/
export class ChatSession extends Model {
declare id: string;
declare data: string;
declare chatPromptId: string;
declare type: string;
declare key: string;
declare title: string;
declare uid: string;
}
ChatSession.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
data: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: {},
},
chatPromptId: {
type: DataTypes.UUID, // 属于哪一个prompt
allowNull: true,
},
type: {
type: DataTypes.STRING, // 属于测试的,还是正式的
defaultValue: 'production',
},
title: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: '',
},
key: {
type: DataTypes.STRING, // 页面属于 /container/edit/list
allowNull: true,
},
uid: {
type: DataTypes.STRING,
allowNull: true,
},
},
{
sequelize, // 传入 Sequelize 实例
modelName: 'chat_session', // 模型名称
},
);
// force 只能run一次否则会删除表
ChatSession.sync({ alter: true, logging: false }).catch((e) => {
console.error('Sessuib sync error', e);
});

View File

@ -1,121 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
export type RouterCode = {
id: string;
path: string;
key: string;
active: boolean;
project: string;
code: string;
exec: string;
type: RouterCodeType;
middleware: string[];
next: string;
data: any;
validator: any;
};
export enum RouterCodeType {
route = 'route',
middleware = 'middleware',
}
export class RouterCodeModel extends Model {
declare id: string;
declare path: string;
declare key: string;
declare active: boolean;
declare project: string;
declare code: string;
declare exec: string;
declare type: RouterCodeType;
declare middleware: string[];
declare next: string; // 如果是中间件,不存在
declare data: any; // 内容
declare validator: any;
}
RouterCodeModel.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
comment: 'code id',
},
path: {
type: DataTypes.STRING,
allowNull: false,
},
key: {
type: DataTypes.STRING,
allowNull: true,
},
active: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
project: {
type: DataTypes.STRING,
defaultValue: 'default',
},
code: {
type: DataTypes.TEXT,
defaultValue: '',
},
exec: {
type: DataTypes.TEXT, // 对代码进行编译后的代码
defaultValue: '',
},
type: {
type: DataTypes.ENUM(RouterCodeType.route, RouterCodeType.middleware),
defaultValue: RouterCodeType.route,
},
middleware: {
type: DataTypes.JSON,
defaultValue: [],
},
next: {
type: DataTypes.JSON,
defaultValue: {},
},
data: {
type: DataTypes.JSON,
defaultValue: {},
},
validator: {
type: DataTypes.JSON,
defaultValue: {},
},
},
{
sequelize,
tableName: 'cf_router_code', // container flow router code
paranoid: true,
},
);
// RouterCodeModel 检测不存在,不存在则创建
RouterCodeModel.sync({ alter: true, logging: false })
.then((res) => {
console.log('RouterCodeModel sync', res);
})
.catch((e) => {
console.error('RouterCodeModel sync', e.message);
if (!TableIsExist()) {
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
}
});
export const TableIsExist = async () => {
// 判断cf_router_code表是否存在
const tableIsExist = await sequelize.getQueryInterface().showAllTables({
logging: false,
});
return tableIsExist.includes('cf_router_code');
};

View File

@ -1,83 +0,0 @@
import { neode } from '@/modules/neo4j.ts';
import { getSession } from '@/modules/neo4j.ts';
import Neode from 'neode';
export const PromptNeo = neode.model('Prompt', {
id: {
type: 'uuid',
primary: true,
},
title: {
type: 'string',
},
description: 'string',
// profile: { type: 'object', optional: true }, // 用于存储 JSON 对象
prompt: 'string',
// inputVariables: { type: 'array', item },
// tags: { type: 'array', items: 'string', optional: true } // 定义字符串数组
inputVariables: { type: 'string', default: JSON.stringify([]) },
localVariables: { type: 'string', default: JSON.stringify([]) },
// 定义可单向或双向的关系
relatedPrompts: {
type: 'relationship',
relationship: 'RELATED_TO',
target: 'Prompt', // 指向自身
direction: 'out', // 默认是单向的
properties: {
created_at: 'datetime',
bidirectional: 'boolean', // 用来标记该关系是否为双向
},
eager: true, // 自动加载相关的 Prompts
},
});
export async function createRelationship(promptA: Neode.Node<unknown>, promptB: Neode.Node<unknown>, isBidirectional = false) {
// 创建单向关系
await promptA.relateTo(promptB, 'RELATED_TO', { created_at: new Date(), bidirectional: isBidirectional });
// 如果是双向关系,创建反向关系
if (isBidirectional) {
await promptB.relateTo(promptA, 'RELATED_TO', { created_at: new Date(), bidirectional: true });
}
}
export async function createRelationship2(promptId1, promptId2, isBidirectional = false) {
const query = `
MATCH (p1:Prompt {id: $id1}), (p2:Prompt {id: $id2})
CREATE (p1)-[r:RELATED_TO {created_at: $createdAt, bidirectional: $bidirectional}]->(p2)
RETURN r
`;
const result = await getSession().run(query, {
id1: promptId1,
id2: promptId2,
createdAt: new Date().toISOString(),
bidirectional: isBidirectional,
});
return result.records[0].get('r');
}
export async function createPrompt(promptData) {
const session = getSession();
const query = `
CREATE (p:Prompt {
id: $id,
title: $title,
description: $description,
prompt: $prompt,
inputVariables: $inputVariables,
localVariables: $localVariables
})
RETURN p
`;
const result = await session.run(query, {
id: promptData.id,
title: promptData.title,
description: promptData.description,
prompt: promptData.prompt,
inputVariables: JSON.stringify(promptData.inputVariables || []),
localVariables: JSON.stringify(promptData.localVariables || []),
});
return result.records[0].get('p');
}

View File

@ -1,66 +0,0 @@
import { sequelize } from '../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
import { Variable } from '@kevisual/ai-graph';
/**
*
*/
export type PresetData = {
// 参数
validator: {
[key: string]: any; // 请求的内容的验证器
};
data: {
prompt?: string; // 提前预设值
inputs: Variable & { operate?: string }[]; // 请求内容的变量和内容
};
};
export class Prompt extends Model {
declare id: string;
declare title: string;
declare description: string;
declare presetData: PresetData;
}
Prompt.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
presetData: {
type: DataTypes.JSON,
},
key: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
// inputVariables: {
// type: DataTypes.JSON,
// defaultValue: [],
// },
// localVariables: {
// type: DataTypes.JSON,
// defaultValue: [],
// },
},
{
sequelize, // 传入 Sequelize 实例
modelName: 'prompt', // 模型名称
paranoid: true,
},
);
Prompt.sync({ alter: true, force: false, logging: false }).catch((e) => {
console.error('Prompt sync error', e);
});

View File

@ -1,12 +0,0 @@
import { Queue } from 'bullmq';
import { useConfig } from '@kevisual/use-config';
const config = useConfig();
export const connection = {
host: config.redis?.host || 'localhost',
port: config.redis?.port || 6379,
};
export const quene = new Queue('test', {
connection: connection,
});

View File

@ -1,38 +0,0 @@
import Neode from 'neode';
import { useConfig } from '@kevisual/use-config';
import neo4j from 'neo4j-driver';
type NeodeConfig = {
uri: string;
username: string;
password: string;
};
const { neo4j: neo4jConfig } = useConfig<{ neo4j: NeodeConfig }>('neo4j');
const { uri, username, password } = neo4jConfig;
// 设置连接配置
// const neode = new Neode('bolt://localhost:7687', 'neo4j', 'your_password');
export const neode = new Neode(uri, username, password);
// 创建与 Neo4j 数据库的连接
export const neoDriver = neo4j.driver(
uri, // 数据库地址
neo4j.auth.basic(username, password), // 用户名和密码
);
export const getSession = () => {
return neoDriver.session();
};
const testConnect = async () => {
// 连接成功
// 尝试执行简单的 Cypher 查询以测试连接
neode
.cypher('RETURN 1', {})
.then(() => {
console.log('connect neo4j success');
})
.catch((err) => {
console.error('Failed to connect:', err);
});
};
testConnect();

View File

@ -1,30 +0,0 @@
import { useConfig } from '@kevisual/use-config';
import { Ollama, Message, ChatRequest } from 'ollama';
const config = useConfig<{ ollama: Ollama['config'] & { model: string } }>();
const { host, model } = config.ollama;
export const ollama = new Ollama({ host });
export type ChatMessage = {
content: string;
} & Message;
type ChatOpts = {
model?: string;
messages?: ChatMessage[];
options?: ChatRequest['options'];
} & ChatRequest;
export const chat = (messages: ChatMessage[], chatOpts?: ChatOpts) => {
const { options, stream, ...rest } = chatOpts || {};
return ollama.chat({
messages,
model: model,
options: {
temperature: 0,
...chatOpts?.options,
},
...rest,
});
};

View File

@ -1 +0,0 @@
import './list.ts';

View File

@ -1,137 +0,0 @@
import { app } from '@/app.ts';
import { AiAgent, AiProperties } from '@/models/agent.ts';
import { CustomError } from '@kevisual/router';
// import { agentManger } from '@kevisual/ai-lang';
import { v4 } from 'uuid';
app
.route({
path: 'agent',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
const agents = await AiAgent.findAll({
order: [['updatedAt', 'DESC']],
// 返回的内容不包含apiKey的字段
attributes: { exclude: ['apiKey'] },
});
ctx.body = agents;
})
.addTo(app);
app
.route('agent', 'get')
.define(async (ctx) => {
const id = ctx.query.id;
if (!id) {
throw new CustomError('id is required');
}
ctx.body = await AiAgent.findByPk(id, {
attributes: { exclude: ['apiKey'] },
});
return ctx;
})
.addTo(app);
app
.route('agent', 'update')
.define(async (ctx) => {
const { id, ...rest } = ctx.query.data;
let agent = await AiAgent.findByPk(id);
if (!agent) {
agent = await AiAgent.create(rest);
ctx.body = agent;
return ctx;
}
await agent.update(rest);
ctx.body = agent;
return ctx;
})
.addTo(app);
app
.route('agent', 'delete')
.define(async (ctx) => {
const id = ctx.query.id;
if (!id) {
throw new CustomError('id is required');
}
const agent = await AiAgent.findByPk(id);
if (!agent) {
throw new CustomError('agent not found');
}
await agent.destroy();
ctx.body = agent;
return ctx;
})
.addTo(app);
// app
// .route('agent', 'test')
// .define(async (ctx) => {
// const { message } = ctx.query;
// const data: AiProperties = {
// type: 'ollama',
// id: 'test',
// model: 'qwen2.5:14b',
// baseUrl: 'http://mz.zxj.im:11434',
// cache: 'memory',
// };
// const agent = agentManger.createAgent(data as any);
// const res = await agent.sendHumanMessage(message);
// // agent.close();
// agentManger.removeAgent(agent.id);
// ctx.body = res;
// return ctx;
// })
// .addTo(app);
export const agentModelList = ['qwen2.5:14b', 'qwen2.5-coder:7b', 'llama3.1:8b', 'bakllava:latest'] as const;
export const openAiModels = ['gpt-4o'];
const demoData: AiProperties[] = [
{
id: v4(),
type: 'openai',
model: 'gpt-4o',
baseUrl: 'https://oneapi.on-ai.ai/v1',
apiKey: 'sk-GJE6I8OJWDr2ErFBD4C4706a65Ad4cD9B596Cf7c76943e45',
},
...agentModelList.map((item) => {
return {
id: v4(),
type: 'ollama',
model: item,
baseUrl: 'http://mz.zxj.im:11434',
apiKey: 'sk-GJE6I8OJWDr2ErFBD4C4706a65Ad4cD9B596Cf7c76943e45',
};
}),
];
// AiAgent.bulkCreate(demoData, { ignoreDuplicates: true }).then(() => {
// console.log('create demo data success');
// });
const initManager = async () => {
// const list = await AiAgent.findAll();
const list = await AiAgent.findAll({
where: {
status: 'open',
},
logging: false,
});
const data = list.map((item) => {
return {
id: item.id,
type: item.type as any,
model: item.model as any,
baseUrl: item.baseUrl,
apiKey: item.apiKey,
temperature: item.temperature,
cache: item.cache as any,
cacheName: item.cacheName,
};
});
// agentManger.createAgentList(data);
};
// setTimeout(() => {
// initManager();
// }, 1000);

View File

@ -1,201 +0,0 @@
import { app } from '@/app.ts';
import { AiAgent } from '@/models/agent.ts';
import { ChatPrompt } from '@/models/chat-prompt.ts';
import { ChatSession } from '@/models/chat-session.ts';
import { Prompt } from '@/models/prompt.ts';
import { agentManger } from '@kevisual/ai-lang';
import { PromptTemplate } from '@kevisual/ai-graph';
import { v4 } from 'uuid';
import { ChatHistory } from '@/models/chat-history.ts';
import { User } from '@/models/user.ts';
const clients = [];
export const compotedToken = () => {
// 计算token消耗
};
export const getConfigByKey = async (key) => {
const chatPrompt = await ChatPrompt.findOne({ where: { key } });
const { promptId, aiAgentId } = chatPrompt.data;
const prompt = await Prompt.findByPk(promptId);
let aiAgent = agentManger.getAgent(aiAgentId);
if (!aiAgent) {
// throw new Error('aiAgent not found');
const aiAgnetModel = await AiAgent.findByPk(aiAgentId);
aiAgent = agentManger.createAgent({
id: aiAgnetModel.id,
type: aiAgnetModel.type as any,
model: aiAgnetModel.model as any,
baseUrl: aiAgnetModel.baseUrl,
apiKey: aiAgnetModel.apiKey,
temperature: aiAgnetModel.temperature,
cache: aiAgnetModel.cache as any,
cacheName: aiAgnetModel.cacheName,
});
}
return { chatPrompt, prompt, aiAgent };
};
export const getTemplate = async ({ data, inputs }) => {
const promptTemplate = new PromptTemplate({
prompt: data.prompt,
inputVariables: inputs.map((item) => {
return {
key: item.key,
value: item.value,
};
}),
localVariables: [],
}); // 传入参数
return await promptTemplate.getTemplate();
};
const onMessage = async ({ data, end, ws }) => {
// messages的 data
const client = clients.find((client) => client.ws === ws);
if (!client) {
end({ code: 404, data: {}, message: 'client not found' });
return;
}
const { uid, id, key } = client.data;
const {
inputs,
message: sendMessage,
data: {},
} = data;
let root = data.root || false;
let chatSession = await ChatSession.findByPk(id);
const config = await getConfigByKey(key);
const { prompt, aiAgent, chatPrompt } = config;
let userQuestion = sendMessage;
if (!chatSession) {
chatSession = await ChatSession.create({ key, id, data: data, uid, chatPromptId: chatPrompt.id });
root = true;
} else {
// 更新session context的值
const newData = JSON.parse(data);
if (newData !== '{}' && JSON.stringify(chatSession.data) !== JSON.stringify(data)) {
await chatSession.update({ data: data });
}
if (root) {
const chatHistory = await ChatHistory.findAll({ where: { chatId: id }, logging: false });
chatHistory.forEach((item) => {
end({ code: 200, data: item, message: 'success', type: 'messages' });
});
// return;
}
root = false;
}
if (!userQuestion) {
if (!prompt?.presetData) {
end({ code: 404, data: {}, message: 'prompt not set, need presetData' });
return;
}
const template = await getTemplate({ data: prompt.presetData.data, inputs });
if (!template) {
end({ code: 404, data: {}, message: 'template not found' });
return;
}
userQuestion = template;
}
// 保存到数据库
const roleUser = await ChatHistory.create({
data: {
message: userQuestion,
},
chatId: id,
chatPromptId: chatPrompt.id,
root: root,
uid: uid,
show: true,
role: 'user',
});
end({ code: 200, data: roleUser, message: 'success', type: 'messages' });
const result = await aiAgent.sendHumanMessage(userQuestion, { thread_id: id });
const lastMessage = result.messages[result.messages.length - 1];
const message = result.messages[result.messages.length - 1].content;
// 根据key找到对应的prompt
// 保存到数据库
const roleAi = await ChatHistory.create({
data: {
message,
result: lastMessage,
},
chatId: id,
chatPromptId: chatPrompt.id,
root: false,
uid: uid,
show: true,
role: 'ai',
});
end({ code: 200, data: roleAi, message: 'success', type: 'messages' });
};
const getHistory = async (id: string, { data, end, ws }) => {
const chatHistory = await ChatHistory.findAll({ where: { chatId: id }, logging: false });
chatHistory.forEach((item) => {
end({ code: 200, data: item, message: 'success', type: 'messages' });
});
};
app.io.addListener('chat', async ({ data, end, ws }) => {
const { type } = data || {};
if (type === 'subscribe') {
const token = data?.token;
if (!token) {
end({ code: 401, data: {}, message: 'need token' });
return;
}
let tokenUesr;
try {
tokenUesr = await User.verifyToken(token);
} catch (e) {
end({ code: 401, data: {}, message: 'token is invaild' });
return;
}
const uid = tokenUesr.id;
const id = v4();
const clientData = { ...data?.data, uid };
if (!clientData.id) {
clientData.id = id;
}
const client = clients.find((client) => client.ws === ws);
if (!client) {
clients.push({ ws, data: clientData }); // 拆包里面包含的type信息去掉
}
end({ code: 200, data: clientData, message: 'subscribe success' });
} else if (type === 'unsubscribe') {
// 需要手动取消订阅
const index = clients.findIndex((client) => client.ws === ws);
if (index > -1) {
const data = clients[index]?.data;
clients.splice(index, 1);
end({ code: 200, data, message: 'unsubscribe success' });
return;
}
end({ code: 200, data: {}, message: 'unsubscribe success' });
return;
} else if (type === 'messages') {
try {
await onMessage({ data: data.data, end, ws });
} catch (e) {
console.error('onMessage error', e);
end({ code: 500, data: {}, message: 'onMessage error' });
}
return;
} else if (type === 'changeSession') {
// 修改client的session的id
const client = clients.find((client) => client.ws === ws);
if (!client) {
end({ code: 404, data: {}, message: 'client not found' });
return;
}
const { id } = data?.data;
client.data.id = id || v4();
// 返回修改后的history的内容
end({ code: 200, data: client.data, message: 'changeSession success' });
getHistory(id, { data, end, ws });
return;
} else {
end({ code: 404, data: {}, message: 'subscribe fail' });
return;
}
ws.on('close', () => {
const index = clients.findIndex((client) => client.ws === ws);
if (index > -1) clients.splice(index, 1);
});
});

View File

@ -1,3 +0,0 @@
import './list.ts'
import './session-list.ts'
import './chat-io.ts'

View File

@ -1,34 +0,0 @@
import { app } from '@/app.ts';
import { ChatHistory } from '@/models/chat-history.ts';
import { CustomError } from '@kevisual/router';
// Admin only
app
.route({
path: 'chat-history',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
const chatPrompt = await ChatHistory.findAll({
order: [['updatedAt', 'DESC']],
});
ctx.body = chatPrompt;
})
.addTo(app);
app
.route({
path: 'chat-history',
key: 'delete',
})
.define(async (ctx) => {
const { id } = ctx.query;
const chatHistory = await ChatHistory.findByPk(id);
if (!chatHistory) {
throw new CustomError('ChatHistory not found');
}
await chatHistory.destroy();
ctx.body = chatHistory;
})
.addTo(app);

View File

@ -1,84 +0,0 @@
import { app } from '@/app.ts';
import { ChatSession } from '@/models/chat-session.ts';
import { ChatPrompt } from '@/models/chat-prompt.ts';
import { CustomError } from '@kevisual/router';
app
.route({
path: 'chat-session',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
const chatSession = await ChatSession.findAll({
order: [['updatedAt', 'DESC']],
});
ctx.body = chatSession;
})
.addTo(app);
// Admin only
app
.route({
path: 'chat-session',
key: 'list-history',
})
.define(async (ctx) => {
const data = ctx.query.data;
const chatPrompt = await ChatPrompt.findOne({
where: {
key: data.key,
},
});
if (!chatPrompt) {
throw new CustomError('ChatPrompt not found');
}
console.log('chatPrompt', chatPrompt.id);
const chatSession = await ChatSession.findAll({
order: [['updatedAt', 'DESC']],
where: {
chatPromptId: chatPrompt.id,
},
limit: data.limit || 10,
});
ctx.body = chatSession;
})
.addTo(app);
app
.route({
path: 'chat-session',
key: 'update',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const uid = tokenUser.id;
const { id, ...data } = ctx.query.data;
if (id) {
const session = await ChatSession.findByPk(id);
if (session) {
await session.update(data);
} else {
throw new CustomError('Session not found');
}
ctx.body = session;
return;
}
const session = await ChatSession.create({ ...data, uid });
ctx.body = session;
})
.addTo(app);
app
.route({
path: 'chat-session',
key: 'delete',
})
.define(async (ctx) => {
const { id } = ctx.query;
const session = await ChatSession.findByPk(id);
if (!session) {
throw new CustomError('Session not found');
}
await session.destroy();
ctx.body = session;
})
.addTo(app);

View File

@ -1 +0,0 @@
import './list.ts';

View File

@ -1,131 +0,0 @@
import { app } from '@/app.ts';
import { AiAgent } from '@/models/agent.ts';
import { ChatPrompt } from '@/models/chat-prompt.ts';
import { Prompt } from '@/models/prompt.ts';
import { CustomError } from '@kevisual/router';
// Admin only
app
.route({
path: 'chat-prompt',
key: 'list',
// middleware: ['auth'],
})
.define(async (ctx) => {
const chatPrompt = await ChatPrompt.findAll({
order: [['updatedAt', 'DESC']],
// 列出被删除的
// paranoid: false,
});
ctx.body = chatPrompt;
})
.addTo(app);
app
.route({
path: 'chat-prompt',
key: 'get',
validator: {
id: {
type: 'string',
required: true,
},
},
})
.define(async (ctx) => {
const { id } = ctx.query;
const chatPrompt = await ChatPrompt.findByPk(id);
if (!chatPrompt) {
throw new CustomError('ChatPrompt not found');
}
ctx.body = chatPrompt;
})
.addTo(app);
app
.route({
path: 'chat-prompt',
key: 'update',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const uid = tokenUser.id;
const { data } = ctx.query;
const { id, ...rest } = data;
if (id) {
const page = await ChatPrompt.findByPk(id);
if (page) {
if (rest.data) {
rest.data = { ...page.data, ...rest.data };
}
const newPage = await page.update(rest);
ctx.body = newPage;
} else {
throw new CustomError('page not found');
}
} else if (data) {
const page = await ChatPrompt.create({ ...rest, uid });
ctx.body = page;
}
})
.addTo(app);
app
.route({
path: 'chat-prompt',
key: 'delete',
validator: {
id: {
type: 'string',
required: true,
},
},
middleware: ['auth'],
})
.define(async (ctx) => {
const id = ctx.query.id;
const chatPrompt = await ChatPrompt.findByPk(id);
if (!chatPrompt) {
throw new CustomError('chatPrompt not found');
}
await chatPrompt.destroy();
ctx.body = 'success';
})
.addTo(app);
app
.route({
path: 'chat-prompt',
key: 'getByKey',
middleware: ['auth'],
})
.define(async (ctx) => {
const { key } = ctx.query.data || {};
if (!key) {
throw new CustomError('key is required');
}
const chatPrompt = await ChatPrompt.findOne({
where: { key },
});
if (!chatPrompt) {
throw new CustomError('chatPrompt not found');
}
const { promptId, aiAgentId } = chatPrompt.data;
if (!aiAgentId) {
throw new CustomError('promptId is required');
}
const aiAgent = await AiAgent.findByPk(aiAgentId, {
// 只获取 id 和description 字段
attributes: ['id', 'description', 'key'],
});
if (!aiAgent) {
throw new CustomError('aiAgent not found');
}
const prompt = await Prompt.findByPk(promptId);
ctx.body = {
chatPrompt: chatPrompt,
aiAgent,
prompt,
};
})
.addTo(app);

View File

@ -4,16 +4,8 @@ import './page/index.ts';
import './resource/index.ts';
import './prompt-graph/index.ts';
import './agent/index.ts';
import './user/index.ts';
import './chat-prompt/index.ts';
import './chat-history/index.ts';
import './github/index.ts';
import './app-manager/index.ts';

View File

@ -1,75 +0,0 @@
import { app } from '@/app.ts';
import { Prompt } from '@/models/prompt.ts';
import { chat } from '@/modules/ollama.ts';
import { CustomError } from '@kevisual/router';
import { PromptTemplate } from '@kevisual/ai-graph';
import { v4 } from 'uuid';
app
.route('ai', 'run', { nextRoute: { id: 'runOllama' } })
.define({
validator: {
data: {
type: 'object',
properties: {
key: {
type: 'string',
required: true,
message: 'Prompt key is required',
},
},
},
},
})
.define(async (ctx) => {
// ctx.currentRoute?.verify(ctx, true);
const { key, inputs = [] } = ctx.query.data || {};
if (!key) {
throw new CustomError('Prompt key is required');
}
const prompt = await Prompt.findOne({ where: { key } });
console.log('prompt', 'key', key, prompt);
if (!prompt) {
throw new CustomError('Prompt not found');
}
const { presetData } = prompt;
const { data, validator } = presetData || {};
// const { inputs = [] } = data;
// TODO: 获取validator和inputs的内容
const promptTemplate = new PromptTemplate({
prompt: data.prompt,
inputVariables: inputs.map((item) => {
return {
key: item.key,
value: item.value,
};
}),
localVariables: [],
});
const result = await promptTemplate.getTemplate();
ctx.state = {
prompt: result,
};
ctx.body = result;
})
.addTo(app);
app
.route('ai', 'runOllama', {
id: 'runOllama',
})
.define(async (ctx) => {
const prompt = ctx.state.prompt;
const uuid = v4();
if (!prompt) {
throw new CustomError('Prompt Template not found');
}
const res = await chat([
{
role: 'user',
content: prompt,
},
]);
ctx.body = { id: uuid, ...res };
})
.addTo(app);

View File

@ -1,73 +0,0 @@
import { getSession } from '@/modules/neo4j.ts';
export async function fetchData() {
const session = getSession();
try {
const query = `MATCH (n)
OPTIONAL MATCH (n)-[r]->(m)
RETURN n, r, m`;
const queryConnect = 'MATCH (n)-[r]->(m) RETURN n, r, m LIMIT 25';
const result = await session.run(query);
const graphData = { nodes: [], links: [] };
const nodeMap = new Map();
// n和n的关系用 relatedPrompts 进行关联
result.records.forEach((record) => {
const node = record.get('n');
const relation = record.get('r');
const target = record.get('m');
if (!nodeMap.has(node.identity)) {
nodeMap.set(node.identity, {
id: node.identity.toString(),
label: node.labels[0],
properties: node.properties,
});
graphData.nodes.push(nodeMap.get(node.identity));
}
if (relation && !nodeMap.has(relation.identity)) {
nodeMap.set(relation.identity, {
id: relation.identity.toString(),
label: relation.type,
properties: relation.properties,
});
graphData.nodes.push(nodeMap.get(relation.identity));
}
if (target && !nodeMap.has(target.identity)) {
nodeMap.set(target.identity, {
id: target.identity.toString(),
label: target.labels[0],
properties: target.properties,
});
graphData.nodes.push(nodeMap.get(target.identity));
}
if (relation) {
graphData.links.push({
source: node.identity.toString(),
target: relation.identity.toString(),
type: relation.type,
properties: relation.properties,
});
}
if (target) {
graphData.links.push({
source: node.identity.toString(),
target: target.identity.toString(),
type: 'RELATED_TO',
properties: {},
});
}
});
return graphData;
} finally {
await session.close();
}
}
// fetchData().then((graphData) => {
// console.log(graphData); // 用于验证获取的数据
// drawGraph(graphData); // 调用 D3 绘制函数
// });

View File

@ -1,3 +0,0 @@
import './list-graph.ts';
import './list.ts';
import './ai.ts';

View File

@ -1,97 +0,0 @@
import { PromptNeo, createRelationship, createRelationship2 } from '@/models/prompt-graph.ts';
import { app } from '@/app.ts';
import { v4 } from 'uuid';
import { fetchData } from './d3/get-graph.ts';
app
.route('prompt-graph', 'list')
.define(async (ctx) => {
const prompts = await PromptNeo.all();
const json = await prompts.toJson();
// console.log('json', json);
ctx.body = json;
})
.addTo(app);
app
.route('prompt-graph', 'update')
.define(async (ctx) => {
const { id, title, description, prompt, inputVariables, localVariables } = ctx.query;
const promptNode = await PromptNeo.first('id', id);
if (!promptNode) {
const promptData = {
id: v4(),
title,
description,
prompt,
inputVariables: JSON.stringify(inputVariables),
localVariables: JSON.stringify(localVariables),
};
const _prompt = await PromptNeo.create(promptData);
ctx.body = await _prompt.toJson();
return;
}
await promptNode.update({ title, description, prompt, inputVariables, localVariables });
ctx.body = await promptNode.toJson();
})
.addTo(app);
app
.route('prompt-graph', 'delete')
.define(async (ctx) => {
const { id, title } = ctx.query;
const promptNode = await PromptNeo.first('id', id);
if (!promptNode) {
ctx.body = 'prompt not found';
return;
}
await promptNode.delete();
ctx.body = 'delete success';
})
.addTo(app);
app
.route('prompt-graph', 'deleteAll')
.define(async (ctx) => {
const prompts = await PromptNeo.all();
for (const prompt of prompts) {
await prompt.delete();
}
ctx.body = 'delete all success';
})
.addTo(app);
app
.route('prompt-graph', 'createDemo')
.define(async (ctx) => {
const promptData = {
id: v4(),
title: 'test-' + v4(),
description: '这是测试保存prompt的数据',
prompt: '这是测试保存prompt的数据',
inputVariables: JSON.stringify([{ key: 'test', value: 'test' }]),
localVariables: JSON.stringify([{ key: 'test', value: 'test' }]),
};
const f = await PromptNeo.first('id', 'f5288cdb-bfca-4a65-b629-cae590ede719');
if (!f) {
ctx.body = 'not found f';
return;
}
const prompt = await PromptNeo.create({ ...promptData });
// await prompt.relateTo(f, 'RELATED_TO', { createdAt: new Date().toISOString() });
// f.relateTo(prompt, 'RELATED_TO', { createdAt: new Date().toISOString() });
// await createRelationship(f, prompt);
const fj = await f.toJson() as any;
const pj = await prompt.toJson() as any;
await createRelationship2(fj.id, pj.id);
ctx.body = await prompt.toJson();
})
.addTo(app);
app
.route('prompt-graph', 'getD3')
.define(async (ctx) => {
const value = await fetchData();
ctx.body = value;
})
.addTo(app);

View File

@ -1,63 +0,0 @@
import { Prompt } from '@/models/prompt.ts';
import { app } from '@/app.ts';
import { CustomError } from '@kevisual/router';
app
.route('prompt', 'list')
.define(async (ctx) => {
const prompts = await Prompt.findAll({
order: [['updatedAt', 'DESC']],
});
ctx.body = prompts;
})
.addTo(app);
app
.route('prompt', 'update')
.define(async (ctx) => {
const { id, title, description, presetData, key } = ctx.query.data || {};
if (!key) {
throw new CustomError('Prompt key is required');
}
const isEdit = !!id;
const promptKey = await Prompt.findOne({ where: { key } });
if (promptKey && promptKey.id !== id) {
throw new CustomError(`Prompt key is already exist, use by ${promptKey.id}`);
}
if (!isEdit) {
const prompt = new Prompt({
title,
key,
description,
presetData,
});
await prompt.save();
ctx.body = prompt;
return;
}
const prompt = await Prompt.findByPk(id);
if (!prompt) {
throw new CustomError('Prompt not found');
}
await prompt.update({ title, description, presetData, key });
ctx.body = prompt;
})
.addTo(app);
app
.route('prompt', 'delete')
.define(async (ctx) => {
const { id } = ctx.query || {};
if (!id) {
throw new CustomError('Prompt id is required');
}
const prompt = await Prompt.findByPk(id);
if (!prompt) {
throw new CustomError('Prompt not found');
}
await prompt.destroy();
ctx.body = 'delete success';
})
.addTo(app);

View File

@ -1 +0,0 @@
import './list.ts'

View File

@ -1,13 +0,0 @@
import { Snippet } from '@/routes/snippet/snippet.ts';
import { app } from '@/app.ts';
app
.route({
path: 'snippet',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
// 获取所有的snippet
})
.addTo(app);

View File

@ -1,54 +0,0 @@
import { sequelize } from '@/modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize';
export class Snippet extends Model {
declare id: string;
declare title: string;
declare description: string;
declare snippet: string;
declare keyword: string;
declare user_id: string;
declare data: any;
}
Snippet.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.TEXT,
allowNull: true,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
snippet: {
type: DataTypes.TEXT,
allowNull: true,
},
keyword: {
type: DataTypes.STRING,
},
user_id: {
type: DataTypes.UUID,
},
data: {
type: DataTypes.JSONB,
allowNull: true,
defaultValue: {},
},
},
{
sequelize,
tableName: 'snippet',
paranoid: true,
},
);
// 当
// Snippet.sync({ alter: true, logging: false }).catch((e) => {
// console.error('Snippet sync error', e);
// });

View File

@ -1,35 +0,0 @@
import { AiAgent } from '@/models/agent.ts';
import { RouterCodeModel } from '@/models/code.ts';
import { Prompt } from '@/models/prompt.ts';
import { User } from '@/models/user.ts';
import { ContainerModel } from '@/routes/container/models/index.ts';
import { PageModel } from '@/routes/page/models/index.ts';
import { ResourceModel } from '@/routes/resource/models/index.ts';
// declare uid: string;
// uid: {
// type: DataTypes.UUID,
// allowNull: true,
// },
// 系统表
export const stystemTables = [AiAgent, RouterCodeModel, Prompt];
export const userTables = [ContainerModel, PageModel, ResourceModel];
const rootUid = '14206305-8b5c-44cc-b177-766cfe2e452f';
const updateUser = async () => {
const updateTables = [...userTables] as any[];
for (let Table of updateTables) {
// const res = await ContainerModel.update({ uid: rootUid }, { where: { uid: null } });
try {
const list = await Table.update({ uid: rootUid }, { where: { uid: null } });
console.log('update--', list.length);
} catch (e) {
console.log(e);
}
}
};
// updateUser();

View File

@ -1,47 +0,0 @@
import { ContainerModel } from '@/routes/container/models/index.ts';
import { ChatPrompt } from '@/models/chat-prompt.ts';
const recoverData = async () => {
const data = {
id: '868970a4-8cab-4141-a73c-cc185fd17508',
title: '测试es6每次导入的变量运行一次+1并打印',
description: '',
tags: [],
type: '',
code: "let a = 1\n\nexport const main = () => {\n console.log('current a', a);\n return a++\n}",
source: '',
sourceType: '',
data: {
className: '',
style: {},
showChild: true,
shadowRoot: false,
},
publish: {},
uid: '14206305-8b5c-44cc-b177-766cfe2e452f',
createdAt: '2024-09-19T13:27:58.796Z',
updatedAt: '2024-09-28T05:27:05.381Z',
};
const r = await ContainerModel.create(data);
};
// recoverData();
const revoverId = async () => {
const id = 'e235576e-eb48-4b5c-8385-9b8ada4a137f';
// const cp = await ChatPrompt.findByPk(id);
const cp = await ChatPrompt.findAll({
paranoid: false,
});
console.log(
cp.map((item) => {
return {
id: item.id,
// @ts-ignore
deletedAt: item.deletedAt,
};
}),
);
// cp 被删除了,复原
await ChatPrompt.restore({ where: { id } });
};
revoverId();

View File

@ -1,5 +1,3 @@
import { CodeManager } from './admin/dashboard/load.ts';
import { ContainerData } from './routes/types.ts';
export { CodeManager };
export { ContainerData };

41
types/index.d.ts vendored
View File

@ -1,41 +0,0 @@
// Generated by dts-bundle-generator v9.5.1
export type RouterCode = {
id: string;
path: string;
key: string;
active: boolean;
project: string;
code: string;
exec: string;
type: RouterCodeType;
middleware: string[];
next: string;
data: any;
validator: any;
};
declare enum RouterCodeType {
route = "route",
middleware = "middleware"
}
declare enum CodeStatus {
running = "running",
stop = "stop",
fail = "fail"
}
export type CodeManager = {
fn?: any;
status?: CodeStatus;
errorMsg?: string;
lock?: boolean;
} & Partial<RouterCode>;
export interface ContainerData {
style?: {
[key: string]: string;
};
className?: string;
showChild?: boolean;
shadowRoot?: boolean;
}
export {};