kv-app/lib/api/opencode.ts

130 lines
No EOL
3.9 KiB
TypeScript

import { AIWorkflowNode } from '../types';
const API_BASE_URL = '/api/opencode';
export async function createWorkflowWithAI(
apiKey: string,
model: string,
userIdea: string
): Promise<{ nodes: AIWorkflowNode[] }> {
const systemPrompt = `You are a creative AI video workflow builder. When user gives a video idea, analyze it and create a structured workflow with 4 nodes: idea, script, image, video. For each node, provide a detailed prompt that can be used to generate content. Output valid JSON only with this exact structure:
{
"nodes": [
{ "type": "idea", "prompt": "..." },
{ "type": "script", "prompt": "..." },
{ "type": "image", "prompt": "..." },
{ "type": "video", "prompt": "..." }
]
}
Do not include any explanation or other text.`;
const response = await fetch(API_BASE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey,
model,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userIdea },
],
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `OpenCode API error: ${response.status}`);
}
const data = await response.json();
const content = data.choices?.[0]?.message?.content || '';
try {
const parsed = JSON.parse(content);
return parsed;
} catch (e) {
throw new Error('Failed to parse AI response as JSON');
}
}
export async function analyzeMediaWithAI(
apiKey: string,
model: string,
mediaType: 'image' | 'video',
mediaUrl: string
): Promise<{
contentSummary: string;
style: { lighting: string; colorPalette: string; mood: string };
motion: { type: string; transitions: string[]; duration: string };
script: string;
keyframes: { time: string; description: string }[];
}> {
const systemPrompt = `You are an expert video and image analyzer. Analyze the uploaded ${mediaType} and provide a detailed analysis in this exact JSON format:
{
"contentSummary": "Brief description of what's shown in the media",
"style": {
"lighting": "Description of lighting",
"colorPalette": "Main colors used",
"mood": "Overall mood/atmosphere"
},
"motion": {
"type": "Type of movement",
"transitions": ["transition1", "transition2"],
"duration": "Estimated duration"
},
"script": "Detailed scene description/script that matches the media",
"keyframes": [
{ "time": "0-2s", "description": "What's happening" },
{ "time": "2-4s", "description": "What's happening" },
{ "time": "4-6s", "description": "What's happening" },
{ "time": "6-8s", "description": "What's happening" }
]
}
Do not include any explanation or other text. Just output valid JSON.`;
const response = await fetch(API_BASE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey,
model,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `Analyze this ${mediaType}: ${mediaUrl}` },
],
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `OpenCode API error: ${response.status}`);
}
const data = await response.json();
const content = data.choices?.[0]?.message?.content || '';
try {
const parsed = JSON.parse(content);
return parsed;
} catch (e) {
throw new Error('Failed to parse AI analysis response');
}
}
export async function testOpenCodeConnection(apiKey: string, model: string): Promise<boolean> {
try {
const response = await fetch(API_BASE_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey,
model,
messages: [{ role: 'user', content: 'Hello' }],
max_tokens: 10,
}),
});
return response.ok;
} catch (e) {
return false;
}
}