UNPKG

contaigents

Version:

Modular AI Content Ecosystem with Audio Generation

140 lines (139 loc) 5.23 kB
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", }, ], };