sam12345324's picture
Upload server/services/opencode.js with huggingface_hub
9849557 verified
import fetch from 'node-fetch';
const MODELS = [
'minimax-m2.5-free', // Only working free model as of 2026-05-04
];
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export async function generateHyperFramesCode(userPrompt, systemPrompt) {
let lastError = null;
// Try each model, with a retry on rate limit
for (const model of MODELS) {
for (let attempt = 0; attempt < 2; attempt++) {
try {
if (attempt > 0) {
console.log(`Retry ${attempt} for model: ${model} after rate limit delay...`);
await sleep(5000);
}
console.log(`Trying model: ${model} (attempt ${attempt + 1})`);
const result = await callModel(model, userPrompt, systemPrompt);
if (result && result.trim().length > 100) {
console.log(`Success with ${model} (${result.length} chars)`);
return result;
}
console.log(`Model ${model} returned insufficient output (${result?.length || 0} chars), trying next...`);
break;
} catch (err) {
console.error(`Model ${model} attempt ${attempt + 1} failed:`, err.message);
lastError = err;
if (err.message.includes('429') && attempt === 0) {
continue;
}
break;
}
}
}
throw lastError || new Error('All AI models failed to generate code');
}
async function callModel(model, userPrompt, systemPrompt) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 180000); // 3 min timeout
// Generate random user_id to bypass rate limits
const randomUserId = `user_${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`;
try {
const response = await fetch('https://opencode.ai/zen/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer public',
'x-opencode-client': 'desktop',
'x-opencode-user-id': randomUserId,
'Accept': 'text/event-stream',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
body: JSON.stringify({
model,
messages: [
{ role: 'system', content: 'You are a code generator. Output ONLY code, no explanations, no reasoning, no commentary. Start directly with the code block.' },
{ role: 'system', content: 'CRITICAL FONT RULE: You MUST use ONLY these fonts: Arial, Helvetica, "Arial Black", Verdana, Tahoma, "Trebuchet MS", Impact, Georgia, "Times New Roman", "Courier New". NEVER use Google Fonts, web fonts, or fonts not in this list. They cause 404 errors.' },
{ role: 'system', content: 'CRITICAL GSAP RULE: Every GSAP selector (e.g., "#scene-2 .flare-pulse") MUST match an element that EXISTS in your HTML. Never animate elements you did not create. Check your HTML before writing animations.' },
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
temperature: 0.7,
max_tokens: 8000,
stream: true
}),
signal: controller.signal
});
if (!response.ok) {
const errText = await response.text().catch(() => '');
throw new Error(`API returned ${response.status}: ${errText.slice(0, 200)}`);
}
let fullContent = '';
let buffer = '';
// Read response body as text stream
for await (const chunk of response.body) {
// Decode chunk as UTF-8
const text = chunk.toString('utf-8');
buffer += text;
// Process complete lines
const lines = buffer.split('\n');
buffer = lines.pop() || ''; // Keep incomplete line in buffer
for (const line of lines) {
if (!line.trim() || !line.startsWith('data:')) {
continue;
}
const data = line.slice(5).trim();
if (data === '[DONE]') {
break;
}
try {
const event = JSON.parse(data);
const choices = event.choices || [];
if (choices.length > 0) {
const delta = choices[0].delta || {};
// Only collect content field, ignore reasoning (minimax is a thinking model)
const content = delta.content || '';
if (content) {
fullContent += content;
}
}
} catch (e) {
// Skip malformed JSON chunks
}
}
}
// Extract HTML from markdown code blocks if present
const htmlMatch = fullContent.match(/```html\n([\s\S]*?)\n```/);
if (htmlMatch) {
return htmlMatch[1];
}
// Try to find raw HTML (look for complete HTML document)
const docTypeMatch = fullContent.match(/(<!doctype html[\s\S]*?<\/html>)/i);
if (docTypeMatch) {
return docTypeMatch[1];
}
// If no HTML found, throw error with preview of what we got
const preview = fullContent.substring(0, 200);
throw new Error(`AI did not generate valid HTML. Got: ${preview}...`);
} finally {
clearTimeout(timeout);
}
}