Commit 4747efe7 authored by jaden's avatar jaden 🏄

init commit

parents
File added
chat-query @ 97f2750d
Subproject commit 97f2750df4a86001cc5dcdf055e076a591d01d66
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
name: Build and Push Docker Image
on:
push:
branches:
- fusionTeach
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install dependencies & build Nest app
run: |
npm install -g pnpm
pnpm install
npm run build
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: jadenxiong/chat-query-backend:fusionTeach
build-args: |
OPEN_AI_API_KEY=${{ secrets.OPEN_AI_API_KEY }}
MODEL_NAME=${{ secrets.MODEL_NAME }}
BASE_URL=${{ secrets.BASE_URL }}
DB_HOST=${{ secrets.DB_HOST }}
DB_PORT=${{ secrets.DB_PORT }}
# compiled output
/dist
/node_modules
# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
packages/*
.env
python
\ No newline at end of file
{
"singleQuote": true,
"trailingComma": "all"
}
\ No newline at end of file
[https://github.com/Mrxyy/chat-query](https://github.com/Mrxyy/chat-query)
\ No newline at end of file
FROM node:18
# 设置工作目录
WORKDIR /usr/src/app
# 复制 package.json 和 package-lock.json 文件到工作目录
COPY package*.json ./
COPY pnpm-lock.yaml ./
ARG OPEN_AI_API_KEY
ENV OPEN_AI_API_KEY $OPEN_AI_API_KEY
ARG MODEL_NAME
ENV MODEL_NAME $MODEL_NAME
ARG BASE_URL
ENV BASE_URL $BASE_URL
ARG DB_HOST
ENV DB_HOST $DB_HOST
ARG DB_PORT
ENV DB_PORT $DB_PORT
ARG DB_PASSWORD
ENV DB_PASSWORD $DB_PASSWORD
ARG DB_USER
ENV DB_USER $DB_USER
# 安装项目依赖
RUN npm i -g pnpm
RUN pnpm i
# 复制应用程序源代码到工作目录
COPY dist ./dist
# 暴露端口,确保与 Nest.js 应用程序中设置的端口一致
EXPOSE 3001
# 启动命令
CMD [ "npm", "run", "start:prod" ]
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
This diff is collapsed.
{
"name": "chat-query",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/src/main",
"build-image": "npm run build && docker build -t jadenxiong/chat-query-backend:latest .",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@dbml/core": "^2.5.3",
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/sequelize": "^9.0.2",
"@types/sequelize": "^4.28.15",
"dotenv": "^16.1.4",
"knex": "^2.4.2",
"langchain": "^0.0.149",
"lodash": "^4.17.21",
"mysql2": "^3.3.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0",
"sequelize": "^6.32.0",
"sequelize-typescript": "^2.1.5",
"typeorm": "^0.3.16",
"zod": "^3.21.4"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@types/express": "^4.17.13",
"@types/jest": "29.5.1",
"@types/node": "18.16.12",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "29.5.0",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "29.1.0",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.2.0",
"typescript": "^5.0.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
},
"peerDependenciesMeta": {
"langchain": {
"injected": true
}
},
"dependenciesMeta": {}
}
This diff is collapsed.
import { Sequelize } from 'sequelize-typescript';
import { Module } from '@nestjs/common';
import { SChemaModel } from './models/Schema';
import { SequelizeModule } from '@nestjs/sequelize';
import { Kenx } from './utils/knex';
import { QueriesModel } from './models/Querys';
import { OpenAIModule } from './models/AI/openAi';
import { config } from 'dotenv';
config();
export const dbHost = process.env['DB_HOST'];
export const dbPort = Number(process.env['DB_PORT']);
export const dbUser = process.env['DB_USER'];
export const dbPassword = process.env['DB_PASSWORD'];
const env = [
SequelizeModule.forRoot({
dialect: 'mysql',
host: dbHost,
port: dbPort,
username: dbUser || 'root',
password: dbPassword || '123789',
database: 'chat_query_fusion',
autoLoadModels: true,
synchronize: true,
}),
];
@Module({
imports: [...env, SChemaModel, QueriesModel, Kenx, OpenAIModule],
})
export class AppModule {
constructor(sequelize: Sequelize) {
// console.log(sequelize, "sequelize实例")
}
}
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3001);
console.log('http://127.0.0.1:3001');
}
bootstrap();
import { Module } from '@nestjs/common';
import { OpenAIController } from './openAi.controller';
import { OpenAIService } from './openAi.service';
@Module({
imports: [],
providers: [OpenAIService],
controllers: [OpenAIController],
})
export class OpenAIModule {
constructor() {}
}
import { Body, Controller, Post } from '@nestjs/common';
import { OpenAIService } from './openAi.service';
@Controller('/openAi/api')
export class OpenAIController {
constructor(private server: OpenAIService) {
server.test();
}
@Post('reactLive')
ReactLive(@Body('props') props, @Body('need') need) {
return this.server.getReactLiveCode(props, need);
}
@Post('code')
Code(@Body('data') data, @Body('need') need) {
return this.server.getFunctionCode(data.slice(0, 2), need);
}
@Post('checkQuery')
checkQuery(@Body('messageList') messageList) {
return this.server.checkQuery(messageList);
}
}
import { async } from 'rxjs';
import { defaultScope, fxTepmlate } from './../../../utils/prompts/reactLive';
import { OpenAI } from 'langchain/llms/openai';
// import { PromptTemplate } from 'langchain/prompts';
// import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
// import { APIChain } from 'langchain/chains';
import { DataSource } from 'typeorm';
import { SqlDatabase } from 'langchain/sql_db';
import { createSqlAgent, SqlToolkit } from 'langchain/agents/toolkits/sql';
// import { SqlDatabaseChain } from 'langchain/chains';
import { get, nth } from 'lodash';
import { Tool } from 'langchain/tools';
import {
disableConstraints,
enableConstraints,
} from 'src/utils/knex/executeSQLWithDisabledForeignKeys';
import { GET_COMPONENT_BY_DATA } from 'src/utils/prompts/reactLive';
import { extractCodeBlocks } from 'src/utils/parse/getCode';
import { GET_FUNCTION_CODE_CHAIN } from 'src/utils/prompts/getFunction';
import { GET_CHECK_RESULT } from 'src/utils/prompts/checkSql';
export const openAIApiKey = process.env['OPEN_AI_API_KEY'];
console.log(Tool);
export class TestSqlTool extends Tool {
name = 'execute-sql';
db: SqlDatabase;
constructor(db: SqlDatabase) {
super();
this.db = db;
}
/** @ignore */
async _call(input: string) {
try {
await this.db.appDataSource.query(disableConstraints['mysql']);
await this.db.appDataSource.query(input);
await this.db.appDataSource.query(enableConstraints['mysql']);
return input;
} catch (error) {
return `${error}`;
}
}
// 此工具的输入是一个逗号分隔的表列表,输出是这些表的模式和示例行。请务必先调用list-tables-sql来确保这些表实际存在!
description = `
Input to this tool is specifically for executing SQL DDL statements and insert, update, delete statements and only one SQL statement can be executed each time.
`;
}
export class OpenAIService {
async test() {
// this.run();
}
async run() {
const model = new OpenAI(
{
modelName: 'gpt-4-0613',
openAIApiKey: openAIApiKey,
temperature: 0,
},
{
basePath:
'https://chat-gpt-next-qwn676aj7-mrxyy.vercel.app/api/openai/v1/',
},
);
const datasource = new DataSource({
type: 'mysql',
host: '127.0.0.1',
port: 3306,
username: 'root',
password: '123789xyy',
database: 'test-10',
connectorPackage: 'mysql2',
});
const db = await SqlDatabase.fromDataSourceParams({
appDataSource: datasource,
});
console.log(db);
const toolkit = new SqlToolkit(db, model);
toolkit.tools.push(new TestSqlTool(db));
toolkit.dialect = 'mysql';
const executor = createSqlAgent(model, toolkit, {
prefix: `You are an agent designed to interact with a SQL database.
Given an input question, create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Unless the user specifies a specific number of examples they wish to obtain, always limit your query to at most {top_k} results using the LIMIT clause.
You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for a the few relevant columns given the question.
You have access to tools for interacting with the database.
Only use the below tools. Only use the information returned by the below tools to construct your final answer.
You MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.
If the question does not seem related to the database, just return "I don't know" as the answer.`,
});
// const chain = new SqlDatabaseChain({
// llm: model,
// database: db,
// sqlOutputKey: 'sql',
// });
const result = await executor.call({
input: '每个表中都插入一条假数据,id 为自增字段',
});
// const res = await chain.call({
// query: '查出所有订单对应的用户和对应地址?',
// });
console.log(get(nth(result.intermediateSteps, -1), 'observation'));
await datasource.destroy();
}
async getReactLiveCode(props: Record<string, any>, need: string) {
const result = await GET_COMPONENT_BY_DATA.call({
props: JSON.stringify(props),
need,
scope: defaultScope,
fxTepmlate: fxTepmlate,
});
return {
code: extractCodeBlocks(result.text)[0],
};
}
async getFunctionCode(data: Record<string, any>, need: string) {
const result = await GET_FUNCTION_CODE_CHAIN.call({
data: JSON.stringify(data),
need,
});
return {
code: result.text,
};
}
async checkQuery(messageList: any[]) {
const result = await GET_CHECK_RESULT.call({
messageList: JSON.stringify(
messageList.map((v) => ({
[v.role]: get(v, 'content') || get(v, 'function_call.arguments'),
})),
),
});
console.log(result, 'result');
return {
...result,
};
}
}
import { Schema } from '../Schema/schema.model';
import {
Table,
Column,
Model,
CreatedAt,
UpdatedAt,
DeletedAt,
PrimaryKey,
DataType,
Comment,
Default,
AllowNull,
BelongsTo,
ForeignKey,
HasMany,
} from 'sequelize-typescript';
import { Query } from './Query.model';
@Table
export class DB extends Model {
@PrimaryKey
@Comment('id')
@Default(DataType.UUIDV4)
@Column(DataType.UUID)
id: string;
@HasMany(() => Query, {
sourceKey: 'id',
foreignKey: 'DbID',
})
Queries: Query[];
@Comment('连接名称')
@AllowNull(false)
@Column
name: string;
@Comment('配置')
@AllowNull(false)
@Column({
type: DataType.JSON,
})
config: JSON;
@BelongsTo(() => Schema, {
foreignKey: 'schemaId',
})
Schema: string;
@ForeignKey(() => Schema)
@Column(DataType.UUID)
schemaId: string;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
@DeletedAt
DeletedAt: Date;
}
import { Schema } from './../Schema/schema.model';
import {
Table,
Column,
Model,
CreatedAt,
UpdatedAt,
DeletedAt,
PrimaryKey,
DataType,
Comment,
Default,
AllowNull,
BelongsTo,
ForeignKey,
} from 'sequelize-typescript';
import { DB } from './DB.model';
@Table
export class Query extends Model {
@PrimaryKey
@Comment('id')
@Default(DataType.UUIDV4)
@Column(DataType.UUID)
id: string;
@Comment('Query名称')
@AllowNull(false)
@Column
name: string;
@Comment('内容')
@AllowNull(false)
@Column({
type: DataType.JSON,
})
content: string;
@BelongsTo(() => Schema, {
foreignKey: 'schemaId',
})
Schema: Schema;
@BelongsTo(() => DB, {
foreignKey: 'DbID',
})
DB: DB;
@ForeignKey(() => DB)
@Column(DataType.UUID)
DbID: string;
@ForeignKey(() => Schema)
@Column(DataType.UUID)
schemaId: string;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
@DeletedAt
DeletedAt: Date;
}
import { CreatedAt } from 'sequelize-typescript';
import {
Body,
Controller,
Delete,
Get,
Param,
Post,
Put,
Query as QueryValue,
} from '@nestjs/common';
import { QueriesService } from './index.service';
import { DB } from './DB.model';
import { Query } from './Query.model';
import { Schema } from '../Schema/schema.model';
@Controller('query')
export class QueriesController {
constructor(private service: QueriesService) {}
@Post('/querySql')
executeQuery(@Body() pramas) {
return this.service.executeQuery(pramas);
}
@Post('/add')
addQuery(@Body() query: Query) {
return this.service.addQuery(query);
}
@Put('/:queryId')
updateQuery(@Param('queryId') queryId, @Body('functions') functions: string) {
return this.service.updateQuery(queryId, functions);
}
@Post('/getDbDBML')
getDbDBML(@Body() config) {
return this.service.getDbDBML(config);
}
@Post('/createDbConnect')
createDbConnect(@Body() dbConfig: Pick<DB, 'config' | 'schemaId' | 'name'>) {
return this.service.createDbConnectConfigWithSchema(dbConfig);
}
@Post('/testConnectDb')
testConnectDb(@Body() dbConfig: DB['config']) {
return this.service.testConnectDb(dbConfig);
}
@Delete('/DbConnect/:DbID')
deleteDbForSchema(@Param('DbID') DbID) {
return this.service.deleteDb(DbID);
}
@Post('/run/:queryId')
runQuery(
@Param('queryId') queryID,
@Body('params') params: Record<string, any>,
@QueryValue('type') type: 1 | undefined,
) {
return this.service.runQuery(queryID, params, type);
}
@Delete('/:queryId')
deleteQuery(@Param('queryId') queryId: Query['id']) {
return this.service.deteteQuery(queryId);
}
@Get('/:schemaId/queries')
getQueries(@Param('schemaId') schemaId: Schema['id']) {
return this.service.getQueries(schemaId);
}
@Get('/:schemaId/DbConnect')
getSchemaAllDb(@Param('schemaId') schemaId: Schema['id']) {
return this.service.getSchemaAllDb(schemaId);
}
@Post('/:schemaId')
create(@Param('schemaId') schemaId: Schema['id']) {
return this.service.createQuery(schemaId);
}
}
import { Schema } from './../Schema/schema.model';
import { Injectable } from '@nestjs/common';
import { KnexContainer } from 'src/utils/knex';
import { Query } from './Query.model';
import { InjectModel } from '@nestjs/sequelize';
import { DB } from './DB.model';
import knex from 'knex';
import { generateDbdiagramDsl } from 'src/utils/knex/DB2DBML';
import { get, pick } from 'lodash';
import { Knex } from 'knex';
import exportSQL from 'src/utils/knex/export-sql';
import { executeSQLWithDisabledForeignKeys } from 'src/utils/knex/executeSQLWithDisabledForeignKeys';
function pureCode(raw: string): string {
const codeRegex = /```.*\n([\s\S]*?)\n```/;
const match = raw.match(codeRegex);
if (match) {
const code = match[1];
return code;
} else {
return raw;
}
}
@Injectable()
export class QueriesService {
constructor(
private knex: KnexContainer,
@InjectModel(Query) private QueryModel: typeof Query,
@InjectModel(DB) private DbModel: typeof DB,
) {}
async executeQuery(pramas: {
config: Record<string, any>;
execution: {
content: string;
type: string;
}[];
dbID: string;
}) {
console.log(pramas);
let db = this.knex.get(pramas.dbID);
if (!db) {
const dbConfig = await this.DbModel.findByPk(pramas.dbID);
const { client, host, port, user, password, database }: any = get(
dbConfig,
'dataValues.config',
);
db = await this.knex.create({
client: client,
asyncStackTraces: true,
debug: true,
connection: {
host: host,
port: port,
user: user,
password: password,
database: database,
},
});
}
const { execution = [], config } = pramas;
if (db) {
const results: string[] = [];
const fx = async ({
content,
type,
}: {
content: string;
type: string;
}) => {
if (type === 'sql') {
const sqlArr = content.split(/;\n/);
const params = [];
const templateSqlArr = [];
for (let i = 0; i < sqlArr.length; i++) {
const paramsItem = [];
templateSqlArr.push(
pureCode(sqlArr[i]).replace(/\$.*?\$/g, (string) => {
paramsItem.push(config[string]);
return '?';
}),
);
params.push(paramsItem);
}
const data = await executeSQLWithDisabledForeignKeys(
db,
templateSqlArr,
params,
);
return data;
}
};
const data = [];
for (const item of execution) {
// 保证执行顺序
data.push(await fx(item));
}
return {
data,
};
}
}
async createQuery(schemaId: Schema['id']): Promise<Query> {
return this.QueryModel.create({
schemaId,
name: 'unknown',
content: '',
});
}
async createDatabaseAndExecuteDDL(dbConfig, ddl, dbName) {
// 创建连接到默认数据库的 knex 实例
const defaultKnex = knex(dbConfig);
// 根据不同数据库系统的语法,创建数据库
if (dbConfig.client === 'mysql' || dbConfig.client === 'mysql2') {
await defaultKnex.schema.raw(
`CREATE DATABASE IF NOT EXISTS \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`,
);
} else if (dbConfig.client === 'mssql') {
await defaultKnex.schema.raw(
`CREATE DATABASE [${dbName}] COLLATE Latin1_General_CI_AS`,
);
} else if (dbConfig.client === 'pg') {
await defaultKnex.schema.raw(
`CREATE DATABASE "${dbName}" WITH ENCODING 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8'`,
);
} else if (dbConfig.client === 'oracle') {
// Oracle 不支持在 CREATE DATABASE 语句中直接设置字符集,请参考官方文档进行配置。
await defaultKnex.schema.raw(`CREATE DATABASE "${dbName}"`);
} else {
throw new Error(`Unsupported database client: ${dbConfig.client}`);
}
// 断开连接到默认数据库的 knex 实例
await defaultKnex.destroy();
// 创建连接到新数据库的 knex 实例
const knexForNewDb = knex({
...dbConfig,
connection: {
...dbConfig.connection,
database: dbName,
},
});
// 执行原始的 DDL SQL 语句
// await knexForNewDb.schema.raw(a);
await executeSQLWithDisabledForeignKeys(knexForNewDb, ddl);
// 断开连接到新数据库的 knex 实例。
await knexForNewDb.destroy();
}
async createDbConnectConfigWithSchema(
dbConfig: Pick<DB, 'config' | 'schemaId' | 'name'>,
): Promise<DB | { err: string }> {
if (get(dbConfig, 'config.create')) {
if (!get(dbConfig, 'config.newDbName')) {
return { err: 'please input database info' };
}
const { Schema: schema } = await this.DbModel.findOne({
include: [
{
model: Schema,
required: false,
right: true,
},
],
where: {
'$Schema.id$': dbConfig.schemaId,
},
paranoid: false,
attributes: [],
});
const { tableDict, linkDict } = get(schema, 'dataValues.graph', {
tableDict: {},
linkDict: {},
});
const ddl = exportSQL(
tableDict,
linkDict,
// get(dbConfig, 'config.newDbType'),
);
const { client, host, port, user, password, database, newDbName }: any =
dbConfig.config;
if (ddl && get(dbConfig.config, 'newDbName')) {
await this.createDatabaseAndExecuteDDL(
{
client: client,
asyncStackTraces: true,
debug: true,
connection: {
host: host,
port: port,
user: user,
password: password,
database: database,
},
},
ddl,
newDbName,
);
}
}
const saveConfig = {
...dbConfig,
config: {
...dbConfig.config,
database: get(
dbConfig.config,
'newDbName',
get(dbConfig.config, 'newDbName', get(dbConfig.config, 'database')),
),
},
};
return this.DbModel.create(saveConfig);
}
async getSchemaAllDb(schemaId: Schema['id']): Promise<DB[]> {
return this.DbModel.findAll({
where: {
schemaId,
},
});
}
async deleteDb(id: DB['id']): Promise<{ id: DB['id'] }> {
await this.DbModel.destroy({
where: {
id,
},
});
return { id };
}
async testConnectDb(dbConfig: DB['config']) {
const { client, host, port, user, password, database } = dbConfig as any;
const db: Knex = this.knex.create({
client: client,
asyncStackTraces: true,
debug: true,
connection: {
host: host,
port: port,
user: user,
password: password,
database: database,
},
});
try {
await db.raw('SHOW TABLES;');
this.knex.destroy(db);
return {
status: 200,
};
} catch (err) {
console.log(err, 'err');
this.knex.destroy(db);
return {
err: '参数错误,连接失败',
status: 401,
};
}
}
async getDbDBML(config: Knex.Config) {
const { client, host, port, user, password, database }: any = config;
const db: Knex = this.knex.create({
client: client,
asyncStackTraces: true,
debug: true,
connection: {
host: host,
port: port,
user: user,
password: password,
database: database,
},
});
try {
const data = await generateDbdiagramDsl(db);
this.knex.destroy(db);
return {
data: data,
status: 200,
};
} catch (err) {
console.log(err, 'err');
this.knex.destroy(db);
return {
err: '参数错误,连接失败',
status: 401,
};
}
}
async addQuery(query: Query) {
return this.QueryModel.create(
pick(query, 'name', 'content', 'schemaId', 'DbID'),
);
}
async updateQuery(queryId: string, functions: string) {
const query = await this.QueryModel.findByPk(queryId);
// query.content
const content: any = query.content;
return await query.update({
content: {
...content,
functions,
},
});
}
async getQueries(schemaId: Schema['id']) {
return this.QueryModel.findAll({
where: {
schemaId,
},
});
}
async deteteQuery(queryId: Query['id']) {
return this.QueryModel.destroy({
where: {
id: queryId,
},
});
}
async runQuery(queryId: string, params: Record<string, any>, type?) {
const query = await this.QueryModel.findByPk(queryId);
console.log(query.content);
const data = await this.executeQuery({
config: params,
execution: get(query.content, 'executions'),
dbID: query.DbID,
});
if (type === '1') {
let result = [];
console.log(data, 'data');
get(data, 'data', []).map((item) => {
item.map((v) => {
result = result.concat(get(v, '0'));
});
});
console.log(result);
return result;
}
return data;
}
}
import { Module, Controller } from '@nestjs/common';
import { QueriesService } from './index.service';
import { QueriesController } from './index.controller';
import { SequelizeModule } from '@nestjs/sequelize';
import { Query } from './Query.model';
import { DB } from './DB.model';
@Module({
imports: [SequelizeModule.forFeature([Query, DB])],
providers: [QueriesService],
controllers: [QueriesController],
})
export class QueriesModel {}
import {
Table,
Column,
Model,
PrimaryKey,
DataType,
Comment,
Default,
AllowNull,
BelongsTo,
ForeignKey,
} from 'sequelize-typescript';
import { Schema } from './schema.model';
@Table
export class SchemaLog extends Model {
@PrimaryKey
@Comment('id')
@Default(DataType.UUIDV4)
@Column(DataType.UUID)
id: string;
@BelongsTo(() => Schema, {
foreignKey: 'schemaId',
})
Schema: string;
@ForeignKey(() => Schema)
@Column(DataType.UUID)
schemaId: string;
@Comment('模型名称')
@AllowNull(false)
@Column
name: string;
@Comment('模型结构')
@AllowNull(false)
@Column({
type: DataType.JSON,
})
graph: string;
createdAt: Date;
updatedAt: Date;
DeletedAt: Date;
}
import {
Body,
Controller,
Delete,
Get,
Next,
Param,
Post,
Put,
} from '@nestjs/common';
import { SchemaService } from './index.service';
import { Schema } from './schema.model';
import { get } from 'lodash';
import { SchemaLog } from './SchemaLog.model';
@Controller('schema')
export class SchemaController {
constructor(private service: SchemaService) {}
@Get('/all')
async findAll() {
return this.service.getAll();
}
@Get('/:id')
async getSchemaById(@Param('id') id) {
return this.service.findSchema(id);
}
@Post('/create')
async create(@Body() body) {
const { dataValues } = await this.service.addSchema(body);
return dataValues;
}
@Delete('/:id')
async delete(@Param('id') id) {
return await this.service.removeSchema(id);
}
@Put('/:id')
save(
@Param('id') id,
@Body('graph') body,
@Body('name') name,
): Promise<Schema> {
return this.service.updateSchema(id, body, name);
}
@Get('/getLogs/:id')
async getLogsbySchemaId(@Param('id') id): Promise<SchemaLog> {
const res = await this.service.getSchemaLogsById(id);
return get(res, 'dataValues.schemaLogs');
}
@Delete('/getLogs/:id')
async deleteLogsbySchemaId(@Param('id') id) {
return await this.service.deleteSchemaLogsById(id);
}
}
import { Injectable } from '@nestjs/common';
import { Schema } from './schema.model';
import { InjectModel } from '@nestjs/sequelize';
import { executeRes } from 'src/utils/response/sequeilze';
import { SchemaLog } from './SchemaLog.model';
import { get, omit } from 'lodash';
import { async } from 'rxjs';
import export_dbml from 'src/utils/knex/export-dbml';
import { GET_SCHEMA_INFO } from 'src/utils/prompts/schema';
@Injectable()
export class SchemaService {
constructor(
@InjectModel(Schema) private SchemaModel: typeof Schema,
@InjectModel(SchemaLog) private SchemaLogModel: typeof SchemaLog,
) {}
async addSchema(body: Pick<Schema, 'name' | 'graph'>): Promise<Schema> {
return await executeRes(() => this.SchemaModel.create(body));
}
async findSchema(id: string): Promise<Schema> {
const schema = await this.SchemaModel.findByPk(id);
if (!schema.description) {
this.updateSchema(schema.id, schema.graph, schema.name);
}
return await executeRes(() => this.SchemaModel.findByPk(id));
}
async getAll(): Promise<Schema[]> {
return await executeRes(() => this.SchemaModel.findAll());
}
async removeSchema(id: string): Promise<{
id: Schema['id'];
}> {
return executeRes(async () => {
const num = await this.SchemaModel.destroy({
where: {
id: id,
},
});
console.log(num);
return { id: id };
});
}
async updateSchema(
id: string,
graph: Schema['graph'],
name: Schema['name'],
): Promise<Schema> {
const schema = await this.SchemaModel.findByPk(id);
//添加日志、
await this.SchemaLogModel.create({
...omit(get(schema, 'dataValues'), 'id'),
schemaId: get(schema, 'dataValues.id'),
});
const { tableDict, linkDict } = (graph as any) || {
tableDict: {},
linkDict: {},
};
const dbml = export_dbml(tableDict, linkDict);
const description = await GET_SCHEMA_INFO.run(dbml);
return executeRes(() =>
schema.update({
name,
graph,
description,
}),
);
}
async getSchemaLogsById(id: string): Promise<Schema[]> {
const resuts = await executeRes(
async () =>
await executeRes(() =>
this.SchemaModel.findOne({
where: {
id,
},
attributes: [],
include: [SchemaLog],
}),
),
);
return resuts;
}
async deleteSchemaLogsById(id: string): Promise<{
id: string;
}> {
await this.SchemaLogModel.destroy({
where: {
id,
},
});
return { id: id };
}
}
import { Module } from '@nestjs/common';
import { SchemaController } from './index.controller';
import { SchemaService } from './index.service';
import { SequelizeModule } from '@nestjs/sequelize';
import { Schema } from './schema.model';
import { SchemaLog } from './SchemaLog.model';
@Module({
imports: [SequelizeModule.forFeature([Schema, SchemaLog])],
controllers: [SchemaController],
providers: [SchemaService],
})
export class SChemaModel {}
import {
Table,
Column,
Model,
CreatedAt,
UpdatedAt,
DeletedAt,
PrimaryKey,
DataType,
Comment,
Default,
AllowNull,
HasMany,
} from 'sequelize-typescript';
import { SchemaLog } from './SchemaLog.model';
@Table
export class Schema extends Model {
@PrimaryKey
@Comment('id')
@Default(DataType.UUIDV4)
@Column(DataType.UUID)
id: string;
@HasMany(() => SchemaLog, {
foreignKey: 'schemaId',
sourceKey: 'id',
})
schemaLogs: SchemaLog[];
@Comment('模型名称')
@AllowNull(false)
@Column
name: string;
@Comment('模型结构')
@AllowNull(false)
@Column({
type: DataType.JSON,
})
graph: typeof DataType.JSON;
@Comment('模型描述')
@AllowNull(true)
@Column({
type: DataType.STRING(10000),
})
description: string;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
@DeletedAt
DeletedAt: Date;
}
import { config } from 'dotenv';
import { ChatOpenAI } from 'langchain/chat_models/openai';
import { OpenAI } from 'langchain/llms/openai';
config();
export const openAIApiKey = process.env['OPEN_AI_API_KEY'];
export const modelName = process.env['MODEL_NAME'];
export const basePath = process.env['BASE_URL'];
export function getOpenAi() {
return new OpenAI(
{
modelName: modelName,
openAIApiKey: openAIApiKey,
temperature: 0,
},
{
basePath: basePath,
},
);
}
export function getChatOpenAi() {
return new ChatOpenAI(
{
modelName: modelName,
openAIApiKey: openAIApiKey,
temperature: 0,
},
{
basePath: basePath,
},
);
}
import { Knex as KnexType } from 'knex';
export async function generateDbdiagramDsl(
knexInstance: KnexType,
): Promise<string> {
const dbType = knexInstance.client.config.client;
const isOracle = dbType === 'oracledb';
const databaseName = isOracle
? knexInstance.client.config.connection.user.toUpperCase()
: knexInstance.client.config.connection.database;
const tables = isOracle
? await knexInstance('all_tables')
.select('table_name')
.where('owner', '=', databaseName)
: await knexInstance('information_schema.tables')
.select('table_name')
.where('table_schema', '=', databaseName);
let dsl = '';
for (const table of tables) {
const table_name = table['TABLE_NAME'] || table['table_name'];
dsl += `Table "${table_name}" {\n`;
// console.log(databaseName,table_name)
const columns = isOracle
? await knexInstance('all_tab_columns')
.select('column_name', 'data_type')
.where('table_name', '=', table_name)
.andWhere('owner', '=', databaseName)
: await knexInstance('information_schema.columns')
.select('column_name', 'data_type', 'column_key')
.where('table_name', table_name)
.andWhere('table_schema', databaseName);
const foreignKeys = isOracle
? await knexInstance('all_cons_columns')
.select('column_name', 'r_constraint_name')
.where('table_name', '=', table_name)
.andWhere('owner', '=', databaseName)
.whereIn('constraint_name', function () {
this.select('constraint_name')
.from('all_constraints')
.where('constraint_type', '=', 'R')
.andWhere('table_name', '=', table_name)
.andWhere('owner', '=', databaseName);
})
: await knexInstance('information_schema.key_column_usage')
.select(
'column_name',
'referenced_table_name',
'referenced_column_name',
)
.where('table_name', '=', table_name)
.andWhere('table_schema', '=', databaseName)
.andWhereRaw('referenced_table_name IS NOT NULL');
const flag: Record<string, any> = {};
for (const item of foreignKeys) {
const column_name = item['COLUMN_NAME'] || item['column_name'];
const referenced_table_name =
item['REFERENCED_TABLE_NAME'] || item['referenced_table_name'];
const referenced_column_name =
item['REFERENCED_COLUMN_NAME'] || item['referenced_column_name'];
const data_type = item['DATA_TYPE'] || item['data_type'];
if (isOracle) {
const refInfo = await knexInstance('all_constraints')
.select('table_name', 'column_name')
.where('constraint_name', '=', referenced_table_name)
.andWhere('owner', '=', databaseName)
.first();
if (refInfo) {
dsl += ` "${column_name}" ${data_type.toUpperCase()} [ref: > ${referenced_table_name}.${referenced_column_name}]\n`;
}
} else {
const columnInfo = columns.find(
(column) =>
(column.COLUMN_NAME || column.column_name) === column_name,
);
const data_type = columnInfo
? columnInfo.DATA_TYPE || columnInfo.data_type
: '';
// 处理外键关系的代码
dsl += ` "${column_name}" ${data_type.toUpperCase()} [ref: > "${referenced_table_name}.${referenced_column_name}"]\n`;
}
flag[column_name] = true;
}
for (const col of columns) {
const column_name = col.COLUMN_NAME || col.column_name;
const data_type = col.DATA_TYPE || col.data_type;
const column_key = col.COLUMN_KEY || col.column_key;
if (!flag[column_name])
dsl += ` "${column_name}" ${data_type.toUpperCase()}${
column_key === 'PRI' ? ' [pk]' : ''
}\n`;
}
// console.log(await knexInstance('information_schema.key_column_usage'), 'foreignKeys');
dsl += '}\n\n';
}
// console.log('generateDbdiagramDsl', dsl);
return dsl;
}
import { Knex } from 'knex';
export const disableConstraints = {
mysql: 'SET FOREIGN_KEY_CHECKS = 0;',
mysql2: 'SET FOREIGN_KEY_CHECKS = 0;',
sqlServer: 'ALTER TABLE table_name NOCHECK CONSTRAINT ALL;',
postgresql: 'SET CONSTRAINTS ALL DEFERRED;',
oracle: 'ALTER TABLE table_name DISABLE ALL TRIGGERS;',
};
// Enable foreign key constraints for different databases
export const enableConstraints = {
mysql: 'SET FOREIGN_KEY_CHECKS = 1;',
mysql2: 'SET FOREIGN_KEY_CHECKS = 1;',
sqlServer: 'ALTER TABLE table_name CHECK CONSTRAINT ALL;',
postgresql: '', // Constraints will be enabled automatically at the end of the transaction
oracle: 'ALTER TABLE table_name ENABLE ALL TRIGGERS;',
};
const annotationMatching = /(--.*)|(((\/\*)+?[\w\W]+?(\*\/)+))/g;
export async function executeSQLWithDisabledForeignKeys(
kenx: Knex,
sqlArray: string[],
params: any[][] = [],
) {
try {
// Disable foreign key constraints for different databases
// Replace 'databaseType' with the actual type of your database (e.g., 'mysql', 'sqlServer', etc.)
const databaseType = kenx.client.config.client;
// Disable foreign key constraints
console.log(disableConstraints[databaseType]);
await kenx.schema.raw(disableConstraints[databaseType]);
// Execute the main SQL query
const result = [];
for (const index in sqlArray) {
result.push(
// ${sql}
await (kenx.schema.raw as any)(
sqlArray[index].replace(annotationMatching, ''),
params[index],
),
);
}
return result;
} catch (error) {
console.error('执行失败☹️:', error);
} finally {
const databaseType = kenx.client.config.client;
await kenx.schema.raw(enableConstraints[databaseType]);
}
}
import { ModelExporter, Parser, exporter } from '@dbml/core';
import { readFileSync, writeFileSync } from 'fs';
/**
* It takes a table dictionary and a link dictionary and returns a SQL string
* @param tableDict - a dictionary of tables, where the key is the table ID and the value is the tableobject
* @param linkDict - a dictionary of links, where the key is the link id and the value is the linkobject
* @param [databaseType=postgres] - The type of database you want to export to.
* @returns dbml string.
*/
const export_dbml = (
tableDict: any,
linkDict: any,
databaseType: 'postgres' | 'mysql' | 'dbml' | 'mssql' | 'json' = 'mysql',
) => {
const combined = {
name: 'public',
note: '',
tables: Object.values(tableDict || {}).map((table: any) => {
return {
name: table.name,
note: table.note,
fields: table.fields.map((field) => {
return {
...field,
type: {
// To lower case because of typing 'BIGINT' with upper case and increment get wrong pg sql type when export
type_name: field.type.toLowerCase(),
args: null,
},
};
}),
};
}),
enums: [],
tableGroups: [],
refs: Object.values(linkDict || {}).map((ref: any) => {
return {
...ref,
endpoints: ref.endpoints.map((endpoint) => {
return {
...endpoint,
tableName: tableDict[endpoint.id].name,
fieldNames: [
tableDict[endpoint.id].fields.find(
(field) => field.id == endpoint.fieldId,
).name,
],
};
}),
};
}),
};
const database = Parser.parse(combined as any, 'json');
const dbml = ModelExporter.export(database, 'dbml', false);
return dbml;
};
export default export_dbml;
import { ModelExporter, Parser, exporter } from '@dbml/core';
import { readFileSync, writeFileSync } from 'fs';
/**
* It takes a table dictionary and a link dictionary and returns a SQL string
* @param tableDict - a dictionary of tables, where the key is the table ID and the value is the tableobject
* @param linkDict - a dictionary of links, where the key is the link id and the value is the linkobject
* @param [databaseType=postgres] - The type of database you want to export to.
* @returns SQL string.
*/
const exportSQL = (
tableDict: any,
linkDict: any,
databaseType: 'postgres' | 'mysql' | 'dbml' | 'mssql' | 'json' = 'mysql',
) => {
const combined = {
name: 'public',
note: '',
tables: Object.values(tableDict || {}).map((table: any) => {
return {
name: table.name,
note: table.note,
fields: table.fields.map((field) => {
return {
...field,
type: {
// To lower case because of typing 'BIGINT' with upper case and increment get wrong pg sql type when export
type_name: field.type.toLowerCase(),
args: null,
},
};
}),
};
}),
enums: [],
tableGroups: [],
refs: Object.values(linkDict || {}).map((ref: any) => {
return {
...ref,
endpoints: ref.endpoints.map((endpoint) => {
return {
...endpoint,
tableName: tableDict[endpoint.id].name,
fieldNames: [
tableDict[endpoint.id].fields.find(
(field) => field.id == endpoint.fieldId,
).name,
],
};
}),
};
}),
};
const database = Parser.parse(combined as any, 'json');
const dbml = ModelExporter.export(database, 'dbml', false);
const sql = exporter.export(dbml, databaseType);
// console.log(sql);
// writeFileSync('./test.sql', sql);
return sql.split(/\n\s*\n/);
};
export default exportSQL;
import { Global, Injectable, Module } from '@nestjs/common';
import { randomUUID } from 'crypto';
import knex, { Knex } from 'knex';
import { get, set } from 'lodash';
@Injectable()
export class KnexContainer {
knexs = new Map();
create(config: Knex.Config, id?: string) {
const db = knex(config);
this.add(db, id);
return db;
}
add(kenx: Knex, id?: string) {
const key = id || randomUUID();
this.knexs.set(key, {
db: kenx,
});
set(kenx, '_key_', key);
}
get(id: string) {
let client;
if (!(client = this.knexs.get(id))) {
// client = create();
//Todo
}
return client?.db;
}
async destroy(key: string | Knex) {
const id = get(key || { _key_: key }, '_key_');
const client = this.get(id);
console.log(this.knexs.has(id));
if (client) {
await client.destroy();
this.knexs.delete(id);
}
console.log('db pools', id, this.knexs.size);
}
getAll() {
return this.knexs.values();
}
}
@Global()
@Module({
providers: [KnexContainer],
exports: [KnexContainer],
})
export class Kenx {}
import { Injectable } from '@nestjs/common';
import { OpenAI } from 'langchain/llms/openai';
class LangChain {
model = new OpenAI({ openAIApiKey: 'sk-...', temperature: 0.9 });
}
export function extractCodeBlocks(markdownText, lang = null) {
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
const codeBlocks = [];
let match;
while ((match = codeBlockRegex.exec(markdownText)) !== null) {
if (lang === null || match[1] === lang) {
codeBlocks.push(match[2]);
}
}
return codeBlocks;
}
import {
ChatPromptTemplate,
HumanMessagePromptTemplate,
SystemMessagePromptTemplate,
} from 'langchain/prompts';
import { z } from 'zod';
import { getChatOpenAi } from '../Ai';
import { createStructuredOutputChainFromZod } from 'langchain/chains/openai_functions';
const model = getChatOpenAi();
const zodSchema = z.object({
answerMeetsRequirements: z
.boolean()
.describe('判断沟通记录中给出的答案是否满足你最后一条记录中的需求'),
why: z
.string()
.describe(
'你现在是用户,下一次你将输入什么内容(中文)保证上面你最后一条记录中的需求能被正确的被理解。',
),
});
const prompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate(`沟通记录:\n
{messageList}
`),
HumanMessagePromptTemplate.fromTemplate(
`你需要谨慎查看这个沟通记录,你扮演对话中的用户, 对比需求和回答,以判断你最后一条记录中的需求是否被正确理解且能被正确解决。
如果需求和答案没有对齐,你现在是用户,下一次你将输入什么内容(中文)保证上面你最后一条记录中的需求能被正确的被理解。`,
),
]);
export const GET_CHECK_RESULT = createStructuredOutputChainFromZod(zodSchema, {
llm: model,
prompt,
});
import { OpenAI } from 'langchain/llms/openai';
import { PromptTemplate } from 'langchain/prompts';
import { LLMChain } from 'langchain/chains';
import { getOpenAi } from '../Ai';
const model = getOpenAi();
const prompt = PromptTemplate.fromTemplate(
`作为js代码编程专家,你需要分析我的需求,请你编写一个函数处理我的需求并返回我的需要的结果,这个是固定第一个入参:
{data}。
需求:
{need}。
请按照需求生成代码之后,将结果按照以下模版中的标签中的内容进行分析并且替换模版中标签的内容(必须保留标签)作为最后结果输出:
<FunctionDescription>该函数描述说明</FunctionDescription>
<FunctionName>函数名称</FunctionName>
<FunctionCode>函数代码</FunctionCode>
<FunctionExample>函数实例</FunctionExample>
`,
);
export const GET_FUNCTION_CODE_CHAIN = new LLMChain({ llm: model, prompt });
import { OpenAI } from 'langchain/llms/openai';
import {
AIMessagePromptTemplate,
ChatPromptTemplate,
HumanMessagePromptTemplate,
} from 'langchain/prompts';
import { LLMChain } from 'langchain/chains';
import { getChatOpenAi } from '../Ai';
const model = getChatOpenAi();
export const defaultScope = `
{
data,
import: {
'styled-components':{
'描述':'A css in js Framework,Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress'
},
'echarts':{
'描述':'Apache ECharts is a powerful, interactive charting and data visualization library for browser.',
'用法': "import echarts from 'echarts';"
},
'echarts-for-react':{
'描述':'Apache ECharts is a powerful, interactive charting and data visualization library for browser.',
'用法': "import React from 'react';
import ReactECharts from 'echarts-for-react'; // or var ReactECharts = require('echarts-for-react');
<ReactECharts
option={this.getOption()}
notMerge={true}
lazyUpdate={true}
theme={"theme_name"}
onChartReady={this.onChartReadyCallback}
onEvents={EventsDict}
opts={}
/>"
},
},
}
`;
export const fxTepmlate = `export default App() {
const props = data;
...
}`;
const Messages_1 =
HumanMessagePromptTemplate.fromTemplate(`我正在使用react-live作为一个实时编辑和编译React组件的工具。请根据我的需求,输出一段能在react-live运行的代码,只需要导出默认组件,不用挂载dom。可用的作用域如下:
{scope}
其中import可供导入的库,除此之外不能使用其它第三方库。 key为包名,value 是包的描述。其它每个属性将作为单独全局变量,变量名为属性名。请确保默认导出的组件接受null作为参数,并将传入props取自模块全局作用域变量data(const props = data),全局变量变量data会自动注入,请不要进行声明。例如:
{fxTepmlate}
`);
const Messages_2 =
AIMessagePromptTemplate.fromTemplate(`好的我明白啦,请问你的业务是什么?`);
const Messages_3 = HumanMessagePromptTemplate.fromTemplate(
`这是我传入的props:{props}。{need}`,
);
const prompt = ChatPromptTemplate.fromPromptMessages([
Messages_1,
Messages_2,
Messages_3,
]);
export const GET_COMPONENT_BY_DATA = new LLMChain({ llm: model, prompt });
import { OpenAI } from 'langchain/llms/openai';
import { PromptTemplate } from 'langchain/prompts';
import { LLMChain } from 'langchain/chains';
import { getOpenAi } from '../Ai';
const model = getOpenAi();
const prompt = PromptTemplate.fromTemplate(
`作为一个数据模型业务分析专家,您需要根据当前数据模型(DBML格式)进行精确的分析,根据模型的提供的信息,分析该模型并输出简要描述。当前数据库模型为:
<dbml>
{sql}
</dbml>`,
);
export const GET_SCHEMA_INFO = new LLMChain({ llm: model, prompt });
export async function executeRes(fx: () => any) {
let result;
try {
result = await fx();
} catch (err) {
result = { dataValues: err };
}
console.log('result', result, 'result');
return result;
}
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}
import { GET_CHECK_RESULT } from 'src/utils/prompts/checkSql';
async function test() {
const result = await GET_CHECK_RESULT.call({
messageList: `[
{
"role": "system",
"content": "IMPRTANT: You are a virtual assistant powered by the gpt-3.5-turbo model, now time is 2023/5/30 16:57:14}"
},
{
"role": "user",
"content": "作为一个数据库模型业务分析专家,您需要根据当前数据库模型(DBML格式)生成对应的 MySQL 数据库可执行的 SQL 文本,并列出执行该 SQL 所需的变量及其解释,最后为此条查询命名。当前数据库模型为:\n\ndbml\nTable "orders" {\n "id" int [pk, increment]\n "patient_id" int\n "doctor_id" int\n "appointment_date" timestamp\n "status" varchar\n}\n\nTable "doctors" {\n "id" int [pk, increment]\n "department_id" int\n "name" varchar\n "specialization" varchar\n "phone_number" varchar\n "email" varchar\n}\n\nTable "patients" {\n "id" int [pk, increment]\n "name" varchar\n "gender" varchar\n "age" int\n "phone_number" varchar\n "email" varchar\n "address" varchar\n}\n\nTable "departments" {\n "id" int [pk, increment]\n "hospital_id" int\n "name" varchar\n "description" varchar\n}\n\nTable "hospitals" {\n "id" int [pk, increment]\n "name" varchar\n "address" varchar\n "phone_number" varchar\n "created_at" timestamp\n}\n\nRef:"doctors"."id" < "orders"."doctor_id"\n\nRef:"patients"."id" < "orders"."patient_id"\n\nRef:"hospitals"."id" < "departments"."hospital_id"\n\nRef:"departments"."id" < "doctors"."department_id"\n\n\n\n请按照需求生成结果之后,将结果按照xml语法,将模版中的标签中的内容进行分析(需要用户填入的信息作为变量,如果需要变量:变量的命名必须请放在
和之间,例如:
tab、
name...)。:\n\n根据您提供的数据库模型,已为您生成查询:\n<sql>按照需要生产的sql语句</sql>\n\n执行所需变量:\n\n判断解决当前问题的查询执行时是否需要变量。若不需要变量,则无需提供任何信息。 若条件成立,请使用:\n<var>
执行
所需变量名称
执行SQL所需变量名称</var>: <varDescription>变量解释</varDescription>\n\n查询命名和描述:\n<queryName>查询名称</queryName>\n<queryDescription>查询描述</queryDescription>\n"
},
{
"role": "system",
"content": "你第一步应该思考分析:用户是否指定生成模拟数据,如果有,你还需要生成模拟数据,你第二步应该思考分析:用户需求中是否需要变量(例如:生成模拟数据就不需要变量,因为数据由你生成),如果需要变量:变量的命名必须请放在
和之间,例如:"variablesArr": [\n {\n "variable": "
variable",\n "varDescription": "这个变量的描述"\n }):\n "
},
{
"role": "assistant",
"content": "好的,我明白了。请问你的业务是什么?"
},
{
"role": "user",
"content": "分析数据库,添加一批中文的模拟数据10-15条"
},
{
"role": "assistant",
"content": "",
"function_call": {
"name": "saveExecuteSqlInfo",
"arguments": "{\n "simulation": true,\n "sql": "INSERT INTO orders (patient_id, doctor_id, appointment_date, status) VALUES (1, 1, '2023-05-30 10:00:00', '待确认'), (2, 2, '2023-05-31 14:30:00', '已确认'), (3, 3, '2023-06-01 09:15:00', '已取消'), (4, 4, '2023-06-02 16:45:00', '已完成'), (5, 5, '2023-06-03 11:30:00', '待确认'), (6, 6, '2023-06-04 13:00:00', '已确认'), (7, 7, '2023-06-05 15:45:00', '已取消'), (8, 8, '2023-06-06 10:30:00', '已完成'), (9, 9, '2023-06-07 12:15:00', '待确认'), (10, 10, '2023-06-08 14:00:00', '已确认')",\n "queryName": "添加模拟数据",\n "queryDescription": "向订单表中添加10条模拟数据"\n}"
}
}
]`,
});
console.log(result, 'result');
}
describe('checkSql', () => {
test();
});
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "packages/**"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"paths": {
"@dbml/core": ["../packages/dbml/packages/dbml-core"]
}
},
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment