Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
249 lines
5.9 KiB
JavaScript
249 lines
5.9 KiB
JavaScript
const axios = require('axios');
|
|
|
|
function providerErrorMessage(error) {
|
|
const data = error.response?.data;
|
|
if (data && typeof data === 'object' && !data.readable) {
|
|
return data.error?.message || data.message || error.message;
|
|
}
|
|
return error.response?.status
|
|
? `HTTP ${error.response.status}: ${error.response.statusText || error.message}`
|
|
: error.message;
|
|
}
|
|
|
|
/**
|
|
* Base LLM Provider class
|
|
*/
|
|
class BaseLLMProvider {
|
|
constructor(config, apiKey) {
|
|
this.config = config;
|
|
this.apiKey = apiKey;
|
|
}
|
|
|
|
async createChatCompletion(messages, options = {}) {
|
|
throw new Error('createChatCompletion method must be implemented by subclass');
|
|
}
|
|
|
|
/**
|
|
* Prepare headers for API request
|
|
* @returns {Object} Headers object
|
|
*/
|
|
getHeaders() {
|
|
return {
|
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
'Content-Type': 'application/json'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Prepare request payload
|
|
* @param {Array} messages - Chat messages
|
|
* @param {Object} options - Additional options
|
|
* @returns {Object} Request payload
|
|
*/
|
|
getRequestPayload(messages, options = {}) {
|
|
return {
|
|
model: this.config.model,
|
|
messages: messages,
|
|
stream: true,
|
|
max_tokens: options.max_tokens || 4096,
|
|
...options
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* OpenAI LLM Provider
|
|
*/
|
|
class OpenAILLMProvider extends BaseLLMProvider {
|
|
async createChatCompletion(messages, options = {}) {
|
|
try {
|
|
const payload = this.getRequestPayload(messages, options);
|
|
const headers = this.getHeaders();
|
|
|
|
console.log('OpenAI LLM Request:', {
|
|
model: payload.model,
|
|
messagesCount: messages.length,
|
|
stream: payload.stream
|
|
});
|
|
|
|
const response = await axios.post(
|
|
this.config.apiUrl,
|
|
payload,
|
|
{
|
|
headers: headers,
|
|
cancelToken: options.cancelToken,
|
|
responseType: 'stream'
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
response: response,
|
|
provider: 'openai'
|
|
};
|
|
|
|
} catch (error) {
|
|
const message = providerErrorMessage(error);
|
|
console.error('OpenAI LLM error:', message);
|
|
return {
|
|
success: false,
|
|
error: message,
|
|
provider: 'openai'
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* OpenRouter LLM Provider (supports both GPT-4o and Gemini)
|
|
*/
|
|
class OpenRouterLLMProvider extends BaseLLMProvider {
|
|
getHeaders() {
|
|
return {
|
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
'HTTP-Referer': 'https://live-audio-chat.local',
|
|
'X-Title': 'Live Audio Chat'
|
|
};
|
|
}
|
|
|
|
async createChatCompletion(messages, options = {}) {
|
|
try {
|
|
const payload = this.getRequestPayload(messages, options);
|
|
const headers = this.getHeaders();
|
|
|
|
console.log('OpenRouter LLM Request:', {
|
|
model: payload.model,
|
|
messagesCount: messages.length,
|
|
stream: payload.stream
|
|
});
|
|
|
|
const response = await axios.post(
|
|
this.config.apiUrl,
|
|
payload,
|
|
{
|
|
headers: headers,
|
|
cancelToken: options.cancelToken,
|
|
responseType: 'stream'
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
response: response,
|
|
provider: 'openrouter'
|
|
};
|
|
|
|
} catch (error) {
|
|
const message = providerErrorMessage(error);
|
|
console.error('OpenRouter LLM error:', message);
|
|
return {
|
|
success: false,
|
|
error: message,
|
|
provider: 'openrouter'
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ARK (Doubao) LLM Provider
|
|
*/
|
|
class ARKLLMProvider extends BaseLLMProvider {
|
|
getHeaders() {
|
|
return {
|
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
'Content-Type': 'application/json'
|
|
};
|
|
}
|
|
|
|
getRequestPayload(messages, options = {}) {
|
|
// ARK API format is similar to OpenAI but may have slight differences
|
|
return {
|
|
model: this.config.model,
|
|
messages: messages,
|
|
stream: true,
|
|
max_tokens: options.max_tokens || 4096,
|
|
temperature: options.temperature || 0.7,
|
|
...options
|
|
};
|
|
}
|
|
|
|
async createChatCompletion(messages, options = {}) {
|
|
try {
|
|
const payload = this.getRequestPayload(messages, options);
|
|
const headers = this.getHeaders();
|
|
|
|
console.log('ARK (Doubao) LLM Request:', {
|
|
model: payload.model,
|
|
messagesCount: messages.length,
|
|
stream: payload.stream
|
|
});
|
|
|
|
const response = await axios.post(
|
|
this.config.apiUrl,
|
|
payload,
|
|
{
|
|
headers: headers,
|
|
cancelToken: options.cancelToken,
|
|
responseType: 'stream'
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
response: response,
|
|
provider: 'ark'
|
|
};
|
|
|
|
} catch (error) {
|
|
const message = providerErrorMessage(error);
|
|
console.error('ARK (Doubao) LLM error:', message);
|
|
return {
|
|
success: false,
|
|
error: message,
|
|
provider: 'ark'
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* LLM Provider Factory
|
|
*/
|
|
class LLMProviderFactory {
|
|
static createProvider(providerName, config, globalConfig) {
|
|
const providerConfig = config.LLM_PROVIDERS[providerName];
|
|
if (!providerConfig) {
|
|
throw new Error(`LLM provider ${providerName} not found in configuration`);
|
|
}
|
|
|
|
// Get API key from global config
|
|
const apiKey = globalConfig[providerConfig.apiKey];
|
|
if (!apiKey) {
|
|
throw new Error(`API key ${providerConfig.apiKey} not found in configuration`);
|
|
}
|
|
|
|
switch (providerName) {
|
|
case 'openai':
|
|
return new OpenAILLMProvider(providerConfig, apiKey);
|
|
case 'openrouter':
|
|
case 'openrouter-gpt':
|
|
case 'openrouter-gemini':
|
|
return new OpenRouterLLMProvider(providerConfig, apiKey);
|
|
case 'ark':
|
|
return new ARKLLMProvider(providerConfig, apiKey);
|
|
default:
|
|
throw new Error(`Unsupported LLM provider: ${providerName}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
BaseLLMProvider,
|
|
OpenAILLMProvider,
|
|
OpenRouterLLMProvider,
|
|
ARKLLMProvider,
|
|
LLMProviderFactory
|
|
};
|