init base app modules
This commit is contained in:
commit
d96c342d3e
68
.gitignore
vendored
Normal file
68
.gitignore
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
node_modules
|
||||||
|
|
||||||
|
# mac
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
.env*
|
||||||
|
!.env*example
|
||||||
|
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
logs
|
||||||
|
|
||||||
|
.turbo
|
||||||
|
|
||||||
|
pack-dist
|
||||||
|
|
||||||
|
# astro
|
||||||
|
.astro
|
||||||
|
|
||||||
|
# next
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# vuepress
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# coverage
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# debug logs
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# vscode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# idea
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# system
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# temp files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# local development
|
||||||
|
*.local
|
||||||
|
|
||||||
|
public/r
|
||||||
|
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
|
storage/
|
3
.npmrc
Normal file
3
.npmrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
|
||||||
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||||
|
ignore-workspace-root-check=true
|
25
apps/aliyun-ai/bun.config.mjs
Normal file
25
apps/aliyun-ai/bun.config.mjs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// @ts-check
|
||||||
|
import { resolvePath } from '@kevisual/use-config/env';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const entry = 'src/index.ts';
|
||||||
|
const naming = 'app';
|
||||||
|
const external = ['sequelize', 'pg', 'sqlite3', 'minio', '@kevisual/router', 'pm2'];
|
||||||
|
/**
|
||||||
|
* @type {import('bun').BuildConfig}
|
||||||
|
*/
|
||||||
|
await Bun.build({
|
||||||
|
target: 'node',
|
||||||
|
format: 'esm',
|
||||||
|
entrypoints: [resolvePath(entry, { meta: import.meta })],
|
||||||
|
outdir: resolvePath('./dist', { meta: import.meta }),
|
||||||
|
naming: {
|
||||||
|
entry: `${naming}.js`,
|
||||||
|
},
|
||||||
|
external: external,
|
||||||
|
env: 'KEVISUAL_*',
|
||||||
|
});
|
||||||
|
|
||||||
|
// const cmd = `dts -i src/index.ts -o app.d.ts`;
|
||||||
|
// const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
|
||||||
|
// execSync(cmd, { stdio: 'inherit' });
|
27
apps/aliyun-ai/package.json
Normal file
27
apps/aliyun-ai/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "aliyun-ai",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"basename": "/root/aliyun-ai",
|
||||||
|
"app": {
|
||||||
|
"key": "aliyun-ai",
|
||||||
|
"entry": "dist/app.js",
|
||||||
|
"type": "system-app"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/dev.ts ",
|
||||||
|
"build": "rimraf dist && bun run bun.config.mjs",
|
||||||
|
"clean": "rm -rf dist",
|
||||||
|
"pub": "npm run build && envision pack -p -u"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
|
"license": "MIT",
|
||||||
|
"packageManager": "pnpm@10.12.1",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
4
apps/aliyun-ai/src/app.ts
Normal file
4
apps/aliyun-ai/src/app.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { app } from '@/modules/router.ts';
|
||||||
|
import { oss } from '@/modules/minio.ts';
|
||||||
|
import { config } from '@/modules/config.ts';
|
||||||
|
export { app, config, oss };
|
6
apps/aliyun-ai/src/dev.ts
Normal file
6
apps/aliyun-ai/src/dev.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { app } from './index.ts';
|
||||||
|
|
||||||
|
app.listen(4000, () => {
|
||||||
|
console.log('Server is running on http://localhost:4000');
|
||||||
|
console.log('Press Ctrl+C to stop the server');
|
||||||
|
});
|
5
apps/aliyun-ai/src/index.ts
Normal file
5
apps/aliyun-ai/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { app } from './app.ts';
|
||||||
|
|
||||||
|
import './routes/create-audio.ts';
|
||||||
|
|
||||||
|
export { app };
|
75
apps/aliyun-ai/src/routes/create-audio.ts
Normal file
75
apps/aliyun-ai/src/routes/create-audio.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { app, config, oss } from '../app.ts';
|
||||||
|
import { dashscopeTTS } from '@/examples/dash-scope/tts.ts';
|
||||||
|
import { randomLetter } from '@/utils/random.ts';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
type DashScopeTTSResponse = {
|
||||||
|
output?: {
|
||||||
|
finish_reason?: string;
|
||||||
|
audio?: {
|
||||||
|
expires_at?: number;
|
||||||
|
data?: string;
|
||||||
|
id?: string;
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
usage?: {
|
||||||
|
input_tokens_details?: {
|
||||||
|
text_tokens?: number;
|
||||||
|
};
|
||||||
|
total_tokens?: number;
|
||||||
|
output_tokens?: number;
|
||||||
|
input_tokens?: number;
|
||||||
|
output_tokens_details?: {
|
||||||
|
audio_tokens?: number;
|
||||||
|
text_tokens?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
request_id?: string;
|
||||||
|
};
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'aliyun-ai',
|
||||||
|
key: 'createVideos',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const { text, model, save = 'none' } = ctx.query;
|
||||||
|
if (!text) {
|
||||||
|
ctx.throw(400, 'Text and model are required parameters');
|
||||||
|
}
|
||||||
|
const value: DashScopeTTSResponse = await dashscopeTTS({
|
||||||
|
text,
|
||||||
|
voice: model || 'Chelsie',
|
||||||
|
token: config.BAILIAN_API_KEY,
|
||||||
|
});
|
||||||
|
const url = value?.output?.audio?.url;
|
||||||
|
const fileName = `audio-${randomLetter(32)}.wav`;
|
||||||
|
const username = 'share';
|
||||||
|
const today = dayjs().format('YYYY-MM-DD');
|
||||||
|
// 使用用户名和日期作为文件夹路径
|
||||||
|
const filePath = `${username}/storage/aliyun-ai/audio/${today}/${fileName}`;
|
||||||
|
if (url) {
|
||||||
|
ctx.body = {
|
||||||
|
audioUrl: url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (save === 'minio' && url) {
|
||||||
|
// 读取文件url地址的数据,并保存到 MinIO, 文件是 音频 wave 格式
|
||||||
|
const audioData = await fetch(url).then((res) => res.arrayBuffer());
|
||||||
|
|
||||||
|
// 将音频数据转换为 Buffer 并上传到 MinIO
|
||||||
|
const buffer = Buffer.from(audioData);
|
||||||
|
await oss.client.putObject(oss.bucketName, filePath, buffer, null, {
|
||||||
|
'Content-Type': 'audio/wav',
|
||||||
|
'app-source': 'aliyun-ai',
|
||||||
|
share: 'public',
|
||||||
|
});
|
||||||
|
console.log('Audio file uploaded to MinIO:', filePath);
|
||||||
|
// @ts-ignore
|
||||||
|
ctx.body.minio = filePath;
|
||||||
|
}
|
||||||
|
// 如果没有 url,抛出错误
|
||||||
|
if (!url) {
|
||||||
|
ctx.throw(500, 'Failed to create audio');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addTo(app);
|
25
bun.config.mjs
Normal file
25
bun.config.mjs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// @ts-check
|
||||||
|
import { resolvePath } from '@kevisual/use-config/env';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const entry = 'src/index.ts';
|
||||||
|
const naming = 'app';
|
||||||
|
const external = ['sequelize', 'pg', 'sqlite3', 'minio', '@kevisual/router', 'pm2'];
|
||||||
|
/**
|
||||||
|
* @type {import('bun').BuildConfig}
|
||||||
|
*/
|
||||||
|
await Bun.build({
|
||||||
|
target: 'node',
|
||||||
|
format: 'esm',
|
||||||
|
entrypoints: [resolvePath(entry, { meta: import.meta })],
|
||||||
|
outdir: resolvePath('./dist', { meta: import.meta }),
|
||||||
|
naming: {
|
||||||
|
entry: `${naming}.js`,
|
||||||
|
},
|
||||||
|
external: external,
|
||||||
|
env: 'KEVISUAL_*',
|
||||||
|
});
|
||||||
|
|
||||||
|
// const cmd = `dts -i src/index.ts -o app.d.ts`;
|
||||||
|
const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
|
||||||
|
execSync(cmd, { stdio: 'inherit' });
|
66
package.json
Normal file
66
package.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "ai-pages-services",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"basename": "/root/ai-pages-services",
|
||||||
|
"app": {
|
||||||
|
"key": "ai-pages-services",
|
||||||
|
"entry": "dist/app.js",
|
||||||
|
"type": "system-app"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 bun --watch src/dev.ts ",
|
||||||
|
"build": "rimraf dist && bun run bun.config.mjs",
|
||||||
|
"test": "tsx test/**/*.ts",
|
||||||
|
"clean": "rm -rf dist",
|
||||||
|
"pub": "npm run build && envision pack -p -u",
|
||||||
|
"cmd": "tsx cmd/index.ts "
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"types": "types/index.d.ts",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@kevisual/code-center-module": "0.0.23",
|
||||||
|
"@kevisual/router": "0.0.22",
|
||||||
|
"@kevisual/use-config": "^1.0.18",
|
||||||
|
"cookie": "^1.0.2",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"formidable": "^3.5.4",
|
||||||
|
"lodash-es": "^4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@kevisual/context": "^0.0.3",
|
||||||
|
"@kevisual/logger": "^0.0.4",
|
||||||
|
"@kevisual/oss": "^0.0.12",
|
||||||
|
"@kevisual/types": "^0.0.10",
|
||||||
|
"@kevisual/use-config": "^1.0.19",
|
||||||
|
"@types/bun": "^1.2.16",
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
|
"@types/formidable": "^3.4.5",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/node": "^24.0.3",
|
||||||
|
"commander": "^14.0.0",
|
||||||
|
"concurrently": "^9.1.2",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"inquire": "^0.4.8",
|
||||||
|
"ioredis": "^5.6.1",
|
||||||
|
"minio": "^8.0.5",
|
||||||
|
"nanoid": "^5.1.5",
|
||||||
|
"nodemon": "^3.1.10",
|
||||||
|
"pg": "^8.16.1",
|
||||||
|
"rimraf": "^6.0.1",
|
||||||
|
"sequelize": "^6.37.7",
|
||||||
|
"tape": "^5.9.0",
|
||||||
|
"typescript": "^5.8.3"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.12.1"
|
||||||
|
}
|
2789
pnpm-lock.yaml
generated
Normal file
2789
pnpm-lock.yaml
generated
Normal file
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:
|
||||||
|
- 'apps/*'
|
30
src/examples/dash-scope/tts.ts
Normal file
30
src/examples/dash-scope/tts.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 使用DashScope API进行TTS (文本转语音) 请求
|
||||||
|
export const dashscopeTTS = async ({ text, voice = 'Chelsie', token }) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
// model: 'qwen-tts',
|
||||||
|
model: 'qwen-tts-latest',
|
||||||
|
input: {
|
||||||
|
text,
|
||||||
|
voice,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('TTS 请求失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
4
src/modules/config.ts
Normal file
4
src/modules/config.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { useConfig } from '@kevisual/use-config';
|
||||||
|
|
||||||
|
export const config = useConfig();
|
||||||
|
export const isDev = config.ENV === 'development';
|
6
src/modules/logger.ts
Normal file
6
src/modules/logger.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Logger } from '@kevisual/logger';
|
||||||
|
import { config } from './config.ts';
|
||||||
|
export const logger = new Logger({
|
||||||
|
level: config.LOG_LEVEL || 'info',
|
||||||
|
showTime: true,
|
||||||
|
});
|
41
src/modules/minio.ts
Normal file
41
src/modules/minio.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Client, ClientOptions } from 'minio';
|
||||||
|
import { config } from './config.ts';
|
||||||
|
import { OssBase } from '@kevisual/oss/services';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
const minioConfig = {
|
||||||
|
endPoint: config.MINIO_ENDPOINT || 'localhost',
|
||||||
|
port: parseInt(config.MINIO_PORT || '9000'),
|
||||||
|
useSSL: config.MINIO_USE_SSL === 'true',
|
||||||
|
accessKey: config.MINIO_ACCESS_KEY,
|
||||||
|
secretKey: config.MINIO_SECRET_KEY,
|
||||||
|
};
|
||||||
|
export const minioClient = useContextKey('minioClient', () => {
|
||||||
|
return new Client(minioConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bucketName = config.MINIO_BUCKET_NAME || 'resources';
|
||||||
|
if (!minioClient) {
|
||||||
|
throw new Error('Minio client not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const check = () => {
|
||||||
|
// 验证权限
|
||||||
|
(async () => {
|
||||||
|
const bucketExists = await minioClient.bucketExists(bucketName);
|
||||||
|
if (!bucketExists) {
|
||||||
|
await minioClient.makeBucket(bucketName);
|
||||||
|
}
|
||||||
|
console.log('bucketExists', bucketExists);
|
||||||
|
// const res = await minioClient.putObject(bucketName, 'root/test/0.0.1/a.txt', 'test');
|
||||||
|
// console.log('minio putObject', res);
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const oss = useContextKey(
|
||||||
|
'oss',
|
||||||
|
new OssBase({
|
||||||
|
client: minioClient,
|
||||||
|
bucketName: bucketName,
|
||||||
|
prefix: '',
|
||||||
|
}),
|
||||||
|
);
|
3
src/modules/notify.ts
Normal file
3
src/modules/notify.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const notify = () => {
|
||||||
|
//
|
||||||
|
};
|
38
src/modules/redis.ts
Normal file
38
src/modules/redis.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Redis } from 'ioredis';
|
||||||
|
import { config } from './config.ts';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
|
||||||
|
const redisConfig = {
|
||||||
|
host: config.REDIS_HOST || 'localhost',
|
||||||
|
port: parseInt(config.REDIS_PORT || '6379'),
|
||||||
|
password: config.REDIS_PASSWORD,
|
||||||
|
};
|
||||||
|
export const createRedisClient = (options = {}) => {
|
||||||
|
const redisClient = new Redis({
|
||||||
|
host: 'localhost', // Redis 服务器的主机名或 IP 地址
|
||||||
|
port: 6379, // Redis 服务器的端口号
|
||||||
|
// password: 'your_password', // Redis 的密码 (如果有)
|
||||||
|
db: 0, // 要使用的 Redis 数据库索引 (0-15)
|
||||||
|
keyPrefix: '', // key 前缀
|
||||||
|
retryStrategy(times) {
|
||||||
|
// 连接重试策略
|
||||||
|
return Math.min(times * 50, 2000); // 每次重试时延迟增加
|
||||||
|
},
|
||||||
|
maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试)
|
||||||
|
...redisConfig,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
redisClient.on('connect', () => {
|
||||||
|
console.log('Redis client connected successfully');
|
||||||
|
});
|
||||||
|
redisClient.on('error', (err) => {
|
||||||
|
console.error('Redis client error:', err);
|
||||||
|
});
|
||||||
|
return redisClient;
|
||||||
|
};
|
||||||
|
// 配置 Redis 连接
|
||||||
|
export const redis = useContextKey('redis', () => createRedisClient());
|
||||||
|
|
||||||
|
// 初始化 Redis 客户端
|
||||||
|
// export const redisPublisher = createRedisClient(); // 用于发布消息
|
||||||
|
// export const redisSubscriber = createRedisClient(); // 用于订阅消息
|
6
src/modules/router.ts
Normal file
6
src/modules/router.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { App } from '@kevisual/router';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
const init = () => {
|
||||||
|
return new App();
|
||||||
|
};
|
||||||
|
export const app = useContextKey('app', init);
|
34
src/modules/sequelize.ts
Normal file
34
src/modules/sequelize.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Sequelize } from 'sequelize';
|
||||||
|
import { config } from './config.ts';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
|
||||||
|
export type PostgresConfig = {
|
||||||
|
postgres: {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
database: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!config.POSTGRES_PASSWORD || !config.POSTGRES_USER) {
|
||||||
|
console.error('postgres config is required password and user');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const postgresConfig = {
|
||||||
|
username: config.POSTGRES_USER,
|
||||||
|
password: config.POSTGRES_PASSWORD,
|
||||||
|
host: config.POSTGRES_HOST || 'localhost',
|
||||||
|
port: parseInt(config.POSTGRES_PORT || '5432'),
|
||||||
|
database: config.POSTGRES_DB || 'postgres',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const init = async () => {
|
||||||
|
return new Sequelize({
|
||||||
|
dialect: 'postgres',
|
||||||
|
...postgresConfig,
|
||||||
|
// logging: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sequelize = useContextKey('sequelize', () => init());
|
9
src/modules/user.ts
Normal file
9
src/modules/user.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { sequelize, User, UserInit, Org, OrgInit } from '@kevisual/code-center-module';
|
||||||
|
|
||||||
|
export { sequelize, User, UserInit, Org, OrgInit };
|
||||||
|
|
||||||
|
export const init = () => {
|
||||||
|
UserInit();
|
||||||
|
OrgInit();
|
||||||
|
};
|
||||||
|
init();
|
26
src/utils/random.ts
Normal file
26
src/utils/random.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
|
||||||
|
export const letter = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
export const number = '0123456789';
|
||||||
|
const alphanumeric = `${letter}${number}`;
|
||||||
|
export const alphanumericWithDash = `${alphanumeric}-`;
|
||||||
|
export const uuid = customAlphabet(letter);
|
||||||
|
|
||||||
|
export const nanoid = customAlphabet(alphanumeric, 10);
|
||||||
|
|
||||||
|
export const nanoidWithDash = customAlphabet(alphanumericWithDash, 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个随机的 id,以字母开头的字符串
|
||||||
|
* @param number
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const randomId = (number: number) => {
|
||||||
|
const _letter = uuid(1);
|
||||||
|
return `${_letter}${nanoid(number)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const randomLetter = (number: number = 8, opts?: { before?: string; after?: string }) => {
|
||||||
|
const { before = '', after = '' } = opts || {};
|
||||||
|
return `${before}${uuid(number)}${after}`;
|
||||||
|
};
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "@kevisual/types/json/backend.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./node_modules/@kevisual"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
"apps/**/*",
|
||||||
|
],
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user