sambanova
Version:
TypeScript/Javascript client for Sambanova AI API with comprehensive model support
146 lines (145 loc) • 6.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SambanovaError = exports.SambanovaClient = void 0;
const utils_1 = require("./utils");
const types_1 = require("./types");
const utils_2 = require("./utils");
class SambanovaClient {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.baseUrl = options.baseUrl || 'https://api.sambanova.ai/v1';
this.defaultModel = options.defaultModel || 'Meta-Llama-3.2-3B-Instruct';
this.defaultRetryCount = options.defaultRetryCount || 3;
this.defaultRetryDelay = options.defaultRetryDelay || 1000;
}
async makeRequest(endpoint, data, retryCount = this.defaultRetryCount, stream = false) {
let lastError = null;
for (let attempt = 0; attempt <= retryCount; attempt++) {
try {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify(data)
});
if (!response.ok) {
const errorData = await response.json();
throw new types_1.SambanovaError(errorData.message || 'API request failed', response.status, errorData.code, errorData);
}
if (stream) {
return response;
}
return await response.json();
}
catch (error) {
lastError = error;
if (attempt < retryCount) {
await (0, utils_1.sleep)(this.defaultRetryDelay * Math.pow(2, attempt));
continue;
}
}
}
throw lastError || new Error('Request failed after retries');
}
async chat(messages, options = {}) {
var _a, _b, _c, _d;
const model = options.model || this.defaultModel;
if ((0, utils_1.isVisionModel)(model)) {
for (const msg of messages) {
if (Array.isArray(msg.content)) {
for (const content of msg.content) {
if (content.type === 'image_url' && ((_a = content.image_url) === null || _a === void 0 ? void 0 : _a.url)) {
try {
content.image_url.url = await (0, utils_2.getBase64Image)(content.image_url.url);
}
catch (error) {
throw new types_1.SambanovaError(`Failed to process image: ${error}`, 400, 'INVALID_IMAGE_FORMAT');
}
}
}
}
}
}
messages.forEach(msg => (0, utils_1.validateMessage)(msg, (0, utils_1.isVisionModel)(model)));
const payload = {
model,
messages,
temperature: (_b = options.temperature) !== null && _b !== void 0 ? _b : 0.1,
top_p: (_c = options.top_p) !== null && _c !== void 0 ? _c : 0.1,
max_tokens: options.max_tokens,
stream: (_d = options.stream) !== null && _d !== void 0 ? _d : false
};
const response = await this.makeRequest('/chat/completions', payload, options.retry_count, payload.stream);
if (payload.stream && response instanceof Response) {
throw new Error('Stream response received in chat method. Use streamChat instead.');
}
return response;
}
async *streamChat(messages, options = {}) {
var _a, _b, _c, _d, _e, _f;
const model = options.model || this.defaultModel;
if ((0, utils_1.isVisionModel)(model)) {
for (const msg of messages) {
if (Array.isArray(msg.content)) {
for (const content of msg.content) {
if (content.type === 'image_url' && ((_a = content.image_url) === null || _a === void 0 ? void 0 : _a.url)) {
try {
content.image_url.url = await (0, utils_2.getBase64Image)(content.image_url.url);
}
catch (error) {
throw new types_1.SambanovaError(`Failed to process image: ${error}`, 400, 'INVALID_IMAGE_FORMAT');
}
}
}
}
}
}
const payload = {
model,
messages,
temperature: (_b = options.temperature) !== null && _b !== void 0 ? _b : 0.1,
top_p: (_c = options.top_p) !== null && _c !== void 0 ? _c : 0.1,
max_tokens: options.max_tokens,
stream: true,
stream_options: { include_usage: true } // Optional
};
const response = await this.makeRequest('/chat/completions', payload, options.retry_count, true);
if (!response ||
!('body' in response) ||
typeof response.body.getReader !== 'function') {
throw new Error('Expected a streaming response');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done)
break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.trim().startsWith('data: ')) {
const dataStr = line.trim().slice(6);
if (dataStr === '[DONE]')
return;
try {
const chunk = JSON.parse(dataStr);
const content = (_f = (_e = (_d = chunk.choices) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.delta) === null || _f === void 0 ? void 0 : _f.content;
if (content)
yield content;
}
catch (error) {
console.error('Failed to parse stream data:', error);
}
}
}
}
}
}
exports.SambanovaClient = SambanovaClient;
var types_2 = require("./types");
Object.defineProperty(exports, "SambanovaError", { enumerable: true, get: function () { return types_2.SambanovaError; } });