import { API_URL } from './config.js' let cachedIP = null async function getClientIP() { if (cachedIP) return cachedIP try { const controller = new AbortController() setTimeout(() => controller.abort(), 3000) const res = await fetch('https://api.ipify.org?format=json', { signal: controller.signal }) const data = await res.json() cachedIP = data.ip return cachedIP } catch { return null } } import { useSettingsStore } from '../stores/settings' export async function fetchSuggestion(prefix, suffix, signal, apiUrl = API_URL) { try { const settings = useSettingsStore() const clientIP = await getClientIP() const headers = { 'Content-Type': 'application/json' } // Only send IP if privacy mode is OFF if (clientIP && !settings.privacyMode) { headers['X-Client-IP'] = clientIP } const body = { prefix, suffix, languageId: 'markdown', model_thinking: settings.modelThinking, privacy_mode: settings.privacyMode, user_preferences: { language: settings.language, currency: settings.currency, timezone: settings.detectedTimezone } } const res = await fetch(apiUrl, { method: 'POST', headers, body: JSON.stringify(body), signal }) if (!res.ok) { const errorText = await res.text() throw new Error(`HTTP ${res.status}: ${errorText}`) } const reader = res.body?.getReader() if (!reader) { throw new Error('No reader available') } let text = '' let buffer = '' while (true) { const { done, value } = await reader.read() if (done) break buffer += new TextDecoder().decode(value) const lines = buffer.split('\n') buffer = lines.pop() || '' for (const line of lines) { if (!line.startsWith('data: ')) continue const jsonStr = line.slice(6).trim() if (!jsonStr) continue try { const data = JSON.parse(jsonStr) if (data.content) { text += data.content } if (data.done || data.error) break } catch (e) { // skip invalid lines } } } return text } catch (e) { if (e.name === 'AbortError') { // ignore abort } else { throw e } } }