llm-chat/backend/utils/helpers.js

327 lines
6.3 KiB
JavaScript
Raw Normal View History

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
/**
* 生成随机字符串
*/
function generateRandomString(length = 32, charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') {
let result = '';
for (let i = 0; i < length; i++) {
result += charset.charAt(Math.floor(Math.random() * charset.length));
}
return result;
}
/**
* 生成UUID
*/
function generateUUID() {
return crypto.randomUUID();
}
/**
* 生成MD5哈希
*/
function generateMD5(data) {
return crypto.createHash('md5').update(data).digest('hex');
}
/**
* 生成SHA256哈希
*/
function generateSHA256(data) {
return crypto.createHash('sha256').update(data).digest('hex');
}
/**
* 延迟函数
*/
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 深度克隆对象
*/
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
if (typeof obj === 'object') {
const clonedObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
}
/**
* 格式化文件大小
*/
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
/**
* 格式化时间差
*/
function formatTimeDiff(startTime, endTime = Date.now()) {
const diff = endTime - startTime;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}${hours % 24}小时`;
if (hours > 0) return `${hours}小时${minutes % 60}分钟`;
if (minutes > 0) return `${minutes}分钟${seconds % 60}`;
return `${seconds}`;
}
/**
* 验证邮箱格式
*/
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
/**
* 验证URL格式
*/
function isValidURL(url) {
try {
new URL(url);
return true;
} catch {
return false;
}
}
/**
* 清理字符串移除HTML标签和特殊字符
*/
function sanitizeString(str) {
if (typeof str !== 'string') return '';
return str
.replace(/<[^>]*>/g, '') // 移除HTML标签
.replace(/[<>'"&]/g, '') // 移除危险字符
.trim();
}
/**
* 截断字符串
*/
function truncateString(str, maxLength, suffix = '...') {
if (typeof str !== 'string') return '';
if (str.length <= maxLength) return str;
return str.substring(0, maxLength - suffix.length) + suffix;
}
/**
* 检查文件是否存在
*/
function fileExists(filePath) {
try {
return fs.existsSync(filePath);
} catch {
return false;
}
}
/**
* 确保目录存在
*/
function ensureDirectoryExists(dirPath) {
try {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
return true;
} catch (error) {
console.error('创建目录失败:', error);
return false;
}
}
/**
* 读取JSON文件
*/
function readJSONFile(filePath) {
try {
const data = fs.readFileSync(filePath, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('读取JSON文件失败:', error);
return null;
}
}
/**
* 写入JSON文件
*/
function writeJSONFile(filePath, data) {
try {
const jsonString = JSON.stringify(data, null, 2);
fs.writeFileSync(filePath, jsonString, 'utf8');
return true;
} catch (error) {
console.error('写入JSON文件失败:', error);
return false;
}
}
/**
* 获取文件扩展名
*/
function getFileExtension(filename) {
return path.extname(filename).toLowerCase();
}
/**
* 获取文件名不含扩展名
*/
function getFileNameWithoutExtension(filename) {
return path.basename(filename, path.extname(filename));
}
/**
* 转换为驼峰命名
*/
function toCamelCase(str) {
return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
}
/**
* 转换为kebab命名
*/
function toKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
/**
* 防抖函数
*/
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
/**
* 节流函数
*/
function throttle(func, limit) {
let inThrottle;
return function executedFunction(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
/**
* 重试函数
*/
async function retry(fn, maxAttempts = 3, delay = 1000) {
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (attempt === maxAttempts) {
throw lastError;
}
console.warn(`尝试 ${attempt} 失败,${delay}ms后重试:`, error.message);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
/**
* 并行执行函数并限制并发数
*/
async function parallelLimit(tasks, limit = 5) {
const results = [];
const executing = [];
for (const task of tasks) {
const promise = Promise.resolve().then(() => task()).then(result => {
executing.splice(executing.indexOf(promise), 1);
return result;
});
results.push(promise);
if (results.length >= limit) {
executing.push(promise);
if (executing.length >= limit) {
await Promise.race(executing);
}
}
}
return Promise.all(results);
}
module.exports = {
generateRandomString,
generateUUID,
generateMD5,
generateSHA256,
delay,
deepClone,
formatFileSize,
formatTimeDiff,
isValidEmail,
isValidURL,
sanitizeString,
truncateString,
fileExists,
ensureDirectoryExists,
readJSONFile,
writeJSONFile,
getFileExtension,
getFileNameWithoutExtension,
toCamelCase,
toKebabCase,
debounce,
throttle,
retry,
parallelLimit
};