import {__} from '@wordpress/i18n' import { addQueryArgs, } from '@wordpress/url' import { debugError, debugInfo, } from '@ska/utils' import type { AIMode, OpenRouterErrorResponse, OpenRouterModelsResponse, OpenRouterRequest, OpenRouterResponse, } from '../types' export interface OpenRouterRequestOptions { mode?: AIMode /** No API key or testing. */ mockResponse?: boolean signal?: AbortSignal } const COMPLETIONS_URL = 'https://openrouter.ai/api/v1/chat/completions' const MODELS_URL = 'https://openrouter.ai/api/v1/models' const isAborted = (err: any) => err && typeof err === 'object' && 'name' in err && err.name === 'AbortError' export const openRouterRequest = async (request: OpenRouterRequest, apiKey: string, opts: OpenRouterRequestOptions = {}) => { const { mode = 'html', mockResponse = false, signal, } = opts if(!apiKey || mockResponse) { try { await new Promise((resolve, reject) => { const resolveTimeout = setTimeout(resolve, 1000) signal?.addEventListener('abort', () => { clearTimeout(resolveTimeout) reject(new DOMException('Aborted', 'AbortError')) }) }) } catch(err) { return { code: -1, message: isAborted(err) ? 'Aborted OpenRouter API request.' : 'This is a mock error response from the OpenRouter API.', } as OpenRouterErrorResponse } const mockResponseText = `This is a mock response from the OpenRouter API.${apiKey ? '' : ' API key is not provided.'}` const timeString = new Date().toTimeString().split(' ')[0] return { id: 'mock-response-id', choices: [ { finish_reason: 'stop', native_finish_reason: 'stop', message: { content: mode === 'html' ? `
${mockResponseText}
` : ( mode === 'seo' ? `[{"title":"Elephants: Giant Brains & Trunk Tricks! ${timeString}","description":"Discover the smart, emotional giants! Elephants use trunks like Swiss Army knives for tasks like communication, golf, nutcracking, and lunch. Understand E. intelligent behavior, how they creatively use tools, and explore The Knowledge Little Trunks May Carry.","slug":"elephants-big-brains-with-trunk"},{"title":"Why Elephants Are Nature's Furries","description":"Elephants: Nature's gentle giants! Matriarchs rule & family is everything. Think proud moms, complex emotions, & amazing ecosystem architects!","slug":"elephants-gentle-herds"},{"title":"Elephants vs. The World | Let's Trunk it Out!","description":"Explore the emotional giants! Elephants shape landscapes, unfold family dramas, cross rivers for water. Dive in to the lives of our largest land mammals and learn just how amazing these creatures are.","slug":"elephant-world-trunks"},{"title":"Elephant Trunks: The Original Multi-Tool","description":" Discover why elephants have trunks of might! These nature's tool have many capabilities such as communication,singing, and also for lifting. From breathing to balancing, elephants' trunks have you covered!","slug":"elephants-trunks-mult-tool"},{"title":"Discover Why Elephants Rule The Land","description":"Great naval battles, intense romance, nurturing herds. Elephants' emotional roller-coasters include grief, joy and sharing chemical love tricks, like the Aussie animals before them, these intelligent animals also like to sing songs about love, mate selection exists, further Odysses evolve.","slug":"elephants-world-nature"}]` : mockResponseText ), role: 'assistant', }, }, ], created: Math.floor(Date.now() / 1000), // Current Unix timestamp model: 'mock-model', object: 'chat.completion', usage: { prompt_tokens: 10, completion_tokens: 15, total_tokens: 25, }, } as OpenRouterResponse } try { const response = await fetch(COMPLETIONS_URL, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://ska-blocks.com', // Site URL for rankings on openrouter.ai. 'X-Title': 'ska-blocks', // Site title for rankings on openrouter.ai. }, body: JSON.stringify(request), signal, }) const json = await response.json() as OpenRouterResponse | {error: OpenRouterErrorResponse} debugInfo('OpenRouter API response.', json) if('error' in json) { return json.error } return json } catch(err: any) { debugError('OpenRouter API request failed.', err) return { code: err?.code || -1, message: isAborted(err) ? 'Aborted OpenRouter API request.' : (err?.message || 'OpenRouter API request failed.'), } as OpenRouterErrorResponse } } export interface OpenRouterModelRequestOptions { /** Query args. */ args?: { category?: string } signal?: AbortSignal } export const fetchModels = async (opts: OpenRouterModelRequestOptions = {}) => { const { args = {}, signal, } = opts const response = await fetch(addQueryArgs(MODELS_URL, args), { method: 'GET', signal, }) if(!response.ok) { throw new Error('OpenRouter API request failed.') } const json = await response.json() as OpenRouterModelsResponse// | {error: OpenRouterErrorResponse} debugInfo('OpenRouter API response.', json) if(!('data' in json)) { throw new Error('No data in response.') } return json.data }