From f7d3bc911e6bd10ed6d442c39f7d3741afcce439 Mon Sep 17 00:00:00 2001 From: zjc <1569294420@qq.com> Date: Thu, 20 Feb 2025 00:37:19 -0800 Subject: [PATCH 1/3] fix:modify Ai model and interface --- app/lib/enum.ts | 2 +- config/config.default.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/enum.ts b/app/lib/enum.ts index 51d7776..ac4b089 100644 --- a/app/lib/enum.ts +++ b/app/lib/enum.ts @@ -289,6 +289,6 @@ export enum E_Public { export enum E_FOUNDATION_MODEL { GPT_35_TURBO = 'gpt-3.5-turbo', // openai Local_GPT = 'loacl-compatible-gpt-3.5', //本地兼容opanai-api接口的 大语言模型,如chatGLM6b,通义千问 等。 - ERNIE_BOT_TURBO = 'ERNIE-Bot-turbo', // 文心一言 + ERNIE_BOT_TURBO = 'ERNIE-4.0-8K', // 文心一言 MOONSHOT_V1_8K = 'moonshot-v1-8k' // kimi } diff --git a/config/config.default.ts b/config/config.default.ts index 4471715..f69e697 100644 --- a/config/config.default.ts +++ b/config/config.default.ts @@ -277,7 +277,7 @@ export default (appInfo) => { manufacturer: '!openai' }, [E_FOUNDATION_MODEL.ERNIE_BOT_TURBO]: { - httpRequestUrl: `https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token=${token || process.env.WENXIN_ACCESS_TOKEN}`, + httpRequestUrl: `https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=${token || process.env.WENXIN_ACCESS_TOKEN}`, httpRequestOption: { ...commonRequestOption, data: { From 19ddb2e2f08bc92deeb6bb78f0b507a9e43e0f88 Mon Sep 17 00:00:00 2001 From: zjc <1569294420@qq.com> Date: Mon, 14 Apr 2025 19:00:53 -0700 Subject: [PATCH 2/3] feat:add component and componentLibrary --- .vscode/settings.json | 4 +- .../material-center/ComponentLibrary.ts | 54 ++++ .../material-center/UserComponents.ts | 26 ++ app/router/materialCenter/base.ts | 9 + app/service/app-center/appSchema.ts | 18 +- .../material-center/ComponentLibrary.ts | 53 ++++ app/service/material-center/UserComponents.ts | 256 ++++++++++++++++++ config/config.default.ts | 6 + config/config.local.ts | 2 +- package.json | 2 +- 10 files changed, 425 insertions(+), 5 deletions(-) create mode 100644 app/controller/material-center/ComponentLibrary.ts create mode 100644 app/controller/material-center/UserComponents.ts create mode 100644 app/service/material-center/ComponentLibrary.ts create mode 100644 app/service/material-center/UserComponents.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index e15e701..a1cd576 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - } + "source.fixAll.eslint": "explicit" + } } \ No newline at end of file diff --git a/app/controller/material-center/ComponentLibrary.ts b/app/controller/material-center/ComponentLibrary.ts new file mode 100644 index 0000000..6e1e0ea --- /dev/null +++ b/app/controller/material-center/ComponentLibrary.ts @@ -0,0 +1,54 @@ +/** +* Copyright (c) 2023 - present TinyEngine Authors. +* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. +* +* Use of this source code is governed by an MIT-style license. +* +* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, +* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR +* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. +* +*/ +import { Controller } from 'egg'; +import { I_CreateComponentLibrary } from '../../lib/interface'; + +export default class ComponentController extends Controller { + + /** + * @summary 注册组件库 + * @router POST /api/componentLibrary/create + */ + async create(){ + const data: I_CreateComponentLibrary = this.ctx.request.body; + this.ctx.body = await this.service.materialCenter.componentLibrary.create(data); + } + + /** + * @summary 查询组件库 + * @router GET + */ + async find(){ + this.ctx.body = await this.service.materialCenter.componentLibrary.find(this.ctx.query); + } + + /** + * @summary 更新组件库 + * @router PUT + */ + async update(){ + const { id } = this.ctx.params; + const params = this.ctx.request.body; + this.ctx.body = await this.service.materialCenter.componentLibrary.update({id, ...params }); + } + + + /** + * @summary 删除组件库 + * @router DELETE + */ + async delete(){ + const { id } = this.ctx.params; + this.ctx.body = await this.service.materialCenter.componentLibrary.delete({ id }); + } + +} diff --git a/app/controller/material-center/UserComponents.ts b/app/controller/material-center/UserComponents.ts new file mode 100644 index 0000000..636a999 --- /dev/null +++ b/app/controller/material-center/UserComponents.ts @@ -0,0 +1,26 @@ +/** +* Copyright (c) 2023 - present TinyEngine Authors. +* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. +* +* Use of this source code is governed by an MIT-style license. +* +* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, +* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR +* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. +* +*/ +import { Controller } from 'egg'; + +export default class userComponentController extends Controller { + + /** + * @summary 注册组件库 + * @router POST /api/componentLibrary/create + */ + async bundleCreate(){ + const ctx = this.ctx; + const fileStream = await ctx.getFileStream(); + this.ctx.body = await this.ctx.service.materialCenter.userComponents.bundleCreate(fileStream); + } + +} diff --git a/app/router/materialCenter/base.ts b/app/router/materialCenter/base.ts index 36b8348..4a6e3c2 100644 --- a/app/router/materialCenter/base.ts +++ b/app/router/materialCenter/base.ts @@ -62,4 +62,13 @@ export default (app: Application) => { subRouter.get('/tasks/status', controller.materialCenter.task.status); subRouter.get('/tasks/:id', controller.materialCenter.task.findById); + //组件库 + subRouter.post('/component-library/update/:id',controller.materialCenter.componentLibrary.update); + subRouter.post('/component-library/create',controller.materialCenter.componentLibrary.create); + subRouter.delete('/component-library/delete/:id',controller.materialCenter.componentLibrary.delete); + subRouter.get('/component-library/find',controller.materialCenter.componentLibrary.find); + + + // 拆分bundle.json + subRouter.post('/component/bundle/create',controller.materialCenter.userComponents.bundleCreate); }; diff --git a/app/service/app-center/appSchema.ts b/app/service/app-center/appSchema.ts index c576957..a96fce7 100644 --- a/app/service/app-center/appSchema.ts +++ b/app/service/app-center/appSchema.ts @@ -22,7 +22,8 @@ class AppSchema extends SchemaService { ['dataSource', this.getSchemaDataSource], ['i18n', this.getSchemaI18n], ['componentsTree', this.getSchemaComponentsTree], - ['componentsMap', this.getSchemaComponentsMap] + ['componentsMap', this.getSchemaComponentsMap], + ['packages', this.getPackages] ]); // 获取schema数据 @@ -79,10 +80,25 @@ class AppSchema extends SchemaService { // 获取应用信息 private async setMeta(query?): Promise { const metaData: I_Response = await this.service.appCenter.apps.schemaMeta(this.appId, query); + const componentLibraryData = await this.service.materialCenter.componentLibrary.list(); this.meta = metaData.data; + this.meta.componentLibrary = componentLibraryData.data; return metaData; } + private getPackages() { + const {componentLibrary} = this.meta; + const packages = componentLibrary.map((item) => ({ + name: item.name, + package: item.packageName, + version: item.version, + script: item.script, + css: item.css, + others: item.others + })); + return this.ctx.helper.getResponseData(packages); + } + // 获取元数据 private getSchemaMeta(): I_Response { const appData = this.meta.app; diff --git a/app/service/material-center/ComponentLibrary.ts b/app/service/material-center/ComponentLibrary.ts new file mode 100644 index 0000000..a8dc565 --- /dev/null +++ b/app/service/material-center/ComponentLibrary.ts @@ -0,0 +1,53 @@ +/** +* Copyright (c) 2023 - present TinyEngine Authors. +* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. +* +* Use of this source code is governed by an MIT-style license. +* +* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, +* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR +* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. +* +*/ +import { E_Method } from '../../lib/enum'; +import { I_CreateComponentLibrary } from '../../lib/interface'; +import * as qs from 'querystring'; +import DataService from '../dataService'; + +export default class ComponentLibrary extends DataService{ + + async create(param: I_CreateComponentLibrary) { + return this.query({ + url: 'component-library' , + method: E_Method.Post, + data: param + }); + } + + async find(param){ + const query = qs.stringify(param); + return this.query({ + url: `component-library?${query}` + }); + } + + async list() { + return this.query({ url: 'component-library' }); + } + + async update(param) { + const { id } = param; + return this.query({ + url: `component-library/${id}`, + method: E_Method.Put, + data: param + }); + } + + delete({ id }){ + return this.query({ + url: `component-library/${id}`, + method: E_Method.Delete + }); + } +} diff --git a/app/service/material-center/UserComponents.ts b/app/service/material-center/UserComponents.ts new file mode 100644 index 0000000..de0b2fd --- /dev/null +++ b/app/service/material-center/UserComponents.ts @@ -0,0 +1,256 @@ +/** +* Copyright (c) 2023 - present TinyEngine Authors. +* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. +* +* Use of this source code is governed by an MIT-style license. +* +* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, +* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR +* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. +* +*/ +import { E_AppErrorCode, E_MimeType, E_Method } from '../../lib/enum'; +import { pipeline } from 'stream'; +import * as path from 'path'; +import { promisify } from 'util'; +import fs from 'fs-extra'; +import { v4 as uuidv4 } from 'uuid'; +import { StatusCodes } from 'http-status-codes'; +import sendToWormhole from 'stream-wormhole'; +import { throwApiError } from '../../lib/ApiError'; +import DataService from '../dataService'; +import { I_Response } from '../../lib/interface'; +import * as qs from 'querystring'; + + +const pump = promisify(pipeline); + +export default class UserComponent extends DataService{ + + capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`; + toPascalCase = (str) => str.split('-').map(this.capitalize).join(''); + + private base = 'user-components'; + protected paramKeys = [ + 'docUrl', + 'devMode', + { + key: 'schema', + value: () => 'schema_fragment' + } + ]; + protected resKeys = [ + 'doc_url', + 'dev_mode', + { + key: 'schema_fragment', + value: () => 'schema' + } + ]; + + async bundleCreate (fileStream) { + const splitResult = await this.splitMaterials(fileStream); + const componentList = splitResult.components; + const packageList = splitResult.packages; + if(!packageList) { + return this.bulkComponentCreate(componentList); + } + packageList.forEach(async (componentLibrary) => { + // 查询是否存在组件库 + const paramComponentLibrary = { + name: componentLibrary.name, + version: componentLibrary.version + } + const componentLibraryList = await this.service.materialCenter.componentLibrary.find(paramComponentLibrary); + componentLibrary.packageName = componentLibrary.package; + componentLibrary.framework = 'Vue'; + componentLibrary.isOfficial = true; + componentLibrary.isDefault = true; + if(componentLibraryList.data.length) { + // 修改组件库 + componentLibrary.id = componentLibraryList.data[0].id; + await this.service.materialCenter.componentLibrary.update(componentLibrary); + }else { + // 新增组件库 + await this.service.materialCenter.componentLibrary.create(componentLibrary); + } + }) + return await this.bulkComponentCreate(componentList); + + } + + // 批量新增或者修改组件 + async bulkComponentCreate(componentList) { + let componentLibraryListResult: any = []; + const fileResult = { + addNum: 0, + updateNum: 0 + } + + await Promise.all(componentList.map(async (component) => { + // 查询是否存在组件 + component.component = (typeof component.component === 'string') + ? component.component + : (Array.isArray(component.component) ? component.component.join(',') : ''); + const paramComponent = { + component: component.component, + version: component.version + }; + + const componentQueryList = await this.find(paramComponent); // 异步查询组件 + let packageName = ''; + if (component.npm && component.npm.package) { + packageName = component.npm.package; + } + + // 根据包名和版本去查询组件库是否存在 + const paramComponentLibrary = { + packageName: packageName, + version: component.version + }; + + const componentLibraryList = await this.service.materialCenter.componentLibrary.find(paramComponentLibrary); + let libraryId = componentLibraryList.data[0] ? componentLibraryList.data[0].id : null; + component.library = libraryId; + + if (!componentQueryList.data.length) { + fileResult.addNum += 1; + // 新增组件 + component.id = null; + const componentObject: I_Response = await this.create(component); + componentLibraryListResult.push(componentObject); + } else { + fileResult.updateNum += 1; + // 修改组件 + component.id = componentQueryList.data[0].id; + const componentObject: I_Response = await this.update(component); + componentLibraryListResult.push(componentObject); + } + })); + + // 返回新增或者修改的条数 + return fileResult; + } + + async create(param) { + return this.fQuery({ + url: this.base, + method: E_Method.Post, + data: param + }); + } + + async update(param) { + const {id} = param; + return this.fQuery({ + url: `${this.base}/${id}`, + method: E_Method.Put, + data: param + }); + + } + + async find(param) { + const query = typeof param === 'string' ? param : qs.stringify(param); + return this.fQuery({ + url: `${this.base}?${query}` + }); + } + + async splitMaterials(fileStream) { + let bundleDefault = { + data: { + framework: 'Vue', + materials: { + components: [], + blocks: [], + snippets: [], + packages: [] + } + } + } + const bundle = await this.parseJsonFileStream(fileStream) || bundleDefault; + const { components, snippets, packages } = bundle?.data.materials; + try { + // 预处理 snippets + const snippetsMap = {} + if(snippets != null && snippets.length != 0){ + snippets.forEach((snippetItem) => { + if (!Array.isArray(snippetItem?.children)) { + return + } + + snippetItem.children.forEach((item) => { + const key = item?.schema?.componentName || item.snippetName + if (!key) { + return + } + const realKey = this.toPascalCase(key) + if (!snippetsMap[realKey]) { + snippetsMap[realKey] = [] + } + snippetsMap[realKey].push({ + ...item, + category: snippetItem.group + }) + }) + }) + } + + // 处理组件 + components.forEach((comp) => { + const matchKey = Array.isArray(comp.component) + ? this.toPascalCase(comp.component[0]) + : this.toPascalCase(comp.component) + + const matchedSnippets = snippetsMap[matchKey] + + if (matchedSnippets?.length) { + comp.snippets = matchedSnippets + } + }) + + } catch (error) { + this.ctx.logger.error(`failed to split materials: ${error}.`) + } + return {components,packages}; + } + + async parseJsonFileStream(fileStream) { + const { filename, fieldname, encoding, mime } = fileStream; + this.logger.info(`parseJsonFileStream field: ${fieldname}, filename:${filename}, encoding: ${encoding}, mime: ${mime}`); + // 校验文件流合法性 + await this.validateFileStream(fileStream, E_AppErrorCode.CM308, [E_MimeType.Json]); + const jsonFileName = `${uuidv4()}_${filename.toLowerCase()}`; + const target = path.resolve(this.config.baseDir, '.tmp', jsonFileName); + try { + await fs.ensureDir(path.parse(target).dir); + const writeStream = fs.createWriteStream(target); + await pump(fileStream, writeStream); + return await fs.readJson(target); + } catch (err) { + await sendToWormhole(fileStream); + throwApiError((err as Error).message, StatusCodes.INTERNAL_SERVER_ERROR, E_AppErrorCode.CM309); + } finally { + await fs.remove(target); + } + } + + /** + * 校验文件流是否合法 + * @param { any } fileStream 文件流 + * @param { E_AppErrorCode } condition 报错码 + * @param { Array } mimeTypes 文件类型集合 + */ + async validateFileStream(fileStream, code: E_AppErrorCode, mimeTypes: Array) { + const { filename, mime } = fileStream; + const condition = filename && mimeTypes.includes(mime); + if (condition) { + return; + } + // 只要文件不合法就throw error, 无论是批量还是单个 + await sendToWormhole(fileStream); + throwApiError('', StatusCodes.BAD_REQUEST, code); + } + +} diff --git a/config/config.default.ts b/config/config.default.ts index f69e697..abdd8a9 100644 --- a/config/config.default.ts +++ b/config/config.default.ts @@ -74,6 +74,12 @@ export default (appInfo) => { domainWhiteList: [''] }; + config.cors = { + origin: '*', //允许所有来源的请求 + allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH', + credentials: true, // 如果需要支持带凭证的跨域请求,则设置为true + } + config.dsl = { 'vue-tiny': { dslGeneratorPkg: '@opentiny/tiny-engine-dsl-vue', diff --git a/config/config.local.ts b/config/config.local.ts index e0def69..0b0ce64 100644 --- a/config/config.local.ts +++ b/config/config.local.ts @@ -14,7 +14,7 @@ import { EggAppConfig, PowerPartial } from 'egg'; export default () => { const config: PowerPartial = {}; config.dataCenter = { - host: process.env.DATA_CENTER_URL || 'http://localhost:1337', + host: process.env.DATA_CENTER_URL || 'http://localhost:1356', sessionKeyPrefix: 'lowcode:data:' }; diff --git a/package.json b/package.json index de550a5..c6b4202 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "scripts": { "start": "egg-scripts start --daemon --stdout=/opt/cloud/logs/master-stdout.log --stderr=/opt/cloud/logs/master-stderr.log --title=lowcode-webservice", "stop": "egg-scripts stop --stdout=/opt/cloud/logs/master-stdout.log --stderr=/opt/cloud/logs/master-stderr.log --title=lowcode-webservice", - "dev": "egg-bin dev --port 7011", + "dev": "egg-bin dev --port 7020", "debug": "egg-bin debug --port 7011", "test-local": "egg-bin test", "test": "npm run lint -- --fix && npm run test-local", From 1c07a83d82a5ca811d1d4039ae43d72692df3c57 Mon Sep 17 00:00:00 2001 From: zhangjuncao <163953928+zhangjuncao@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:15:14 +0800 Subject: [PATCH 3/3] Update settings.json --- .vscode/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a1cd576..7ddd0c1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "source.fixAll.eslint": true } -} \ No newline at end of file +}