clear: old code
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,8 +2,6 @@ node_modules | |||||||
|  |  | ||||||
| dist | dist | ||||||
|  |  | ||||||
| # dist/app.cjs |  | ||||||
|  |  | ||||||
| app.config.json5 | app.config.json5 | ||||||
|  |  | ||||||
| apps.config.json | apps.config.json | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.npmrc
									
									
									
									
									
								
							| @@ -1,3 +1 @@ | |||||||
| @abearxiong:registry=https://npm.pkg.github.com | @abearxiong:registry=https://npm.pkg.github.com | ||||||
| @build:registry=https://npm.xiongxiao.me |  | ||||||
| @kevisual:registry=https://npm.xiongxiao.me |  | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| module.exports = { | module.exports = { | ||||||
|   apps: [ |   apps: [ | ||||||
|     { |     { | ||||||
|       name: 'codeflow', // 应用名称 |       name: 'codecenter', // 应用名称 | ||||||
|       script: './dist/app.mjs', // 入口文件 |       script: './dist/app.mjs', // 入口文件 | ||||||
|       // cwd: '.', // 设置当前工作目录 |       // cwd: '.', // 设置当前工作目录 | ||||||
|       output: './logs/codflow.log', |       output: './logs/codflow.log', | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| { | { | ||||||
|   "name": "@build/code-flow", |   "name": "@kevisual/code-center", | ||||||
|   "version": "0.0.2", |   "version": "0.0.1", | ||||||
|   "description": "code的flow流程成图", |   "description": "code center", | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "author": "abearxiong", |   "author": "abearxiong", | ||||||
| @@ -12,14 +12,14 @@ | |||||||
|     "test": "tsx  test/**/*.ts", |     "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\" ", |     "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", |     "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", |     "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", |     "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:build": "rollup -c rollup.apps.config.mjs", | ||||||
|     "apps:watch": "rollup -c rollup.apps.config.mjs -w", |     "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": [], |   "keywords": [], | ||||||
|   "types": "types/index.d.ts", |   "types": "types/index.d.ts", | ||||||
| @@ -30,41 +30,29 @@ | |||||||
|   ], |   ], | ||||||
|   "license": "UNLICENSED", |   "license": "UNLICENSED", | ||||||
|   "dependencies": { |   "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/auth": "1.0.5", | ||||||
|     "@kevisual/local-app-manager": "0.1.6", |     "@kevisual/local-app-manager": "0.1.6", | ||||||
|     "@kevisual/router": "^0.0.6-alpha-5", |     "@kevisual/router": "^0.0.6-alpha-5", | ||||||
|     "@types/semver": "^7.5.8", |     "@types/semver": "^7.5.8", | ||||||
|     "archiver": "^7.0.1", |     "archiver": "^7.0.1", | ||||||
|     "bullmq": "^5.34.6", |  | ||||||
|     "dayjs": "^1.11.13", |     "dayjs": "^1.11.13", | ||||||
|     "dts-bundle-generator": "^9.5.1", |  | ||||||
|     "formidable": "^3.5.2", |     "formidable": "^3.5.2", | ||||||
|     "ioredis": "^5.4.2", |     "ioredis": "^5.5.0", | ||||||
|     "json5": "^2.2.3", |     "json5": "^2.2.3", | ||||||
|     "jsonwebtoken": "^9.0.2", |  | ||||||
|     "lodash-es": "^4.17.21", |     "lodash-es": "^4.17.21", | ||||||
|     "minio": "^8.0.3", |     "minio": "^8.0.4", | ||||||
|     "nanoid": "^5.0.9", |     "nanoid": "^5.1.0", | ||||||
|     "neo4j-driver": "^5.27.0", |  | ||||||
|     "neode": "^0.4.9", |  | ||||||
|     "node-fetch": "^3.3.2", |     "node-fetch": "^3.3.2", | ||||||
|     "ollama": "^0.5.11", |     "p-queue": "^8.1.0", | ||||||
|     "p-queue": "^8.0.1", |     "pg": "^8.13.3", | ||||||
|     "pg": "^8.13.1", |     "rollup-plugin-esbuild": "^6.2.0", | ||||||
|     "rollup-plugin-esbuild": "^6.1.1", |     "semver": "^7.7.1", | ||||||
|     "semver": "^7.6.3", |  | ||||||
|     "sequelize": "^6.37.5", |     "sequelize": "^6.37.5", | ||||||
|     "socket.io": "^4.8.1", |     "socket.io": "^4.8.1", | ||||||
|     "sqlite3": "^5.1.7", |  | ||||||
|     "strip-ansi": "^7.1.0", |     "strip-ansi": "^7.1.0", | ||||||
|     "tar": "^7.4.3", |     "tar": "^7.4.3", | ||||||
|     "uuid": "^11.0.3", |     "uuid": "^11.0.5", | ||||||
|     "zod": "^3.24.1" |     "zod": "^3.24.2" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@kevisual/use-config": "^1.0.7", |     "@kevisual/use-config": "^1.0.7", | ||||||
| @@ -77,23 +65,21 @@ | |||||||
|     "@types/archiver": "^6.0.3", |     "@types/archiver": "^6.0.3", | ||||||
|     "@types/crypto-js": "^4.2.2", |     "@types/crypto-js": "^4.2.2", | ||||||
|     "@types/formidable": "^3.4.5", |     "@types/formidable": "^3.4.5", | ||||||
|     "@types/jsonwebtoken": "^9.0.7", |  | ||||||
|     "@types/lodash-es": "^4.17.12", |     "@types/lodash-es": "^4.17.12", | ||||||
|     "@types/node": "^22.10.5", |     "@types/node": "^22.13.4", | ||||||
|     "@types/react": "^19.0.2", |     "@types/react": "^19.0.10", | ||||||
|     "@types/uuid": "^10.0.0", |     "@types/uuid": "^10.0.0", | ||||||
|     "concurrently": "^9.1.2", |     "concurrently": "^9.1.2", | ||||||
|     "cross-env": "^7.0.3", |     "cross-env": "^7.0.3", | ||||||
|     "nodemon": "^3.1.9", |     "nodemon": "^3.1.9", | ||||||
|     "pm2": "^5.4.3", |     "pm2": "^5.4.3", | ||||||
|     "pm2-dev": "^5.4.1", |  | ||||||
|     "rimraf": "^6.0.1", |     "rimraf": "^6.0.1", | ||||||
|     "rollup": "^4.29.1", |     "rollup": "^4.34.8", | ||||||
|     "rollup-plugin-copy": "^3.5.0", |     "rollup-plugin-copy": "^3.5.0", | ||||||
|     "rollup-plugin-dts": "^6.1.1", |     "rollup-plugin-dts": "^6.1.1", | ||||||
|     "tape": "^5.9.0", |     "tape": "^5.9.0", | ||||||
|     "tsx": "^4.19.2", |     "tsx": "^4.19.2", | ||||||
|     "typescript": "^5.7.2" |     "typescript": "^5.7.3" | ||||||
|   }, |   }, | ||||||
|   "resolutions": { |   "resolutions": { | ||||||
|     "inflight": "latest", |     "inflight": "latest", | ||||||
|   | |||||||
 Submodule packages/ai-graph deleted from f15a9035a5
									
								
							| @@ -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" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -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'] |  | ||||||
| }; |  | ||||||
| @@ -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', |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| export * from './app.ts'; |  | ||||||
| import './routes/agent.ts'; |  | ||||||
| import { agentManger } from './module/agent.ts'; |  | ||||||
| export { agentManger }; |  | ||||||
| @@ -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(); |  | ||||||
| @@ -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'; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -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); |  | ||||||
|   }); |  | ||||||
| @@ -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({}) |  | ||||||
| @@ -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": [], |  | ||||||
| } |  | ||||||
 Submodule packages/var-proxy deleted from 79a9568a87
									
								
							
							
								
								
									
										4172
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4172
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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, |  | ||||||
| }); |  | ||||||
| @@ -8,15 +8,23 @@ fs.writeFileSync( | |||||||
|   packagePath, |   packagePath, | ||||||
|   JSON.stringify( |   JSON.stringify( | ||||||
|     { |     { | ||||||
|       name: 'codeflow', |       name: 'codecenter', | ||||||
|       version: '1.0.0', |       version: '1.0.0', | ||||||
|       devDependencies: { |       scripts: { | ||||||
|         '@babel/core': '^7.24.7', |         start: 'pm2 start dist/app.mjs --name codecenter', | ||||||
|         '@babel/preset-env': '^7.24.7', |       }, | ||||||
|         '@babel/preset-typescript': '^7.24.7', |       dependencies: { | ||||||
|         sequelize: '^6.37.3', |         '@kevisual/router': '^0.0.6-alpha-5', | ||||||
|         'socket.io': '^4.7.5', |         '@kevisual/use-config': '^1.0.7', | ||||||
|         pg: '^8.12.0', |         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, |     null, | ||||||
|   | |||||||
| @@ -1,17 +1,20 @@ | |||||||
| { | { | ||||||
|   "name": "codeflow", |   "name": "codecenter", | ||||||
|   "version": "1.0.0", |   "version": "1.0.0", | ||||||
|  |   "scripts": { | ||||||
|  |     "start": "pm2 start dist/app.mjs --name codecenter" | ||||||
|  |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@kevisual/router": "^0.0.6-alpha-2", |     "@kevisual/router": "^0.0.6-alpha-5", | ||||||
|     "@kevisual/use-config": "^1.0.3", |     "@kevisual/use-config": "^1.0.7", | ||||||
|     "ioredis": "^5.4.1", |     "ioredis": "^5.5.0", | ||||||
|     "minio": "^8.0.2", |     "minio": "^8.0.4", | ||||||
|     "pg": "^8.13.1", |     "pg": "^8.13.3", | ||||||
|     "sequelize": "^6.37.5", |     "sequelize": "^6.37.5", | ||||||
|     "sqlite3": "^5.1.7", |     "sqlite3": "^5.1.7", | ||||||
|     "socket.io": "^4.8.1", |     "socket.io": "^4.8.1", | ||||||
|     "@msgpack/msgpack": "3.0.0-beta2", |     "@msgpack/msgpack": "3.0.1", | ||||||
|     "pino": "^9.5.0", |     "pino": "^9.6.0", | ||||||
|     "pino-pretty": "^13.0.0" |     "pino-pretty": "^13.0.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -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); |  | ||||||
| }; |  | ||||||
| @@ -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); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| export { manager } from './manager.ts'; |  | ||||||
| @@ -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; |  | ||||||
| }; |  | ||||||
| @@ -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(); |  | ||||||
| @@ -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 }; |  | ||||||
| @@ -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); |  | ||||||
| @@ -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'); |  | ||||||
| }; |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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); // 监听器中的值 |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| @@ -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, |  | ||||||
| }); |  | ||||||
| @@ -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); |  | ||||||
| @@ -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); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| export * from './ts2js.ts'; |  | ||||||
|   | |||||||
| @@ -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)); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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'); |  | ||||||
| }; |  | ||||||
| @@ -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'); |  | ||||||
| } |  | ||||||
| @@ -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); |  | ||||||
| }); |  | ||||||
| @@ -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, |  | ||||||
| }); |  | ||||||
| @@ -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(); |  | ||||||
| @@ -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, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| import './list.ts'; |  | ||||||
| @@ -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); |  | ||||||
| @@ -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); |  | ||||||
|   }); |  | ||||||
| }); |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| import './list.ts' |  | ||||||
| import './session-list.ts' |  | ||||||
| import './chat-io.ts' |  | ||||||
| @@ -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); |  | ||||||
| @@ -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); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| import './list.ts'; |  | ||||||
| @@ -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); |  | ||||||
| @@ -4,16 +4,8 @@ import './page/index.ts'; | |||||||
|  |  | ||||||
| import './resource/index.ts'; | import './resource/index.ts'; | ||||||
|  |  | ||||||
| import './prompt-graph/index.ts'; |  | ||||||
|  |  | ||||||
| import './agent/index.ts'; |  | ||||||
|  |  | ||||||
| import './user/index.ts'; | import './user/index.ts'; | ||||||
|  |  | ||||||
| import './chat-prompt/index.ts'; |  | ||||||
|  |  | ||||||
| import './chat-history/index.ts'; |  | ||||||
|  |  | ||||||
| import './github/index.ts'; | import './github/index.ts'; | ||||||
|  |  | ||||||
| import './app-manager/index.ts'; | import './app-manager/index.ts'; | ||||||
|   | |||||||
| @@ -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); |  | ||||||
| @@ -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 绘制函数 |  | ||||||
| // }); |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| import './list-graph.ts'; |  | ||||||
| import './list.ts'; |  | ||||||
| import './ai.ts'; |  | ||||||
| @@ -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); |  | ||||||
| @@ -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); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| import './list.ts' |  | ||||||
| @@ -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); |  | ||||||
| @@ -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); |  | ||||||
| // }); |  | ||||||
| @@ -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(); |  | ||||||
| @@ -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(); |  | ||||||
| @@ -1,5 +1,3 @@ | |||||||
| import { CodeManager } from './admin/dashboard/load.ts'; |  | ||||||
| import { ContainerData } from './routes/types.ts'; | import { ContainerData } from './routes/types.ts'; | ||||||
|  |  | ||||||
| export { CodeManager }; |  | ||||||
| export { ContainerData }; | export { ContainerData }; | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -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 {}; |  | ||||||
		Reference in New Issue
	
	Block a user