update new way

This commit is contained in:
xion 2024-11-17 01:35:05 +08:00
parent 7ec8a001de
commit dc69b95f39
13 changed files with 463 additions and 1030 deletions

View File

@ -26,21 +26,20 @@
"files": [ "files": [
"types" "types"
], ],
"license": "ISC", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@abearxiong/auth": "1.0.2", "@abearxiong/auth": "1.0.2",
"@abearxiong/router": "0.0.1-alpha.43",
"@abearxiong/use-config": "^0.0.2", "@abearxiong/use-config": "^0.0.2",
"@babel/core": "^7.26.0", "@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0", "@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0", "@babel/preset-typescript": "^7.26.0",
"@kevisual/ai-graph": "workspace:^", "@kevisual/ai-graph": "workspace:^",
"@kevisual/ai-lang": "workspace:^", "@kevisual/ai-lang": "workspace:^",
"@kevisual/router": "0.0.4-alpha-8", "@kevisual/router": "0.0.5-alpha-1",
"@supabase/supabase-js": "^2.46.1", "@supabase/supabase-js": "^2.46.1",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"archiver": "^7.0.1", "archiver": "^7.0.1",
"bullmq": "^5.25.6", "bullmq": "^5.26.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"dts-bundle-generator": "^9.5.1", "dts-bundle-generator": "^9.5.1",
"formidable": "^3.5.2", "formidable": "^3.5.2",
@ -84,14 +83,12 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"glob": "^11.0.0", "glob": "^11.0.0",
"nodemon": "^3.1.7", "nodemon": "^3.1.7",
"patch-package": "^8.0.0",
"pm2": "^5.4.3", "pm2": "^5.4.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup": "^4.26.0", "rollup": "^4.27.2",
"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",
"ts-loader": "^9.5.1",
"tsx": "^4.19.2", "tsx": "^4.19.2",
"typescript": "^5.6.3" "typescript": "^5.6.3"
}, },

955
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -23,15 +23,6 @@ export const app = new App<{ import: any; emit: typeof emit; sequelize: typeof s
emit, emit,
sequelize, sequelize,
}, },
// routerHandle(res) {
// console.log('routerHandle', res.query);
// const { code, data, message } = res;
// return {
// code,
// data,
// message,
// };
// },
}); });
const clients = []; const clients = [];

View File

@ -2,10 +2,10 @@ import { useConfig } from '@abearxiong/use-config';
import { app } from './app.ts'; import { app } from './app.ts';
import './route.ts'; import './route.ts';
const config = useConfig(); const config = useConfig();
import { app as aiApp } from '@kevisual/ai-lang/src/index.ts'; // import { app as aiApp } from '@kevisual/ai-lang/src/index.ts';
import { uploadMiddleware } from './lib/upload.ts'; import { uploadMiddleware } from './lib/upload.ts';
import { loadApps } from './load-apps.ts'; import { loadApps } from './load-apps.ts';
export { aiApp }; // export { aiApp };
export { app }; export { app };
loadApps(app); loadApps(app);
app.listen(config.port, () => { app.listen(config.port, () => {

View File

@ -4,9 +4,11 @@ import fs, { rm } from 'fs';
import path from 'path'; import path from 'path';
import { IncomingForm } from 'formidable'; import { IncomingForm } from 'formidable';
import { app, minioClient } from '@/app.ts'; import { app, minioClient } from '@/app.ts';
import { SimpleRouter } from '@kevisual/router/simple';
import { bucketName } from '@/modules/minio.ts'; import { bucketName } from '@/modules/minio.ts';
import { getContentType } from '@/utils/get-content-type.ts'; import { getContentType } from '@/utils/get-content-type.ts';
import { User } from '@/models/user.ts'; import { User } from '@/models/user.ts';
import { getContainerById } from '@/routes/container/module/get-container-file.ts';
const filePath = useFileStore('upload', { needExists: true }); const filePath = useFileStore('upload', { needExists: true });
const cacheFilePath = useFileStore('cache-file', { needExists: true }); const cacheFilePath = useFileStore('cache-file', { needExists: true });
// curl -X POST http://localhost:4000/api/upload -F "file=@readme.md" // curl -X POST http://localhost:4000/api/upload -F "file=@readme.md"
@ -17,16 +19,12 @@ const cacheFilePath = useFileStore('cache-file', { needExists: true });
// -F "username=testuser" // -F "username=testuser"
let clients = []; let clients = [];
export const uploadMiddleware = async (req: http.IncomingMessage, res: http.ServerResponse) => {
if (req.method === 'GET' && req.url === '/api/app/upload') { const router = new SimpleRouter();
res.writeHead(200, { 'Content-Type': 'text/plain' }); const error = (msg: string, code = 500) => {
res.end('Upload API is ready'); return JSON.stringify({ code, message: msg });
return; };
} const checkAuth = async (req: http.IncomingMessage, res: http.ServerResponse) => {
const error = (msg: string) => {
return JSON.stringify({ code: 500, message: msg });
};
const checkAuth = async () => {
const authroization = req.headers?.['authorization'] as string; const authroization = req.headers?.['authorization'] as string;
if (!authroization) { if (!authroization) {
res.statusCode = 401; res.statusCode = 401;
@ -43,11 +41,15 @@ export const uploadMiddleware = async (req: http.IncomingMessage, res: http.Serv
return { tokenUser: null, token: null }; return { tokenUser: null, token: null };
} }
return { tokenUser, token }; return { tokenUser, token };
}; };
if (req.method === 'POST' && req.url === '/api/upload') { router.get('/api/app/upload', async (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Upload API is ready');
});
router.post('/api/upload', async (req, res) => {
if (res.headersSent) return; // 如果响应已发送,不再处理 if (res.headersSent) return; // 如果响应已发送,不再处理
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
const { tokenUser } = await checkAuth(); const { tokenUser } = await checkAuth(req, res);
if (!tokenUser) return; if (!tokenUser) return;
// 使用 formidable 解析 multipart/form-data // 使用 formidable 解析 multipart/form-data
const form = new IncomingForm({ const form = new IncomingForm({
@ -91,11 +93,11 @@ export const uploadMiddleware = async (req: http.IncomingMessage, res: http.Serv
} }
res.end(JSON.stringify({ code: 200, data: uploadResults })); res.end(JSON.stringify({ code: 200, data: uploadResults }));
}); });
} });
if (req.method === 'POST' && req.url === '/api/app/upload') { router.post('/api/app/upload', async (req, res) => {
if (res.headersSent) return; // 如果响应已发送,不再处理 if (res.headersSent) return; // 如果响应已发送,不再处理
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
const { tokenUser, token } = await checkAuth(); const { tokenUser, token } = await checkAuth(req, res);
if (!tokenUser) return; if (!tokenUser) return;
// //
// 使用 formidable 解析 multipart/form-data // 使用 formidable 解析 multipart/form-data
@ -203,7 +205,8 @@ export const uploadMiddleware = async (req: http.IncomingMessage, res: http.Serv
} }
res.end(JSON.stringify(data)); res.end(JSON.stringify(data));
}); });
} });
router.get('/api/events', async (req, res) => {
if (req.url === '/api/events') { if (req.url === '/api/events') {
res.writeHead(200, { res.writeHead(200, {
'Content-Type': 'text/event-stream', 'Content-Type': 'text/event-stream',
@ -217,4 +220,31 @@ export const uploadMiddleware = async (req: http.IncomingMessage, res: http.Serv
clients = clients.filter((client) => client !== res); clients = clients.filter((client) => client !== res);
}); });
} }
});
router.get('/api/container/file/:id', async (req, res) => {
const id = req.params.id;
if (!id) {
res.end(error('id is required'));
return;
}
const container = await getContainerById(id);
if (container.id) {
const code = container.code;
res.writeHead(200, {
'Content-Type': 'application/javascript; charset=utf-8',
'container-id': container.id,
});
res.end(code);
} else {
res.end(error('Container not found'));
}
res.writeHead(200, {
'Content-Type': 'application/json',
});
res.end(JSON.stringify(container));
});
export const uploadMiddleware = async (req: http.IncomingMessage, res: http.ServerResponse) => {
return router.parse(req, res);
}; };

View File

@ -18,6 +18,7 @@ export const redis = new Redis({
maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试) maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试)
...config.redis, ...config.redis,
}); });
console.log('redis', config.redis);
// 监听连接事件 // 监听连接事件
redis.on('connect', () => { redis.on('connect', () => {

View File

@ -1,5 +1,5 @@
import './demo/index.ts'; // import './demo/index.ts';
import { app as adminApp, appendTo } from './admin/index.ts'; // import { app as adminApp, appendTo } from './admin/index.ts';
import './routes/index.ts'; import './routes/index.ts';
import { app } from './app.ts'; import { app } from './app.ts';
import { useConfig } from '@abearxiong/use-config'; import { useConfig } from '@abearxiong/use-config';
@ -13,4 +13,4 @@ createAuthRoute({
// app.importApp(adminApp); // app.importApp(adminApp);
appendTo(app); // appendTo(app);

View File

@ -1,7 +1,7 @@
import { app } from '@/app.ts'; import { app } from '@/app.ts';
import { AiAgent, AiProperties } from '@/models/agent.ts'; import { AiAgent, AiProperties } from '@/models/agent.ts';
import { CustomError } from '@kevisual/router'; import { CustomError } from '@kevisual/router';
import { agentManger } from '@kevisual/ai-lang'; // import { agentManger } from '@kevisual/ai-lang';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
app app
.route({ .route({
@ -66,25 +66,25 @@ app
}) })
.addTo(app); .addTo(app);
app // app
.route('agent', 'test') // .route('agent', 'test')
.define(async (ctx) => { // .define(async (ctx) => {
const { message } = ctx.query; // const { message } = ctx.query;
const data: AiProperties = { // const data: AiProperties = {
type: 'ollama', // type: 'ollama',
id: 'test', // id: 'test',
model: 'qwen2.5:14b', // model: 'qwen2.5:14b',
baseUrl: 'http://mz.zxj.im:11434', // baseUrl: 'http://mz.zxj.im:11434',
cache: 'memory', // cache: 'memory',
}; // };
const agent = agentManger.createAgent(data as any); // const agent = agentManger.createAgent(data as any);
const res = await agent.sendHumanMessage(message); // const res = await agent.sendHumanMessage(message);
// agent.close(); // // agent.close();
agentManger.removeAgent(agent.id); // agentManger.removeAgent(agent.id);
ctx.body = res; // ctx.body = res;
return ctx; // return ctx;
}) // })
.addTo(app); // .addTo(app);
export const agentModelList = ['qwen2.5:14b', 'qwen2.5-coder:7b', 'llama3.1:8b', 'bakllava:latest'] as const; export const agentModelList = ['qwen2.5:14b', 'qwen2.5-coder:7b', 'llama3.1:8b', 'bakllava:latest'] as const;
export const openAiModels = ['gpt-4o']; export const openAiModels = ['gpt-4o'];
@ -130,8 +130,8 @@ const initManager = async () => {
cacheName: item.cacheName, cacheName: item.cacheName,
}; };
}); });
agentManger.createAgentList(data); // agentManger.createAgentList(data);
}; };
setTimeout(() => { // setTimeout(() => {
initManager(); // initManager();
}, 1000); // }, 1000);

View File

@ -1,7 +1,6 @@
import { CustomError } from '@kevisual/router'; import { CustomError } from '@kevisual/router';
import { app } from '../../app.ts'; import { app } from '../../app.ts';
import { ContainerModel, ContainerData, Container } from './models/index.ts'; import { ContainerModel, ContainerData, Container } from './models/index.ts';
import semver from 'semver';
import { uploadMinioContainer } from '../page/module/cache-file.ts'; import { uploadMinioContainer } from '../page/module/cache-file.ts';
const list = app.route({ const list = app.route({
path: 'container', path: 'container',
@ -49,7 +48,7 @@ add.run = async (ctx) => {
const container = { const container = {
...data, ...data,
}; };
let containerModel: any = null; let containerModel: ContainerModel | null = null;
if (container.id) { if (container.id) {
containerModel = await ContainerModel.findByPk(container.id); containerModel = await ContainerModel.findByPk(container.id);
if (containerModel) { if (containerModel) {
@ -134,7 +133,7 @@ app
version: version, version: version,
code: container.code, code: container.code,
filePath: fileName, filePath: fileName,
saveHTML saveHTML,
}); });
await ctx.call({ await ctx.call({
path: 'app', path: 'app',

View File

@ -1,6 +1,6 @@
import { sequelize } from '../../../modules/sequelize.ts'; import { sequelize } from '../../../modules/sequelize.ts';
import { DataTypes, Model } from 'sequelize'; import { DataTypes, Model } from 'sequelize';
import crypto from 'crypto';
export interface ContainerData {} export interface ContainerData {}
export type ContainerPublish = { export type ContainerPublish = {
key: string; key: string;
@ -21,11 +21,20 @@ export class ContainerModel extends Model {
declare type: string; declare type: string;
declare tags: string[]; declare tags: string[];
declare code: string; declare code: string;
declare hash: string;
declare source: string; declare source: string;
declare sourceType: string; declare sourceType: string;
declare data: ContainerData; declare data: ContainerData;
declare publish: ContainerPublish; declare publish: ContainerPublish;
declare uid: string; declare uid: string;
declare updatedAt: Date;
declare createdAt: Date;
createHash() {
const { code } = this;
const hash = crypto.createHash('md5');
hash.update(code);
this.hash = hash.digest('hex');
}
} }
ContainerModel.init( ContainerModel.init(
{ {
@ -55,6 +64,10 @@ ContainerModel.init(
type: DataTypes.TEXT, type: DataTypes.TEXT,
defaultValue: '', defaultValue: '',
}, },
hash: {
type: DataTypes.TEXT,
defaultValue: '',
},
source: { source: {
type: DataTypes.STRING, type: DataTypes.STRING,
defaultValue: '', defaultValue: '',

View File

@ -0,0 +1,11 @@
import { ContainerModel } from '../models/index.ts';
export const getContainerById = async (id: string) => {
const container = await ContainerModel.findByPk(id);
const code = container?.code;
return {
code,
id: container?.id,
updatedAt: new Date(container?.updatedAt).getTime(),
};
};

View File

@ -10,9 +10,9 @@ import './agent/index.ts';
import './user/index.ts'; import './user/index.ts';
import './chat-prompt/index.ts'; // import './chat-prompt/index.ts';
import './chat-history/index.ts'; // import './chat-history/index.ts';
import './github/index.ts'; import './github/index.ts';

View File

@ -16,7 +16,7 @@ app
logging: false, logging: false,
}); });
if (!user) { if (!user) {
throw new CustomError(500, 'user not found'); ctx.throw(500, 'user not found');
} }
user.setTokenUser(tokenUser); user.setTokenUser(tokenUser);
ctx.body = await user.getInfo(); ctx.body = await user.getInfo();
@ -30,7 +30,7 @@ app
.define(async (ctx) => { .define(async (ctx) => {
const { username, email, password } = ctx.query; const { username, email, password } = ctx.query;
if (!username && !email) { if (!username && !email) {
throw new CustomError(400, 'username or email is required'); ctx.throw(400, 'username or email is required');
} }
let user: User | null = null; let user: User | null = null;
if (username) { if (username) {
@ -40,10 +40,10 @@ app
user = await User.findOne({ where: { email } }); user = await User.findOne({ where: { email } });
} }
if (!user) { if (!user) {
throw new CustomError(500, 'Login Failed'); ctx.throw(500, 'Login Failed');
} }
if (!user.checkPassword(password)) { if (!user.checkPassword(password)) {
throw new CustomError(500, 'Password error'); ctx.throw(500, 'Password error');
} }
const token = await user.createToken(); const token = await user.createToken();
ctx.body = token; ctx.body = token;
@ -58,7 +58,7 @@ app
const result = await User.verifyToken(token); const result = await User.verifyToken(token);
ctx.body = result || {}; ctx.body = result || {};
} catch (e) { } catch (e) {
throw new CustomError(401, 'Token InValid '); ctx.throw(401, 'Token InValid ');
} }
}) })
.addTo(app); .addTo(app);
@ -73,7 +73,7 @@ app
const { id } = tokenUser; const { id } = tokenUser;
const user = await User.findByPk(id); const user = await User.findByPk(id);
if (!user) { if (!user) {
throw new CustomError(500, 'user not found'); ctx.throw(500, 'user not found');
} }
user.setTokenUser(tokenUser); user.setTokenUser(tokenUser);
if (username) { if (username) {
@ -105,13 +105,13 @@ app
const tokenUser = ctx.state.tokenUser; const tokenUser = ctx.state.tokenUser;
const { username, type = 'org' } = ctx.query.data || {}; const { username, type = 'org' } = ctx.query.data || {};
if (!username && type === 'org') { if (!username && type === 'org') {
throw new CustomError('username is required'); ctx.throw('username is required');
} }
if (tokenUser.username === username) { if (tokenUser.username === username) {
// 自己刷新自己的token // 自己刷新自己的token
const user = await User.findByPk(tokenUser.id); const user = await User.findByPk(tokenUser.id);
if (!user) { if (!user) {
throw new CustomError('user not found'); ctx.throw('user not found');
} }
if (user.type === 'user') { if (user.type === 'user') {
const token = await user.createToken(); const token = await user.createToken();
@ -131,7 +131,7 @@ app
} }
if (!me || me.type === 'org') { if (!me || me.type === 'org') {
console.log('switch Error ', me.username, me.type); console.log('switch Error ', me.username, me.type);
throw new CustomError('Permission denied'); ctx.throw('Permission denied');
} }
if (type === 'user') { if (type === 'user') {
const token = await me.createToken(); const token = await me.createToken();
@ -140,13 +140,13 @@ app
} }
const orgUser = await User.findOne({ where: { username } }); const orgUser = await User.findOne({ where: { username } });
if (!orgUser) { if (!orgUser) {
throw new CustomError('org user not found'); ctx.throw('org user not found');
} }
const user = await Org.findOne({ where: { username } }); const user = await Org.findOne({ where: { username } });
const users = user.users; const users = user.users;
const index = users.findIndex((u) => u.uid === me.id); const index = users.findIndex((u) => u.uid === me.id);
if (index === -1) { if (index === -1) {
throw new CustomError('Permission denied'); ctx.throw('Permission denied');
} }
const token = await orgUser.createToken(me.id); const token = await orgUser.createToken(me.id);
ctx.body = token; ctx.body = token;