aisapi
Version:
A JavaScript/TypeScript API library for multiple AI providers
480 lines • 19.5 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnthropicProvider = void 0;
const base_1 = require("./base");
/**
* Anthropic Claude API实现
* 支持文本生成、多模态输入、工具调用等
*/
class AnthropicProvider extends base_1.BaseProvider {
/**
* 创建Anthropic提供商实例
*/
constructor(options = {}) {
super(options);
this.name = 'Anthropic';
this.model = options.model || 'claude-3-7-sonnet-20250219';
this.anthropicVersion = options.anthropicVersion || '2024-06-23';
this.maxRetries = options.maxRetries || 3;
}
/**
* @inheritdoc
*/
getDefaultBaseUrl() {
return 'https://api.anthropic.com/v1';
}
/**
* @inheritdoc
*/
validateApiKey() {
super.validateApiKey();
if (this.apiKey && !this.apiKey.startsWith('sk-ant-')) {
console.warn(`[${this.name}] 警告: API密钥格式可能不正确,应以 'sk-ant-' 开头`);
}
}
/**
* @inheritdoc
*/
generateText(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
const model = params.model || this.model;
// 构建消息格式
const messages = [];
// 添加用户消息
messages.push({
role: 'user',
content: params.prompt
});
// 构建请求体
const requestBody = {
model,
messages,
max_tokens: params.maxTokens || 1000,
temperature: (_a = params.temperature) !== null && _a !== void 0 ? _a : 0.7,
stream: params.stream || false
};
// 添加系统消息(如果有)
if (params.systemMessage) {
requestBody.system = params.systemMessage;
}
// 添加top_p(如果指定)
if (params.topP !== undefined) {
requestBody.top_p = params.topP;
}
// 发送请求并获取响应
const data = yield this.sendClaudeRequest('/messages', requestBody);
return {
text: this.extractTextFromContent(data.content),
usage: {
promptTokens: ((_b = data.usage) === null || _b === void 0 ? void 0 : _b.input_tokens) || 0,
completionTokens: ((_c = data.usage) === null || _c === void 0 ? void 0 : _c.output_tokens) || 0,
totalTokens: (((_d = data.usage) === null || _d === void 0 ? void 0 : _d.input_tokens) || 0) + (((_e = data.usage) === null || _e === void 0 ? void 0 : _e.output_tokens) || 0)
},
rawResponse: data
};
});
}
/**
* 支持多模态输入的Claude对话
*/
chatCompletion(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
const model = params.model || this.model;
// 将ChatMessage[]转换为Claude消息格式
const claudeMessages = this.convertToCloudeMessages(params.messages);
// 构建请求体
const requestBody = {
model,
messages: claudeMessages,
max_tokens: params.maxTokens || 1000,
temperature: (_a = params.temperature) !== null && _a !== void 0 ? _a : 0.7,
stream: params.stream || false
};
// 添加系统消息
if (params.systemMessage) {
requestBody.system = params.systemMessage;
}
// 添加topP
if (params.topP !== undefined) {
requestBody.top_p = params.topP;
}
// 添加工具定义
if (params.tools && params.tools.length > 0) {
requestBody.tools = params.tools;
}
// 发送请求并获取响应
const data = yield this.sendClaudeRequest('/messages', requestBody);
return {
text: this.extractTextFromContent(data.content),
usage: {
promptTokens: ((_b = data.usage) === null || _b === void 0 ? void 0 : _b.input_tokens) || 0,
completionTokens: ((_c = data.usage) === null || _c === void 0 ? void 0 : _c.output_tokens) || 0,
totalTokens: (((_d = data.usage) === null || _d === void 0 ? void 0 : _d.input_tokens) || 0) + (((_e = data.usage) === null || _e === void 0 ? void 0 : _e.output_tokens) || 0)
},
rawResponse: data
};
});
}
/**
* 创建流式输出的聊天会话
*/
createStreamingChatCompletion(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const model = params.model || this.model;
// 将ChatMessage[]转换为Claude消息格式
const claudeMessages = this.convertToCloudeMessages(params.messages);
// 构建请求体
const requestBody = {
model,
messages: claudeMessages,
max_tokens: params.maxTokens || 1000,
temperature: (_a = params.temperature) !== null && _a !== void 0 ? _a : 0.7,
stream: true
};
// 添加系统消息
if (params.systemMessage) {
requestBody.system = params.systemMessage;
}
// 添加topP
if (params.topP !== undefined) {
requestBody.top_p = params.topP;
}
// 添加工具定义
if (params.tools && params.tools.length > 0) {
requestBody.tools = params.tools;
}
// 获取流式响应
return this.sendClaudeStreamRequest('/messages', requestBody);
});
}
/**
* 生成JSON格式响应
*/
generateJSON(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
const model = params.model || this.model;
// 构建消息
const messages = [{
role: 'user',
content: params.prompt
}];
// 添加JSON格式要求
const systemMessage = (params.systemMessage || '') +
'\n请以有效的JSON格式返回响应,不要包含额外的文本说明。';
// 构建请求体
const requestBody = {
model,
messages,
system: systemMessage,
max_tokens: params.maxTokens || 1000,
temperature: (_a = params.temperature) !== null && _a !== void 0 ? _a : 0.7
};
// 添加topP(如果指定)
if (params.topP !== undefined) {
requestBody.top_p = params.topP;
}
// 发送请求并获取响应
const data = yield this.sendClaudeRequest('/messages', requestBody);
// 提取JSON文本
const jsonText = this.extractTextFromContent(data.content);
try {
// 解析JSON
const jsonData = JSON.parse(jsonText);
return {
data: jsonData,
usage: {
promptTokens: ((_b = data.usage) === null || _b === void 0 ? void 0 : _b.input_tokens) || 0,
completionTokens: ((_c = data.usage) === null || _c === void 0 ? void 0 : _c.output_tokens) || 0,
totalTokens: (((_d = data.usage) === null || _d === void 0 ? void 0 : _d.input_tokens) || 0) + (((_e = data.usage) === null || _e === void 0 ? void 0 : _e.output_tokens) || 0)
}
};
}
catch (error) {
throw new Error(`[${this.name}] 解析JSON响应失败: ${error.message}`);
}
});
}
/**
* 计算消息的token数量
*/
countTokens(messages, systemMessage) {
return __awaiter(this, void 0, void 0, function* () {
const claudeMessages = this.convertToCloudeMessages(messages);
const requestBody = {
model: this.model,
messages: claudeMessages
};
if (systemMessage) {
requestBody.system = systemMessage;
}
const data = yield this.sendClaudeRequest('/messages/count_tokens', requestBody);
return {
input_tokens: data.input_tokens
};
});
}
/**
* 发送Claude API请求
*/
sendClaudeRequest(endpoint, body) {
return __awaiter(this, void 0, void 0, function* () {
const headers = {
'Content-Type': 'application/json',
'x-api-key': this.apiKey || '',
'anthropic-version': this.anthropicVersion
};
let retries = 0;
while (retries <= this.maxRetries) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const response = yield fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers,
body: JSON.stringify(body),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const errorData = yield response.json().catch(() => ({}));
throw new Error(`API请求失败: ${response.status} ${response.statusText} - ${JSON.stringify(errorData)}`);
}
return yield response.json();
}
catch (error) {
retries++;
if (retries > this.maxRetries) {
if (error instanceof Error) {
throw new Error(`[${this.name}] ${error.message}`);
}
throw error;
}
// 指数退避重试
const delay = Math.min(1000 * Math.pow(2, retries), 10000);
yield new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error(`[${this.name}] 达到最大重试次数`);
});
}
/**
* 发送Claude流式API请求
*/
sendClaudeStreamRequest(endpoint, body) {
return __awaiter(this, void 0, void 0, function* () {
const headers = {
'Content-Type': 'application/json',
'x-api-key': this.apiKey || '',
'anthropic-version': this.anthropicVersion,
'Accept': 'text/event-stream'
};
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const response = yield fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers,
body: JSON.stringify(body),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const errorData = yield response.json().catch(() => ({}));
throw new Error(`API请求失败: ${response.status} ${response.statusText} - ${JSON.stringify(errorData)}`);
}
if (!response.body) {
throw new Error('响应没有可读流');
}
return response.body;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`[${this.name}] ${error.message}`);
}
throw error;
}
});
}
/**
* 从Claude内容块中提取文本
*/
extractTextFromContent(content) {
return content
.filter(item => item.type === 'text')
.map(item => item.text || '')
.join('');
}
/**
* 将文本带图像提示发送到Claude
* 支持URL或Base64编码图像
*/
generateTextWithImage(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
const model = params.model || this.model;
// 构建多模态内容
const content = [];
// 添加图像内容(如果有)
if (params.image) {
if (params.image.url) {
content.push({
type: 'image',
source: {
type: 'url',
url: params.image.url
}
});
}
else if (params.image.base64Data) {
content.push({
type: 'image',
source: {
type: 'base64',
media_type: params.image.mimeType || 'image/jpeg',
data: params.image.base64Data
}
});
}
}
// 添加文档内容(如果有)
if (params.document) {
if (params.document.url) {
content.push({
type: 'document',
source: {
type: 'url',
url: params.document.url
}
});
}
else if (params.document.base64Data) {
content.push({
type: 'document',
source: {
type: 'base64',
media_type: params.document.mimeType || 'application/pdf',
data: params.document.base64Data
}
});
}
}
// 添加文本内容
content.push({
type: 'text',
text: params.prompt
});
// 构建请求消息
const messages = [{
role: 'user',
content
}];
// 构建请求体
const requestBody = {
model,
messages,
max_tokens: params.maxTokens || 1000,
temperature: (_a = params.temperature) !== null && _a !== void 0 ? _a : 0.7,
stream: params.stream || false
};
// 添加系统消息(如果有)
if (params.systemMessage) {
requestBody.system = params.systemMessage;
}
// 添加top_p(如果指定)
if (params.topP !== undefined) {
requestBody.top_p = params.topP;
}
// 发送请求并获取响应
const data = yield this.sendClaudeRequest('/messages', requestBody);
return {
text: this.extractTextFromContent(data.content),
usage: {
promptTokens: ((_b = data.usage) === null || _b === void 0 ? void 0 : _b.input_tokens) || 0,
completionTokens: ((_c = data.usage) === null || _c === void 0 ? void 0 : _c.output_tokens) || 0,
totalTokens: (((_d = data.usage) === null || _d === void 0 ? void 0 : _d.input_tokens) || 0) + (((_e = data.usage) === null || _e === void 0 ? void 0 : _e.output_tokens) || 0)
},
rawResponse: data
};
});
}
/**
* 将通用ChatMessage格式转换为Claude消息格式
*/
convertToCloudeMessages(messages) {
return messages.map(msg => {
// Claude不支持function或tool角色,忽略它们或转换为用户消息
const role = msg.role === 'function' || msg.role === 'tool'
? 'user'
: (msg.role === 'system' ? 'user' : msg.role);
// 简单文本内容
if (typeof msg.content === 'string') {
return {
role,
content: msg.content
};
}
// 处理复杂内容(数组,可能包含多模态内容)
if (Array.isArray(msg.content)) {
// 将内容转换为Claude格式
const claudeContent = msg.content.map(item => {
// 文本内容
if (typeof item === 'string' || (item && item.type === 'text')) {
return {
type: 'text',
text: typeof item === 'string' ? item : (item.text || '')
};
}
// 图像内容
if (item && item.type === 'image' && item.image_url) {
return {
type: 'image',
source: {
type: 'url',
url: item.image_url.url
}
};
}
// 文档内容
if (item && item.type === 'document' && item.document_url) {
return {
type: 'document',
source: {
type: 'url',
url: item.document_url.url
}
};
}
// 其他内容类型
return {
type: 'text',
text: typeof item === 'object' ? JSON.stringify(item) : String(item)
};
});
return {
role,
content: claudeContent
};
}
// 默认处理
return {
role,
content: String(msg.content || '')
};
});
}
}
exports.AnthropicProvider = AnthropicProvider;
//# sourceMappingURL=anthropic.js.map