/** * M5 JavaScript SDK */ class M5Client { constructor(apiKey, baseUrl = 'https://m5.hf.space') { this.apiKey = apiKey; this.baseUrl = baseUrl.replace(/\/$/, ''); this.headers = { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }; } async chatCompletion(options) { const { model, messages, temperature = 0.7, maxTokens = null, stream = false, ollamaUrl = null } = options; const payload = { model, messages, temperature, stream }; if (maxTokens) payload.max_tokens = maxTokens; if (ollamaUrl) payload.ollama_url = ollamaUrl; const response = await fetch(`${this.baseUrl}/v1/chat/completions`, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } async *chatCompletionStream(options) { const { model, messages, temperature = 0.7, maxTokens = null, ollamaUrl = null } = options; const payload = { model, messages, temperature, stream: true }; if (maxTokens) payload.max_tokens = maxTokens; if (ollamaUrl) payload.ollama_url = ollamaUrl; const response = await fetch(`${this.baseUrl}/v1/chat/completions`, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); const lines = chunk.split('\n'); for (const line of lines) { if (!line.startsWith('data: ')) continue; const data = line.slice(6).trim(); if (data === '[DONE]') break; try { const parsed = JSON.parse(data); if (parsed.choices && parsed.choices[0]) { const delta = parsed.choices[0].delta; if (delta && delta.content) { yield delta.content; } } } catch (e) { // Skip invalid JSON } } } } async listModels() { const response = await fetch(`${this.baseUrl}/v1/models`, { headers: this.headers }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data.data || []; } } // Convenience classes class Chat { constructor(client) { this.client = client; } async create(options) { return await this.client.chatCompletion(options); } async *createStream(options) { yield* this.client.chatCompletionStream(options); } } class M5 { constructor(apiKey, baseUrl = 'https://m5.hf.space') { this.client = new M5Client(apiKey, baseUrl); this.chat = new Chat(this.client); } } // Export for Node.js if (typeof module !== 'undefined' && module.exports) { module.exports = { M5, M5Client, Chat }; } // Export for browser if (typeof window !== 'undefined') { window.M5 = M5; window.M5Client = M5Client; window.Chat = Chat; }