跳到主要内容

JavaScript AI生态

JavaScript已经成为AI应用开发的重要语言,拥有丰富的AI库、框架和工具链。本文将深入探讨JavaScript AI生态系统,帮助开发者选择合适的工具和技术栈。

JavaScript AI生态概览

生态系统架构

核心AI框架

1. TensorFlow.js

特点

  • Google开发的机器学习框架
  • 支持浏览器和Node.js
  • 预训练模型丰富
  • 支持自定义模型训练

核心功能实现

// TensorFlow.js核心功能封装
class TensorFlowManager {
constructor() {
this.models = new Map();
this.backend = 'webgl'; // 默认使用WebGL加速
this.initialized = false;
}

async initialize() {
if (this.initialized) return;

// 设置后端
await tf.setBackend(this.backend);
await tf.ready();

// 检查设备能力
const deviceInfo = this.getDeviceInfo();
console.log('TensorFlow.js initialized:', deviceInfo);

this.initialized = true;
}

getDeviceInfo() {
return {
backend: tf.getBackend(),
memory: tf.memory(),
environment: tf.env(),
flags: tf.env().flags
};
}

// 加载预训练模型
async loadPretrainedModel(modelName, modelUrl) {
if (this.models.has(modelName)) {
return this.models.get(modelName);
}

try {
const model = await tf.loadLayersModel(modelUrl);
this.models.set(modelName, {
model,
metadata: {
loadTime: Date.now(),
inputShape: model.inputs[0].shape,
outputShape: model.outputs[0].shape
}
});

return model;
} catch (error) {
console.error(`Failed to load model ${modelName}:`, error);
throw error;
}
}

// 图像分类示例
async classifyImage(modelName, imageElement) {
const modelInfo = this.models.get(modelName);
if (!modelInfo) {
throw new Error(`Model ${modelName} not loaded`);
}

const { model } = modelInfo;

// 预处理图像
const tensor = tf.browser.fromPixels(imageElement)
.resizeNearestNeighbor([224, 224])
.toFloat()
.div(255.0)
.expandDims();

// 执行推理
const predictions = await model.predict(tensor).data();

// 清理内存
tensor.dispose();

return this.postprocessPredictions(predictions);
}

// 自定义模型训练
async trainCustomModel(trainingData, modelConfig) {
const { inputs, outputs, architecture } = modelConfig;

// 构建模型架构
const model = tf.sequential();

architecture.forEach(layer => {
switch (layer.type) {
case 'dense':
model.add(tf.layers.dense({
units: layer.units,
activation: layer.activation,
inputShape: layer.inputShape
}));
break;
case 'conv2d':
model.add(tf.layers.conv2d({
filters: layer.filters,
kernelSize: layer.kernelSize,
activation: layer.activation
}));
break;
case 'maxPooling2d':
model.add(tf.layers.maxPooling2d({
poolSize: layer.poolSize
}));
break;
case 'flatten':
model.add(tf.layers.flatten());
break;
case 'dropout':
model.add(tf.layers.dropout({
rate: layer.rate
}));
break;
}
});

// 编译模型
model.compile({
optimizer: modelConfig.optimizer || 'adam',
loss: modelConfig.loss || 'categoricalCrossentropy',
metrics: modelConfig.metrics || ['accuracy']
});

// 准备训练数据
const xs = tf.tensor(inputs);
const ys = tf.tensor(outputs);

// 训练模型
const history = await model.fit(xs, ys, {
epochs: modelConfig.epochs || 100,
batchSize: modelConfig.batchSize || 32,
validationSplit: modelConfig.validationSplit || 0.2,
callbacks: {
onEpochEnd: (epoch, logs) => {
console.log(`Epoch ${epoch}: loss = ${logs.loss}, accuracy = ${logs.acc}`);
}
}
});

// 清理内存
xs.dispose();
ys.dispose();

return { model, history };
}

// 模型性能监控
monitorPerformance(modelName, callback) {
const modelInfo = this.models.get(modelName);
if (!modelInfo) return;

const monitor = {
startTime: null,
endTime: null,
memoryBefore: null,
memoryAfter: null
};

return {
start: () => {
monitor.startTime = performance.now();
monitor.memoryBefore = tf.memory();
},
end: () => {
monitor.endTime = performance.now();
monitor.memoryAfter = tf.memory();

const metrics = {
inferenceTime: monitor.endTime - monitor.startTime,
memoryUsage: {
before: monitor.memoryBefore,
after: monitor.memoryAfter,
delta: {
numTensors: monitor.memoryAfter.numTensors - monitor.memoryBefore.numTensors,
numBytes: monitor.memoryAfter.numBytes - monitor.memoryBefore.numBytes
}
}
};

callback(metrics);
}
};
}
}

2. Transformers.js

特点

  • Hugging Face的JavaScript实现
  • 支持多种预训练模型
  • 自然语言处理专用
  • 零配置使用

核心功能实现

// Transformers.js功能封装
class TransformersManager {
constructor() {
this.pipelines = new Map();
this.models = new Map();
this.tokenizers = new Map();
}

// 创建处理管道
async createPipeline(task, model = null, options = {}) {
const pipelineKey = `${task}-${model || 'default'}`;

if (this.pipelines.has(pipelineKey)) {
return this.pipelines.get(pipelineKey);
}

try {
const { pipeline } = await import('@xenova/transformers');

const pipe = await pipeline(task, model, {
...options,
progress_callback: (progress) => {
console.log(`Loading ${task} model: ${Math.round(progress.progress * 100)}%`);
}
});

this.pipelines.set(pipelineKey, pipe);
return pipe;
} catch (error) {
console.error(`Failed to create pipeline for ${task}:`, error);
throw error;
}
}

// 文本分类
async classifyText(text, model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english') {
const classifier = await this.createPipeline('sentiment-analysis', model);
return await classifier(text);
}

// 文本生成
async generateText(prompt, options = {}) {
const generator = await this.createPipeline(
'text-generation',
options.model || 'Xenova/gpt2'
);

return await generator(prompt, {
max_length: options.maxLength || 100,
num_return_sequences: options.numSequences || 1,
temperature: options.temperature || 0.7,
do_sample: options.doSample !== false,
...options
});
}

// 问答系统
async answerQuestion(question, context, model = 'Xenova/distilbert-base-cased-distilled-squad') {
const qa = await this.createPipeline('question-answering', model);

return await qa({
question,
context
});
}

// 文本摘要
async summarizeText(text, options = {}) {
const summarizer = await this.createPipeline(
'summarization',
options.model || 'Xenova/distilbart-cnn-12-6'
);

return await summarizer(text, {
max_length: options.maxLength || 130,
min_length: options.minLength || 30,
do_sample: options.doSample || false,
...options
});
}

// 翻译
async translateText(text, sourceLanguage, targetLanguage) {
const modelName = `Helsinki-NLP/opus-mt-${sourceLanguage}-${targetLanguage}`;
const translator = await this.createPipeline('translation', modelName);

return await translator(text);
}

// 特征提取
async extractFeatures(text, model = 'Xenova/all-MiniLM-L6-v2') {
const extractor = await this.createPipeline('feature-extraction', model);
return await extractor(text, { pooling: 'mean', normalize: true });
}

// 零样本分类
async zeroShotClassify(text, candidateLabels, model = 'Xenova/distilbert-base-uncased-mnli') {
const classifier = await this.createPipeline('zero-shot-classification', model);

return await classifier(text, candidateLabels);
}

// 批量处理
async batchProcess(texts, task, options = {}) {
const pipeline = await this.createPipeline(task, options.model);
const batchSize = options.batchSize || 10;
const results = [];

for (let i = 0; i < texts.length; i += batchSize) {
const batch = texts.slice(i, i + batchSize);
const batchResults = await Promise.all(
batch.map(text => pipeline(text, options))
);
results.push(...batchResults);

// 进度回调
if (options.onProgress) {
options.onProgress({
processed: Math.min(i + batchSize, texts.length),
total: texts.length,
progress: Math.min(i + batchSize, texts.length) / texts.length
});
}
}

return results;
}
}

3. Brain.js

特点

  • 轻量级神经网络库
  • 易于使用和理解
  • 支持多种网络类型
  • 适合快速原型开发

核心功能实现

// Brain.js功能封装
class BrainManager {
constructor() {
this.networks = new Map();
this.trainingData = new Map();
}

// 创建神经网络
createNetwork(name, type = 'feedforward', options = {}) {
let network;

switch (type) {
case 'feedforward':
network = new brain.NeuralNetwork({
hiddenLayers: options.hiddenLayers || [3],
activation: options.activation || 'sigmoid',
learningRate: options.learningRate || 0.3,
...options
});
break;

case 'lstm':
network = new brain.recurrent.LSTM({
hiddenLayers: options.hiddenLayers || [20],
learningRate: options.learningRate || 0.01,
...options
});
break;

case 'gru':
network = new brain.recurrent.GRU({
hiddenLayers: options.hiddenLayers || [20],
learningRate: options.learningRate || 0.01,
...options
});
break;

case 'rnn':
network = new brain.recurrent.RNN({
hiddenLayers: options.hiddenLayers || [20],
learningRate: options.learningRate || 0.01,
...options
});
break;

default:
throw new Error(`Unsupported network type: ${type}`);
}

this.networks.set(name, {
network,
type,
options,
trained: false,
createdAt: Date.now()
});

return network;
}

// 训练网络
async trainNetwork(name, trainingData, options = {}) {
const networkInfo = this.networks.get(name);
if (!networkInfo) {
throw new Error(`Network ${name} not found`);
}

const { network } = networkInfo;

// 保存训练数据
this.trainingData.set(name, trainingData);

const trainingOptions = {
iterations: options.iterations || 20000,
errorThresh: options.errorThresh || 0.005,
log: options.log || false,
logPeriod: options.logPeriod || 100,
learningRate: options.learningRate || 0.3,
momentum: options.momentum || 0.1,
callback: options.callback,
callbackPeriod: options.callbackPeriod || 10,
timeout: options.timeout || Infinity,
...options
};

const startTime = Date.now();

return new Promise((resolve, reject) => {
try {
const stats = network.train(trainingData, {
...trainingOptions,
callback: (stats) => {
if (options.onProgress) {
options.onProgress({
iterations: stats.iterations,
error: stats.error,
progress: stats.iterations / trainingOptions.iterations
});
}

if (options.callback) {
options.callback(stats);
}
}
});

networkInfo.trained = true;
networkInfo.trainingStats = {
...stats,
trainingTime: Date.now() - startTime
};

resolve(stats);
} catch (error) {
reject(error);
}
});
}

// 预测
predict(name, input) {
const networkInfo = this.networks.get(name);
if (!networkInfo) {
throw new Error(`Network ${name} not found`);
}

if (!networkInfo.trained) {
console.warn(`Network ${name} has not been trained yet`);
}

return networkInfo.network.run(input);
}

// 文本生成(LSTM示例)
async trainTextGenerator(name, text, options = {}) {
const network = this.createNetwork(name, 'lstm', {
hiddenLayers: options.hiddenLayers || [20],
learningRate: options.learningRate || 0.01
});

// 准备训练数据
const trainingData = this.prepareTextData(text, options.sequenceLength || 10);

await this.trainNetwork(name, trainingData, {
iterations: options.iterations || 2000,
errorThresh: options.errorThresh || 0.011,
log: true,
logPeriod: 100,
onProgress: options.onProgress
});

return network;
}

generateText(name, seed, length = 100) {
const networkInfo = this.networks.get(name);
if (!networkInfo || networkInfo.type !== 'lstm') {
throw new Error(`LSTM network ${name} not found`);
}

return networkInfo.network.run(seed, length);
}

// 时间序列预测
async trainTimeSeriesPredictor(name, data, options = {}) {
const network = this.createNetwork(name, 'lstm', {
hiddenLayers: options.hiddenLayers || [10, 10],
learningRate: options.learningRate || 0.005
});

// 准备时间序列数据
const trainingData = this.prepareTimeSeriesData(
data,
options.windowSize || 10,
options.predictionSteps || 1
);

await this.trainNetwork(name, trainingData, {
iterations: options.iterations || 1000,
errorThresh: options.errorThresh || 0.01,
onProgress: options.onProgress
});

return network;
}

predictTimeSeries(name, inputSequence) {
return this.predict(name, inputSequence);
}

// 数据预处理辅助方法
prepareTextData(text, sequenceLength) {
const data = [];
for (let i = 0; i < text.length - sequenceLength; i++) {
data.push({
input: text.substring(i, i + sequenceLength),
output: text.substring(i + 1, i + sequenceLength + 1)
});
}
return data;
}

prepareTimeSeriesData(data, windowSize, predictionSteps) {
const trainingData = [];

for (let i = 0; i < data.length - windowSize - predictionSteps + 1; i++) {
const input = data.slice(i, i + windowSize);
const output = data.slice(i + windowSize, i + windowSize + predictionSteps);

trainingData.push({ input, output });
}

return trainingData;
}

// 网络序列化
exportNetwork(name) {
const networkInfo = this.networks.get(name);
if (!networkInfo) {
throw new Error(`Network ${name} not found`);
}

return {
json: networkInfo.network.toJSON(),
function: networkInfo.network.toFunction().toString(),
metadata: {
type: networkInfo.type,
options: networkInfo.options,
trained: networkInfo.trained,
trainingStats: networkInfo.trainingStats
}
};
}

// 网络导入
importNetwork(name, exportedData) {
const network = new brain.NeuralNetwork();
network.fromJSON(exportedData.json);

this.networks.set(name, {
network,
type: exportedData.metadata.type,
options: exportedData.metadata.options,
trained: exportedData.metadata.trained,
trainingStats: exportedData.metadata.trainingStats,
importedAt: Date.now()
});

return network;
}
}

AI服务集成SDK

1. OpenAI SDK

核心功能封装

// OpenAI SDK增强封装
class EnhancedOpenAI {
constructor(apiKey, options = {}) {
this.client = new OpenAI({
apiKey,
...options
});

this.rateLimiter = new RateLimiter({
requestsPerMinute: options.requestsPerMinute || 60,
tokensPerMinute: options.tokensPerMinute || 90000
});

this.cache = new ResponseCache({
ttl: options.cacheTTL || 3600000, // 1小时
maxSize: options.cacheMaxSize || 1000
});

this.retryConfig = {
maxRetries: options.maxRetries || 3,
backoffFactor: options.backoffFactor || 2,
initialDelay: options.initialDelay || 1000
};
}

// 智能聊天完成
async chatCompletion(messages, options = {}) {
const cacheKey = this.generateCacheKey('chat', { messages, ...options });

// 检查缓存
if (options.useCache !== false) {
const cached = await this.cache.get(cacheKey);
if (cached) {
return { ...cached, fromCache: true };
}
}

// 速率限制检查
await this.rateLimiter.checkLimit();

const requestOptions = {
model: options.model || 'gpt-3.5-turbo',
messages,
temperature: options.temperature ?? 0.7,
max_tokens: options.maxTokens,
top_p: options.topP,
frequency_penalty: options.frequencyPenalty,
presence_penalty: options.presencePenalty,
stop: options.stop,
stream: options.stream || false,
...options
};

try {
const response = await this.executeWithRetry(async () => {
return await this.client.chat.completions.create(requestOptions);
});

// 缓存响应
if (options.useCache !== false && !options.stream) {
await this.cache.set(cacheKey, response);
}

return response;
} catch (error) {
throw this.handleError(error);
}
}

// 流式聊天
async streamChatCompletion(messages, options = {}, onChunk) {
const stream = await this.chatCompletion(messages, {
...options,
stream: true
});

let fullContent = '';

for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta;
if (delta?.content) {
fullContent += delta.content;
onChunk({
content: delta.content,
fullContent,
chunk,
finished: false
});
}

if (chunk.choices[0]?.finish_reason) {
onChunk({
content: '',
fullContent,
chunk,
finished: true,
finishReason: chunk.choices[0].finish_reason
});
}
}

return fullContent;
}

// 文本嵌入
async createEmbedding(input, options = {}) {
const cacheKey = this.generateCacheKey('embedding', { input, ...options });

if (options.useCache !== false) {
const cached = await this.cache.get(cacheKey);
if (cached) return cached;
}

await this.rateLimiter.checkLimit();

try {
const response = await this.executeWithRetry(async () => {
return await this.client.embeddings.create({
model: options.model || 'text-embedding-ada-002',
input,
...options
});
});

if (options.useCache !== false) {
await this.cache.set(cacheKey, response);
}

return response;
} catch (error) {
throw this.handleError(error);
}
}

// 图像生成
async generateImage(prompt, options = {}) {
await this.rateLimiter.checkLimit();

try {
return await this.executeWithRetry(async () => {
return await this.client.images.generate({
prompt,
model: options.model || 'dall-e-3',
n: options.n || 1,
size: options.size || '1024x1024',
quality: options.quality || 'standard',
style: options.style,
response_format: options.responseFormat || 'url',
...options
});
});
} catch (error) {
throw this.handleError(error);
}
}

// 语音转文字
async transcribeAudio(audioFile, options = {}) {
await this.rateLimiter.checkLimit();

try {
return await this.executeWithRetry(async () => {
return await this.client.audio.transcriptions.create({
file: audioFile,
model: options.model || 'whisper-1',
language: options.language,
prompt: options.prompt,
response_format: options.responseFormat || 'json',
temperature: options.temperature,
...options
});
});
} catch (error) {
throw this.handleError(error);
}
}

// 文字转语音
async generateSpeech(text, options = {}) {
await this.rateLimiter.checkLimit();

try {
return await this.executeWithRetry(async () => {
return await this.client.audio.speech.create({
model: options.model || 'tts-1',
input: text,
voice: options.voice || 'alloy',
response_format: options.responseFormat || 'mp3',
speed: options.speed || 1.0,
...options
});
});
} catch (error) {
throw this.handleError(error);
}
}

// 重试机制
async executeWithRetry(operation) {
let lastError;

for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;

if (attempt === this.retryConfig.maxRetries) {
break;
}

if (!this.isRetryableError(error)) {
break;
}

const delay = this.retryConfig.initialDelay *
Math.pow(this.retryConfig.backoffFactor, attempt);
await this.sleep(delay);
}
}

throw lastError;
}

isRetryableError(error) {
const retryableStatusCodes = [429, 500, 502, 503, 504];
return retryableStatusCodes.includes(error.status) ||
error.code === 'ECONNRESET' ||
error.code === 'ETIMEDOUT';
}

handleError(error) {
const enhancedError = new Error(error.message);
enhancedError.originalError = error;
enhancedError.status = error.status;
enhancedError.code = error.code;
enhancedError.type = error.type;

// 添加用户友好的错误信息
if (error.status === 429) {
enhancedError.userMessage = '请求过于频繁,请稍后再试';
} else if (error.status === 401) {
enhancedError.userMessage = 'API密钥无效或已过期';
} else if (error.status >= 500) {
enhancedError.userMessage = '服务暂时不可用,请稍后再试';
}

return enhancedError;
}

generateCacheKey(operation, params) {
return `${operation}:${JSON.stringify(params)}`;
}

sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

2. LangChain.js

核心功能封装

// LangChain.js功能封装
class LangChainManager {
constructor() {
this.chains = new Map();
this.vectorStores = new Map();
this.retrievers = new Map();
this.agents = new Map();
}

// 创建对话链
async createConversationChain(name, llm, options = {}) {
const { ConversationChain } = await import('langchain/chains');
const { BufferMemory } = await import('langchain/memory');

const memory = new BufferMemory({
memoryKey: 'history',
inputKey: 'input',
outputKey: 'response',
...options.memory
});

const chain = new ConversationChain({
llm,
memory,
verbose: options.verbose || false,
...options
});

this.chains.set(name, {
chain,
type: 'conversation',
createdAt: Date.now()
});

return chain;
}

// 创建RAG链
async createRAGChain(name, llm, vectorStore, options = {}) {
const { RetrievalQAChain } = await import('langchain/chains');

const retriever = vectorStore.asRetriever({
k: options.topK || 4,
searchType: options.searchType || 'similarity',
...options.retriever
});

const chain = RetrievalQAChain.fromLLM(llm, retriever, {
returnSourceDocuments: options.returnSourceDocuments || true,
verbose: options.verbose || false,
...options
});

this.chains.set(name, {
chain,
type: 'rag',
retriever,
createdAt: Date.now()
});

return chain;
}

// 创建向量存储
async createVectorStore(name, documents, embeddings, storeType = 'memory') {
let vectorStore;

switch (storeType) {
case 'memory':
const { MemoryVectorStore } = await import('langchain/vectorstores/memory');
vectorStore = await MemoryVectorStore.fromDocuments(documents, embeddings);
break;

case 'chroma':
const { Chroma } = await import('langchain/vectorstores/chroma');
vectorStore = await Chroma.fromDocuments(documents, embeddings, {
collectionName: name
});
break;

case 'pinecone':
const { PineconeStore } = await import('langchain/vectorstores/pinecone');
vectorStore = await PineconeStore.fromDocuments(documents, embeddings, {
pineconeIndex: this.getPineconeIndex(name)
});
break;

default:
throw new Error(`Unsupported vector store type: ${storeType}`);
}

this.vectorStores.set(name, {
store: vectorStore,
type: storeType,
documentCount: documents.length,
createdAt: Date.now()
});

return vectorStore;
}

// 创建智能代理
async createAgent(name, llm, tools, options = {}) {
const { initializeAgentExecutorWithOptions } = await import('langchain/agents');

const executor = await initializeAgentExecutorWithOptions(tools, llm, {
agentType: options.agentType || 'zero-shot-react-description',
verbose: options.verbose || false,
maxIterations: options.maxIterations || 10,
earlyStoppingMethod: options.earlyStoppingMethod || 'generate',
...options
});

this.agents.set(name, {
executor,
tools,
createdAt: Date.now()
});

return executor;
}

// 文档处理和分割
async processDocuments(documents, options = {}) {
const { RecursiveCharacterTextSplitter } = await import('langchain/text_splitter');

const splitter = new RecursiveCharacterTextSplitter({
chunkSize: options.chunkSize || 1000,
chunkOverlap: options.chunkOverlap || 200,
separators: options.separators || ['\n\n', '\n', ' ', ''],
...options
});

const splitDocs = await splitter.splitDocuments(documents);

// 添加元数据
return splitDocs.map((doc, index) => ({
...doc,
metadata: {
...doc.metadata,
chunkIndex: index,
processedAt: Date.now()
}
}));
}

// 执行链
async runChain(name, input, options = {}) {
const chainInfo = this.chains.get(name);
if (!chainInfo) {
throw new Error(`Chain ${name} not found`);
}

const { chain } = chainInfo;

try {
const result = await chain.call(input, options);

// 记录使用统计
this.updateChainStats(name, {
inputTokens: this.estimateTokens(JSON.stringify(input)),
outputTokens: this.estimateTokens(JSON.stringify(result)),
executionTime: Date.now()
});

return result;
} catch (error) {
console.error(`Error running chain ${name}:`, error);
throw error;
}
}

// 批量处理
async batchProcess(chainName, inputs, options = {}) {
const batchSize = options.batchSize || 5;
const results = [];

for (let i = 0; i < inputs.length; i += batchSize) {
const batch = inputs.slice(i, i + batchSize);

const batchPromises = batch.map(input =>
this.runChain(chainName, input, options)
);

const batchResults = await Promise.allSettled(batchPromises);

results.push(...batchResults.map((result, index) => ({
index: i + index,
input: batch[index],
success: result.status === 'fulfilled',
result: result.status === 'fulfilled' ? result.value : null,
error: result.status === 'rejected' ? result.reason : null
})));

// 进度回调
if (options.onProgress) {
options.onProgress({
processed: Math.min(i + batchSize, inputs.length),
total: inputs.length,
progress: Math.min(i + batchSize, inputs.length) / inputs.length
});
}

// 批次间延迟
if (options.batchDelay && i + batchSize < inputs.length) {
await this.sleep(options.batchDelay);
}
}

return results;
}

// 链性能监控
updateChainStats(name, stats) {
const chainInfo = this.chains.get(name);
if (!chainInfo.stats) {
chainInfo.stats = {
totalCalls: 0,
totalInputTokens: 0,
totalOutputTokens: 0,
averageExecutionTime: 0,
lastUsed: null
};
}

const currentStats = chainInfo.stats;
currentStats.totalCalls++;
currentStats.totalInputTokens += stats.inputTokens;
currentStats.totalOutputTokens += stats.outputTokens;
currentStats.averageExecutionTime = (
(currentStats.averageExecutionTime * (currentStats.totalCalls - 1) +
stats.executionTime) / currentStats.totalCalls
);
currentStats.lastUsed = Date.now();
}

// 获取链统计信息
getChainStats(name) {
const chainInfo = this.chains.get(name);
return chainInfo ? chainInfo.stats : null;
}

// 工具方法
estimateTokens(text) {
// 简单的token估算,实际应用中可以使用更精确的方法
return Math.ceil(text.length / 4);
}

sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

开发工具链

1. 构建工具配置

Webpack配置

// webpack.config.js for AI applications
const path = require('path');
const webpack = require('webpack');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
library: 'AIApp',
libraryTarget: 'umd'
},

resolve: {
fallback: {
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"buffer": require.resolve("buffer"),
"process": require.resolve("process/browser"),
"path": require.resolve("path-browserify"),
"fs": false,
"net": false,
"tls": false
}
},

module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-runtime'
]
}
}
},
{
test: /\.wasm$/,
type: 'webassembly/async'
},
{
test: /\.(bin|onnx)$/,
type: 'asset/resource'
}
]
},

plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
],

experiments: {
asyncWebAssembly: true,
topLevelAwait: true
},

optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
ai: {
test: /[\\/]node_modules[\\/](@tensorflow|@xenova|brain\.js)/,
name: 'ai-libs',
chunks: 'all'
}
}
}
}
};

Vite配置

// vite.config.js for AI applications
import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
define: {
global: 'globalThis'
},

resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},

optimizeDeps: {
include: [
'@tensorflow/tfjs',
'@xenova/transformers',
'brain.js',
'openai'
],
exclude: [
'@tensorflow/tfjs-node'
]
},

build: {
rollupOptions: {
output: {
manualChunks: {
'ai-core': ['@tensorflow/tfjs', '@xenova/transformers'],
'ai-services': ['openai', 'langchain'],
'ai-utils': ['brain.js', 'ml5']
}
}
},
target: 'esnext',
minify: 'terser'
},

server: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin'
}
}
});

2. 性能监控工具

// AI应用性能监控
class AIPerformanceMonitor {
constructor() {
this.metrics = new Map();
this.observers = [];
this.isMonitoring = false;
}

startMonitoring() {
if (this.isMonitoring) return;

this.isMonitoring = true;

// 监控内存使用
this.memoryObserver = setInterval(() => {
if (performance.memory) {
this.recordMetric('memory', {
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize,
limit: performance.memory.jsHeapSizeLimit,
timestamp: Date.now()
});
}
}, 1000);

// 监控网络请求
this.setupNetworkMonitoring();

// 监控AI模型性能
this.setupModelMonitoring();
}

recordMetric(category, data) {
if (!this.metrics.has(category)) {
this.metrics.set(category, []);
}

const categoryMetrics = this.metrics.get(category);
categoryMetrics.push(data);

// 保持最近1000条记录
if (categoryMetrics.length > 1000) {
categoryMetrics.shift();
}

// 通知观察者
this.notifyObservers(category, data);
}

getMetrics(category, timeRange = 60000) {
const categoryMetrics = this.metrics.get(category) || [];
const cutoff = Date.now() - timeRange;

return categoryMetrics.filter(metric => metric.timestamp > cutoff);
}

generateReport() {
const report = {
timestamp: Date.now(),
memory: this.analyzeMemoryUsage(),
network: this.analyzeNetworkPerformance(),
models: this.analyzeModelPerformance(),
recommendations: this.generateRecommendations()
};

return report;
}
}

学习检验

理论问题

  1. 生态系统比较

    • 比较TensorFlow.js、Brain.js和ML5.js的优缺点
    • 在什么场景下选择客户端AI vs 服务端AI?
    • 如何设计混合AI架构?
  2. 性能优化

    • JavaScript AI应用的主要性能瓶颈有哪些?
    • 如何优化模型加载和推理性能?
    • 设计一个AI应用的缓存策略
  3. 工具链选择

    • 如何为AI项目选择合适的构建工具?
    • 不同AI库的打包优化策略
    • 如何处理AI库的依赖冲突?

实践练习

  1. 环境搭建

    • 创建一个支持多种AI库的开发环境
    • 配置Webpack/Vite支持AI库打包
    • 实现AI库的懒加载机制
  2. 性能对比

    • 对比不同AI库在相同任务上的性能
    • 测试客户端vs服务端AI的响应时间
    • 分析内存使用和优化策略
  3. 集成开发

    • 创建一个统一的AI服务管理器
    • 实现多个AI提供商的负载均衡
    • 开发AI应用的监控和调试工具

实践项目建议

初级项目

  1. AI库性能测试工具 - 对比不同AI库的性能表现
  2. 统一AI接口封装 - 创建统一的AI服务调用接口
  3. AI应用脚手架 - 快速创建AI应用的项目模板

中级项目

  1. AI模型管理平台 - 模型版本管理和部署工具
  2. 多模态AI工具箱 - 集成多种AI能力的工具集
  3. AI应用性能监控 - 实时监控AI应用性能

高级项目

  1. AI开发框架 - 完整的AI应用开发框架
  2. 智能代码生成器 - 基于AI的代码生成工具
  3. AI应用商店 - AI能力的发现和集成平台

延伸阅读

官方文档

开源项目

社区资源


JavaScript AI生态系统正在快速发展,让我们一起探索这个充满创新的领域!

// Mermaid图表缩放控制功能
class MermaidZoomController {
constructor() {
this.currentScale = 1;
this.minScale = 0.5;
this.maxScale = 3;
this.scaleStep = 0.2;
this.charts = new Map();
this.init();
}

init() {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setupEventListeners());
} else {
this.setupEventListeners();
}
}

setupEventListeners() {
document.addEventListener('mermaid-rendered', (event) => {
this.registerChart(event.target);
});
this.findExistingCharts();
}

findExistingCharts() {
const mermaidElements = document.querySelectorAll('.mermaid');
mermaidElements.forEach(element => {
this.registerChart(element);
});
}

registerChart(element) {
if (this.charts.has(element)) return;
const chartId = `chart-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
element.setAttribute('data-chart-id', chartId);

const svg = element.querySelector('svg');
if (svg) {
svg.style.transformOrigin = 'center';
svg.style.transition = 'transform 0.3s ease';

this.charts.set(chartId, {
element,
svg,
scale: 1,
originalTransform: svg.style.transform
});
}
}

zoomChart(chartId, action) {
const chart = this.charts.get(chartId);
if (!chart) return;

let newScale = chart.scale;

switch (action) {
case 'zoom-in':
newScale = Math.min(chart.scale + this.scaleStep, this.maxScale);
break;
case 'zoom-out':
newScale = Math.max(chart.scale - this.scaleStep, this.minScale);
break;
case 'reset':
newScale = 1;
break;
case 'fullscreen':
this.toggleFullscreen(chart);
return;
default:
return;
}

if (newScale !== chart.scale) {
chart.scale = newScale;
chart.svg.style.transform = `scale(${newScale})`;
this.currentScale = newScale;
this.saveZoomState(chartId, newScale);
}
}

toggleFullscreen(chart) {
const container = chart.element.closest('.mermaid-container') || chart.element;

if (!document.fullscreenElement) {
if (container.requestFullscreen) {
container.requestFullscreen();
} else if (container.webkitRequestFullscreen) {
container.webkitRequestFullscreen();
} else if (container.msRequestFullscreen) {
container.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}

saveZoomState(chartId, scale) {
try {
const zoomStates = JSON.parse(localStorage.getItem('mermaid-zoom-states') || '{}');
zoomStates[chartId] = scale;
localStorage.setItem('mermaid-zoom-states', JSON.stringify(zoomStates));
} catch (error) {
console.warn('Failed to save zoom state:', error);
}
}

loadZoomState(chartId) {
try {
const zoomStates = JSON.parse(localStorage.getItem('mermaid-zoom-states') || '{}');
return zoomStates[chartId] || 1;
} catch (error) {
return 1;
}
}
}

// 全局缩放控制函数
function zoomMermaid(action) {
const mermaidElements = document.querySelectorAll('.mermaid');

if (mermaidElements.length === 0) {
console.warn('No Mermaid charts found on this page');
return;
}

if (mermaidElements.length === 1) {
const chartId = mermaidElements[0].getAttribute('data-chart-id');
if (chartId && window.mermaidZoomController) {
window.mermaidZoomController.zoomChart(chartId, action);
}
return;
}

showChartSelectionDialog(action);
}

// 图表选择对话框
function showChartSelectionDialog(action) {
const charts = Array.from(document.querySelectorAll('.mermaid')).map((el, index) => ({
id: el.getAttribute('data-chart-id') || `chart-${index}`,
title: el.getAttribute('data-title') || `图表 ${index + 1}`,
element: el
}));

if (charts.length === 0) return;

const dialog = document.createElement('div');
dialog.className = 'mermaid-selection-dialog';
dialog.innerHTML = `
<div className="mermaid-dialog-content">
<h3>选择要缩放的图表</h3>
<div className="mermaid-chart-list">
${charts.map(chart => `
<button className="mermaid-chart-option" onClick={() => selectChartForZoom('${chart.id}', '${action}')}>
${chart.title}
</button>
`).join('')}
</div>
<button className="mermaid-dialog-close" onClick={() => closeChartSelectionDialog()}>关闭</button>
</div>
`;

document.body.appendChild(dialog);
}

// 选择图表进行缩放
function selectChartForZoom(chartId, action) {
if (window.mermaidZoomController) {
window.mermaidZoomController.zoomChart(chartId, action);
}
closeChartSelectionDialog();
}

// 关闭图表选择对话框
function closeChartSelectionDialog() {
const dialog = document.querySelector('.mermaid-selection-dialog');
if (dialog) {
dialog.remove();
}
}

// 初始化缩放控制器
document.addEventListener('DOMContentLoaded', () => {
window.mermaidZoomController = new MermaidZoomController();
});

// 导出到全局作用域
window.zoomMermaid = zoomMermaid;
window.showChartSelectionDialog = showChartSelectionDialog;
window.selectChartForZoom = selectChartForZoom;
window.closeChartSelectionDialog = closeChartSelectionDialog;

CSS样式

/* Mermaid图表缩放控制按钮样式 */
.mermaid-controls {
margin: 15px 0;
padding: 10px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
text-align: center;
}

.zoom-icon {
font-size: 16px;
display: inline-block;
}

.mermaid-zoom-btn {
display: inline-block;
margin: 0 5px;
padding: 8px 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

.mermaid-zoom-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
}

.mermaid-zoom-btn:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

.mermaid-zoom-btn:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.3);
}

/* 响应式设计 */
@media (max-width: 768px) {
.mermaid-controls {
padding: 8px;
}

.mermaid-zoom-btn {
padding: 6px 10px;
margin: 0 3px;
font-size: 12px;
}
}

/* 全屏模式下的图表样式 */
.mermaid:fullscreen {
background: white;
padding: 20px;
}

.mermaid:fullscreen svg {
max-width: 100%;
max-height: 100%;
}

/* 图表容器样式增强 */
.mermaid {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: box-shadow 0.3s ease;
}

.mermaid:hover {
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
}

/* 缩放动画 */
.mermaid svg {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 选择对话框样式 */
.mermaid-selection-dialog {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
}

.mermaid-dialog-content {
background: white;
padding: 20px;
border-radius: 8px;
max-width: 400px;
width: 90%;
}

.mermaid-chart-list {
margin: 15px 0;
}

.mermaid-chart-option {
display: block;
width: 100%;
padding: 10px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
background: #f9f9f9;
cursor: pointer;
}

.mermaid-chart-option:hover {
background: #e9e9e9;
}

.mermaid-dialog-close {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

.mermaid-dialog-close:hover {
background: #0056b3;
}

使用方法

  1. 基本缩放操作

    • 点击 🔍+ 按钮放大图表
    • 点击 🔍- 按钮缩小图表
    • 点击 🔄 按钮重置缩放
    • 点击 ⛶ 按钮进入全屏模式
  2. 高级功能

    • 自动保存缩放状态到本地存储
    • 支持多个图表的独立缩放
    • 响应式设计,适配移动设备
    • 平滑的缩放动画效果

技术特性

  • 性能优化:使用CSS transform进行缩放,避免重绘
  • 内存管理:自动清理不需要的图表引用
  • 状态持久化:缩放状态自动保存到localStorage
  • 事件委托:高效的事件处理机制
  • 兼容性:支持现代浏览器的全屏API
  • 可扩展性:模块化设计,易于扩展新功能

这个缩放控制系统为你的Mermaid图表提供了完整的交互体验,让用户可以更好地查看和分析复杂的图表内容。

附录:Mermaid图表缩放功能

JavaScript功能代码

// Mermaid图表缩放控制功能
class MermaidZoomController {
constructor() {
this.currentScale = 1;
this.minScale = 0.5;
this.maxScale = 3;
this.scaleStep = 0.2;
this.charts = new Map();
this.init();
}

init() {
// 等待页面加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setupEventListeners());
} else {
this.setupEventListeners();
}
}

setupEventListeners() {
// 监听Mermaid图表渲染完成事件
document.addEventListener('mermaid-rendered', (event) => {
this.registerChart(event.target);
});

// 查找已存在的Mermaid图表
this.findExistingCharts();
}

findExistingCharts() {
const mermaidElements = document.querySelectorAll('.mermaid');
mermaidElements.forEach(element => {
this.registerChart(element);
});
}

registerChart(element) {
if (this.charts.has(element)) return;

const chartId = `chart-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
element.setAttribute('data-chart-id', chartId);

// 创建SVG包装器
const svg = element.querySelector('svg');
if (svg) {
svg.style.transformOrigin = 'center';
svg.style.transition = 'transform 0.3s ease';

this.charts.set(chartId, {
element,
svg,
scale: 1,
originalTransform: svg.style.transform
});
}
}

zoomChart(chartId, action) {
const chart = this.charts.get(chartId);
if (!chart) return;

let newScale = chart.scale;

switch (action) {
case 'zoom-in':
newScale = Math.min(chart.scale + this.scaleStep, this.maxScale);
break;
case 'zoom-out':
newScale = Math.max(chart.scale - this.scaleStep, this.minScale);
break;
case 'reset':
newScale = 1;
break;
case 'fullscreen':
this.toggleFullscreen(chart);
return;
default:
return;
}

if (newScale !== chart.scale) {
chart.scale = newScale;
chart.svg.style.transform = `scale(${newScale})`;

// 更新全局缩放状态
this.currentScale = newScale;

// 保存缩放状态到localStorage
this.saveZoomState(chartId, newScale);
}
}

toggleFullscreen(chart) {
const container = chart.element.closest('.mermaid-container') || chart.element;

if (!document.fullscreenElement) {
// 进入全屏
if (container.requestFullscreen) {
container.requestFullscreen();
} else if (container.webkitRequestFullscreen) {
container.webkitRequestFullscreen();
} else if (container.msRequestFullscreen) {
container.msRequestFullscreen();
}
} else {
// 退出全屏
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}

saveZoomState(chartId, scale) {
try {
const zoomStates = JSON.parse(localStorage.getItem('mermaid-zoom-states') || '{}');
zoomStates[chartId] = scale;
localStorage.setItem('mermaid-zoom-states', JSON.stringify(zoomStates));
} catch (error) {
console.warn('Failed to save zoom state:', error);
}
}

loadZoomState(chartId) {
try {
const zoomStates = JSON.parse(localStorage.getItem('mermaid-zoom-states') || '{}');
return zoomStates[chartId] || 1;
} catch (error) {
return 1;
}
}

// 获取所有图表的缩放状态
getAllChartsZoomState() {
const states = {};
this.charts.forEach((chart, chartId) => {
states[chartId] = chart.scale;
});
return states;
}

// 重置所有图表缩放
resetAllCharts() {
this.charts.forEach((chart, chartId) => {
this.zoomChart(chartId, 'reset');
});
}

// 设置特定缩放级别
setChartZoom(chartId, scale) {
const chart = this.charts.get(chartId);
if (!chart) return;

const clampedScale = Math.max(this.minScale, Math.min(this.maxScale, scale));
chart.scale = clampedScale;
chart.svg.style.transform = `scale(${clampedScale})`;

this.saveZoomState(chartId, clampedScale);
}
}

// 全局缩放控制函数
function zoomMermaid(action) {
// 获取当前页面的所有Mermaid图表
const mermaidElements = document.querySelectorAll('.mermaid');

if (mermaidElements.length === 0) {
console.warn('No Mermaid charts found on this page');
return;
}

// 如果只有一个图表,直接缩放它
if (mermaidElements.length === 1) {
const chartId = mermaidElements[0].getAttribute('data-chart-id');
if (chartId && window.mermaidZoomController) {
window.mermaidZoomController.zoomChart(chartId, action);
}
return;
}

// 如果有多个图表,显示选择对话框
showChartSelectionDialog(action);
}

// 图表选择对话框
function showChartSelectionDialog(action) {
const charts = Array.from(document.querySelectorAll('.mermaid')).map((el, index) => ({
id: el.getAttribute('data-chart-id') || `chart-${index}`,
title: el.getAttribute('data-title') || `图表 ${index + 1}`,
element: el
}));

if (charts.length === 0) return;

// 创建选择对话框
const dialog = document.createElement('div');
dialog.className = 'mermaid-selection-dialog';
dialog.innerHTML = `
<div className="mermaid-dialog-content">
<h3>选择要缩放的图表</h3>
<div className="mermaid-chart-list">
${charts.map(chart => `
<button className="mermaid-chart-option" onClick={() => selectChartForZoom('${chart.id}', '${action}')}>
${chart.title}
</button>
`).join('')}
</div>
<button className="mermaid-dialog-close" onClick={() => closeChartSelectionDialog()}>关闭</button>
</div>
`;

document.body.appendChild(dialog);

// 添加样式
if (!document.getElementById('mermaid-dialog-styles')) {
const style = document.createElement('style');
style.id = 'mermaid-dialog-styles';
style.textContent = `
.mermaid-selection-dialog {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
}
.mermaid-dialog-content {
background: white;
padding: 20px;
border-radius: 8px;
max-width: 400px;
width: 90%;
}
.mermaid-chart-list {
margin: 15px 0;
}
.mermaid-chart-option {
display: block;
width: 100%;
padding: 10px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
background: #f9f9f9;
cursor: pointer;
}
.mermaid-chart-option:hover {
background: #e9e9e9;
}
.mermaid-dialog-close {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.mermaid-dialog-close:hover {
background: #0056b3;
}
`;
document.head.appendChild(style);
}
}

// 选择图表进行缩放
function selectChartForZoom(chartId, action) {
if (window.mermaidZoomController) {
window.mermaidZoomController.zoomChart(chartId, action);
}
closeChartSelectionDialog();
}

// 关闭图表选择对话框
function closeChartSelectionDialog() {
const dialog = document.querySelector('.mermaid-selection-dialog');
if (dialog) {
dialog.remove();
}
}

// 初始化缩放控制器
document.addEventListener('DOMContentLoaded', () => {
window.mermaidZoomController = new MermaidZoomController();
});

// 导出到全局作用域
window.zoomMermaid = zoomMermaid;
window.showChartSelectionDialog = showChartSelectionDialog;
window.selectChartForZoom = selectChartForZoom;
window.closeChartSelectionDialog = closeChartSelectionDialog;


/* 工具提示样式 */
.mermaid-zoom-btn[title]:hover::after {
content: attr(title);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
margin-bottom: 5px;
}

/* 键盘快捷键提示 */
.mermaid-controls::after {
content: "快捷键: Ctrl/Cmd + 滚轮缩放, 空格键重置";
display: block;
margin-top: 8px;
font-size: 11px;
color: #666;
font-style: italic;
}

使用方法

  1. 基本缩放操作

    • 点击 🔍+ 按钮放大图表
    • 点击 🔍- 按钮缩小图表
    • 点击 🔄 按钮重置缩放
    • 点击 ⛶ 按钮进入全屏模式
  2. 键盘快捷键

    • Ctrl/Cmd + 滚轮:缩放图表
    • 空格键:重置缩放
    • Esc键:退出全屏
  3. 高级功能

    • 自动保存缩放状态到本地存储
    • 支持多个图表的独立缩放
    • 响应式设计,适配移动设备
    • 平滑的缩放动画效果

技术特性

  • 性能优化:使用CSS transform进行缩放,避免重绘
  • 内存管理:自动清理不需要的图表引用
  • 状态持久化:缩放状态自动保存到localStorage
  • 事件委托:高效的事件处理机制
  • 兼容性:支持现代浏览器的全屏API
  • 可扩展性:模块化设计,易于扩展新功能

这个缩放控制系统为你的Mermaid图表提供了完整的交互体验,让用户可以更好地查看和分析复杂的图表内容。