feat: add neo4j
This commit is contained in:
		
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
								
							| @@ -31,11 +31,12 @@ | |||||||
|   ], |   ], | ||||||
|   "license": "ISC", |   "license": "ISC", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@abearxiong/router": "0.0.1-alpha.33", |     "@abearxiong/router": "0.0.1-alpha.34", | ||||||
|     "@abearxiong/use-config": "^0.0.2", |     "@abearxiong/use-config": "^0.0.2", | ||||||
|     "@babel/core": "^7.25.2", |     "@babel/core": "^7.25.2", | ||||||
|     "@babel/preset-env": "^7.25.4", |     "@babel/preset-env": "^7.25.4", | ||||||
|     "@babel/preset-typescript": "^7.24.7", |     "@babel/preset-typescript": "^7.24.7", | ||||||
|  |     "@kevisual/ai-graph": "workspace:^", | ||||||
|     "@types/semver": "^7.5.8", |     "@types/semver": "^7.5.8", | ||||||
|     "dayjs": "^1.11.13", |     "dayjs": "^1.11.13", | ||||||
|     "dts-bundle-generator": "^9.5.1", |     "dts-bundle-generator": "^9.5.1", | ||||||
| @@ -45,6 +46,9 @@ | |||||||
|     "lodash-es": "^4.17.21", |     "lodash-es": "^4.17.21", | ||||||
|     "minio": "^8.0.1", |     "minio": "^8.0.1", | ||||||
|     "nanoid": "^5.0.7", |     "nanoid": "^5.0.7", | ||||||
|  |     "neo4j-driver": "^5.24.1", | ||||||
|  |     "neode": "^0.4.9", | ||||||
|  |     "ollama": "^0.5.9", | ||||||
|     "pg": "^8.13.0", |     "pg": "^8.13.0", | ||||||
|     "semver": "^7.6.3", |     "semver": "^7.6.3", | ||||||
|     "sequelize": "^6.37.3", |     "sequelize": "^6.37.3", | ||||||
| @@ -58,9 +62,10 @@ | |||||||
|     "@types/jest": "^29.5.13", |     "@types/jest": "^29.5.13", | ||||||
|     "@types/jsonwebtoken": "^9.0.7", |     "@types/jsonwebtoken": "^9.0.7", | ||||||
|     "@types/lodash-es": "^4.17.12", |     "@types/lodash-es": "^4.17.12", | ||||||
|     "@types/node": "^22.5.5", |     "@types/node": "^22.6.1", | ||||||
|     "@types/superagent": "^8.1.9", |     "@types/superagent": "^8.1.9", | ||||||
|     "@types/supertest": "^6.0.2", |     "@types/supertest": "^6.0.2", | ||||||
|  |     "@types/uuid": "^10.0.0", | ||||||
|     "@types/webpack-env": "^1.18.5", |     "@types/webpack-env": "^1.18.5", | ||||||
|     "concurrently": "^9.0.1", |     "concurrently": "^9.0.1", | ||||||
|     "copy-webpack-plugin": "^12.0.2", |     "copy-webpack-plugin": "^12.0.2", | ||||||
| @@ -79,5 +84,10 @@ | |||||||
|     "webpack-cli": "^5.1.4", |     "webpack-cli": "^5.1.4", | ||||||
|     "webpack-node-externals": "^3.0.0" |     "webpack-node-externals": "^3.0.0" | ||||||
|   }, |   }, | ||||||
|  |   "resolutions": { | ||||||
|  |     "glob": "latest", | ||||||
|  |     "inflight": "latest", | ||||||
|  |     "rimraf": "latest" | ||||||
|  |   }, | ||||||
|   "pnpm": {} |   "pnpm": {} | ||||||
| } | } | ||||||
 Submodule packages/ai-graph updated: 492d1b0e7c...d1e2306233
									
								
							
							
								
								
									
										455
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										455
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | packages: | ||||||
|  |   - 'packages/*' | ||||||
| @@ -64,7 +64,11 @@ export const loadOne = async (item: RouterCodeModel) => { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
| export const load = async function () { | export const load = async function () { | ||||||
|   const codes = await RouterCodeModel.findAll(); |   const codes = await RouterCodeModel.findAll({ | ||||||
|  |     logging: (sql, timing) => { | ||||||
|  |       console.log('manager load database router codeModel'); | ||||||
|  |     }, | ||||||
|  |   }); | ||||||
|   const codeManager: CodeManager[] = codes.map((item) => { |   const codeManager: CodeManager[] = codes.map((item) => { | ||||||
|     const { path, key, id, code, exec, project, active, middleware } = item.toJSON(); |     const { path, key, id, code, exec, project, active, middleware } = item.toJSON(); | ||||||
|     if (!active) { |     if (!active) { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| // admin router manger | // admin router manger | ||||||
|  |  | ||||||
| import { Route } from '@abearxiong/router'; | import { CustomError, Route } from '@abearxiong/router'; | ||||||
| import { router } from '../modules/router.ts'; | import { router } from '../modules/router.ts'; | ||||||
| import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts'; | import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts'; | ||||||
| import { loadOne } from './dashboard/load.ts'; | import { loadOne } from './dashboard/load.ts'; | ||||||
| @@ -143,9 +143,8 @@ updateRouter.run = async (ctx) => { | |||||||
|       await newCodeRouter.save(); |       await newCodeRouter.save(); | ||||||
|       codeRouter = newCodeRouter; |       codeRouter = newCodeRouter; | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       ctx.body = e.message.toString(); |       console.error('updateRouter', e); | ||||||
|       ctx.code = 500; |       throw new CustomError(e.message.toString()); | ||||||
|       return ctx; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,12 +1,15 @@ | |||||||
| import { App } from '@abearxiong/router'; | import { App } from '@abearxiong/router'; | ||||||
| import { useConfig } from '@abearxiong/use-config'; | import { useConfig } from '@abearxiong/use-config'; | ||||||
| import { dynamicImport } from './lib/dynamic-import.ts'; | import { dynamicImport } from './lib/dynamic-import.ts'; | ||||||
| import { redisPublisher, redisSubscriber } from './modules/redis.ts'; | import { redisPublisher, redisSubscriber, redis } from './modules/redis.ts'; | ||||||
|  | import { neode } from './modules/neo4j.ts'; | ||||||
|  | import { minioClient } from './modules/minio.ts'; | ||||||
|  | import { sequelize } from './modules/sequelize.ts'; | ||||||
| useConfig(); | useConfig(); | ||||||
| export const emit = (channel: string, message?: any) => { | export const emit = (channel: string, message?: any) => { | ||||||
|   redisPublisher.publish(channel, JSON.stringify(message)); |   redisPublisher.publish(channel, JSON.stringify(message)); | ||||||
| }; | }; | ||||||
|  | export { neode, redis, minioClient, sequelize }; | ||||||
|  |  | ||||||
| export const app = new App<{ import: any; emit: typeof emit }>({ | export const app = new App<{ import: any; emit: typeof emit }>({ | ||||||
|   serverOptions: { |   serverOptions: { | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ RouterCodeModel.init( | |||||||
|       type: DataTypes.UUID, |       type: DataTypes.UUID, | ||||||
|       primaryKey: true, |       primaryKey: true, | ||||||
|       defaultValue: DataTypes.UUIDV4, |       defaultValue: DataTypes.UUIDV4, | ||||||
|       comment: '用户id', |       comment: '用户code id', | ||||||
|     }, |     }, | ||||||
|     path: { |     path: { | ||||||
|       type: DataTypes.STRING, |       type: DataTypes.STRING, | ||||||
| @@ -60,11 +60,11 @@ RouterCodeModel.init( | |||||||
|       defaultValue: 'default', |       defaultValue: 'default', | ||||||
|     }, |     }, | ||||||
|     code: { |     code: { | ||||||
|       type: DataTypes.STRING, |       type: DataTypes.TEXT, | ||||||
|       defaultValue: '', |       defaultValue: '', | ||||||
|     }, |     }, | ||||||
|     exec: { |     exec: { | ||||||
|       type: DataTypes.STRING, // 对代码进行编译后的代码 |       type: DataTypes.TEXT, // 对代码进行编译后的代码 | ||||||
|       defaultValue: '', |       defaultValue: '', | ||||||
|     }, |     }, | ||||||
|     type: { |     type: { | ||||||
| @@ -93,5 +93,7 @@ RouterCodeModel.init( | |||||||
|     tableName: 'cf_router_code', |     tableName: 'cf_router_code', | ||||||
|   }, |   }, | ||||||
| ); | ); | ||||||
| // RouterCodeModel.sync({ alter: true }); | RouterCodeModel.sync({ alter: true, logging: false }).catch((e) => { | ||||||
|  |   console.error('RouterCodeModel sync', e); | ||||||
|  | }); | ||||||
| // RouterCodeModel.sync({force: true}); | // RouterCodeModel.sync({force: true}); | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								src/models/prompt.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/models/prompt.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import { neode } from '@/app.ts'; | ||||||
|  |  | ||||||
|  | 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([]) }, | ||||||
|  | }); | ||||||
							
								
								
									
										29
									
								
								src/modules/neo4j.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/modules/neo4j.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | import Neode from 'neode'; | ||||||
|  | import { useConfig } from '@abearxiong/use-config'; | ||||||
|  |  | ||||||
|  | type NeodeConfig = { | ||||||
|  |   uri: string; | ||||||
|  |   username: string; | ||||||
|  |   password: string; | ||||||
|  | }; | ||||||
|  | const { neo4j } = useConfig<{ neo4j: NeodeConfig }>('neo4j'); | ||||||
|  |  | ||||||
|  | const { uri, username, password } = neo4j; | ||||||
|  | // 设置连接配置 | ||||||
|  | // const neode = new Neode('bolt://localhost:7687', 'neo4j', 'your_password'); | ||||||
|  | export const neode = new Neode(uri, username, password); | ||||||
|  |  | ||||||
|  | const testConnect = async () => { | ||||||
|  |   // 连接成功 | ||||||
|  |   // 尝试执行简单的 Cypher 查询以测试连接 | ||||||
|  |   neode | ||||||
|  |     .cypher('RETURN 1', {}) | ||||||
|  |     .then(() => { | ||||||
|  |       console.log('connect neo4j success'); | ||||||
|  |     }) | ||||||
|  |     .catch((err) => { | ||||||
|  |       console.error('Failed to connect:', err); | ||||||
|  |     }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | testConnect(); | ||||||
							
								
								
									
										30
									
								
								src/modules/ollama.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/modules/ollama.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | import { useConfig } from '@abearxiong/use-config'; | ||||||
|  | import { Ollama, Message, ChatRequest } from 'ollama'; | ||||||
|  |  | ||||||
|  | const config = useConfig<{ ollama: Ollama['config'] & { model: string } }>(); | ||||||
|  |  | ||||||
|  | const { host } = 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: config.model, | ||||||
|  |     options: { | ||||||
|  |       temperature: 0, | ||||||
|  |       ...chatOpts?.options, | ||||||
|  |     }, | ||||||
|  |     ...rest, | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| @@ -5,7 +5,7 @@ const config = useConfig<{ | |||||||
|   redis: ConstructorParameters<typeof Redis>; |   redis: ConstructorParameters<typeof Redis>; | ||||||
| }>(); | }>(); | ||||||
| // 配置 Redis 连接 | // 配置 Redis 连接 | ||||||
| const redis = new Redis({ | export const redis = new Redis({ | ||||||
|   host: 'localhost', // Redis 服务器的主机名或 IP 地址 |   host: 'localhost', // Redis 服务器的主机名或 IP 地址 | ||||||
|   port: 6379, // Redis 服务器的端口号 |   port: 6379, // Redis 服务器的端口号 | ||||||
|   // password: 'your_password', // Redis 的密码 (如果有) |   // password: 'your_password', // Redis 的密码 (如果有) | ||||||
|   | |||||||
| @@ -26,10 +26,6 @@ export class ContainerModel extends Model { | |||||||
|   declare data: ContainerData; |   declare data: ContainerData; | ||||||
|   declare publish: ContainerPublish; |   declare publish: ContainerPublish; | ||||||
|   declare uid: string; |   declare uid: string; | ||||||
|  |  | ||||||
|   // timestamps |  | ||||||
|   public readonly createdAt!: Date; |  | ||||||
|   public readonly updatedAt!: Date; |  | ||||||
| } | } | ||||||
| ContainerModel.init( | ContainerModel.init( | ||||||
|   { |   { | ||||||
|   | |||||||
| @@ -3,3 +3,5 @@ import './container/index.ts'; | |||||||
| import './page/index.ts'; | import './page/index.ts'; | ||||||
|  |  | ||||||
| import './resource/index.ts'; | import './resource/index.ts'; | ||||||
|  |  | ||||||
|  | import './prompt-graph/index.ts'; | ||||||
							
								
								
									
										1
									
								
								src/routes/prompt-graph/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/routes/prompt-graph/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | import './list.ts' | ||||||
							
								
								
									
										76
									
								
								src/routes/prompt-graph/list.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/routes/prompt-graph/list.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | import { PromptNeo } from '@/models/prompt.ts'; | ||||||
|  | import { app } from '@/app.ts'; | ||||||
|  | import { v4 } from 'uuid'; | ||||||
|  | app | ||||||
|  |   .route('prompt', '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', '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', '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', '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', 'createDemo') | ||||||
|  |   .define(async (ctx) => { | ||||||
|  |     const promptData = { | ||||||
|  |       id: v4(), | ||||||
|  |       title: 'test', | ||||||
|  |       description: '这是测试保存prompt的数据', | ||||||
|  |       prompt: '这是测试保存prompt的数据', | ||||||
|  |       inputVariables: JSON.stringify([{ key: 'test', value: 'test' }]), | ||||||
|  |       localVariables: JSON.stringify([{ key: 'test', value: 'test' }]), | ||||||
|  |     }; | ||||||
|  |     const prompt = await PromptNeo.create(promptData); | ||||||
|  |     ctx.body = await prompt.toJson(); | ||||||
|  |   }) | ||||||
|  |   .addTo(app); | ||||||
		Reference in New Issue
	
	Block a user