contaigents
Version:
Modular AI Content Ecosystem with Audio Generation
140 lines (139 loc) • 5.23 kB
JavaScript
import { BaseLLM } from "./BaseLLM.js";
export class ReplicateProvider extends BaseLLM {
constructor() {
super(ReplicateProvider.providerConfig);
}
async executePrompt(prompt, options = {}) {
if (!this.isConfigured()) {
throw new Error("Replicate provider is not configured");
}
const response = await fetch(`https://api.replicate.com/v1/models/${this.config.model}/predictions`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.config.apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
input: {
prompt: prompt,
max_new_tokens: options.maxTokens || 512,
temperature: options.temperature || 0.7,
prompt_template: "<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n{system_prompt}<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n{prompt}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n",
},
stream: true,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Replicate API error: ${error.detail || "Unknown error"}`);
}
const data = await response.json();
const streamUrl = data.urls.stream;
const streamResponse = await fetch(streamUrl, {
headers: {
Accept: "text/event-stream",
"Cache-Control": "no-store",
},
});
if (!streamResponse.ok) {
throw new Error(`Failed to fetch stream: ${streamResponse.statusText}`);
}
const reader = streamResponse.body?.getReader();
if (!reader) {
throw new Error("Failed to get reader from stream response");
}
let content = "";
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done)
break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data:')) {
const jsonStr = line.slice(5); // Remove 'data: ' prefix, but don't trim
try {
const eventData = JSON.parse(jsonStr);
if (eventData.output) {
content += eventData.output;
}
}
catch (e) {
// If it's not JSON, just append the raw content
const cleanContent = line.slice(5); // Remove 'data: ' prefix, but don't trim
if (cleanContent) {
content += cleanContent;
}
}
}
}
}
return {
content: content.trim(), // Only trim the final result
raw: {
promptTokens: 0,
completionTokens: 0,
totalTokens: 0,
},
};
}
async imagine(prompt, options = {}) {
if (!this.isConfigured()) {
throw new Error("Replicate provider is not configured");
}
const modelName = options.model || "minimax/image-01";
const response = await fetch(`https://api.replicate.com/v1/models/${modelName}/predictions`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.config.apiKey}`,
"Content-Type": "application/json",
"Prefer": "wait"
},
body: JSON.stringify({
input: {
prompt,
aspect_ratio: options.aspect_ratio || "3:4",
number_of_images: options.number_of_images || 1,
prompt_optimizer: options.prompt_optimizer ?? true
}
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Replicate API error: ${error.detail || "Unknown error"}`);
}
const data = await response.json();
return {
urls: Array.isArray(data.output) ? data.output : [data.output],
raw: data
};
}
}
ReplicateProvider.providerConfig = {
name: "Replicate",
configFields: [
{
name: "apiKey",
label: "API Key",
type: "password",
required: true,
},
{
name: "model",
label: "Model",
type: "select",
required: true,
options: [
"meta/meta-llama-3-8b-instruct",
"meta/llama-2-70b-chat",
"meta/llama-2-13b-chat",
"mistralai/mixtral-8x7b-instruct",
"mistralai/mistral-7b-instruct",
"anthropic/claude-2",
"replicate/vicuna-13b"
],
default: "meta/llama-2-70b-chat",
},
],
};