import 'dart:convert'; import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:http/http.dart' as http; import '../http_client.dart'; import '../models.dart'; import '../sse.dart'; import 'base_provider.dart'; class ChatGptOss extends BaseProvider { @override String get name => 'ChatGptOss'; @override bool get working => true; @override List get models => ['gpt-oss-120b', 'gpt-5-nano']; @override String get defaultModel => 'gpt-oss-120b'; String _generateFingerprint() { final seed = '${DateTime.now().millisecondsSinceEpoch / 1000.0}-${Random().nextDouble()}'; return md5.convert(utf8.encode(seed)).toString(); } @override Stream createAsyncGenerator( String model, List messages, { bool stream = false, }) async* { final prompt = formatPrompt(messages); final url = Uri.parse('https://chat-gpt-oss.com/api/message'); final payload = { "conversation_id": null, "model": model, "content": prompt, "reasoning_effort": "low", }; final req = http.Request('POST', url); req.headers.addAll({ "accept": "text/event-stream", "accept-language": "en-US,en;q=0.9", "cache-control": "no-cache", "content-type": "application/json", "origin": "https://chat-gpt-oss.com", "pragma": "no-cache", "referer": "https://chat-gpt-oss.com/", "sec-ch-ua": '"Chromium";v="148", "Google Chrome";v="148", "Not/A)Brand";v="99"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Linux"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36", "x-fingerprint": _generateFingerprint(), }); req.body = jsonEncode(payload); final response = await g4fHttp.send(req); if (response.statusCode == 200) { String? currentEvent; await for (final line in splitSseLines(response.stream.transform(utf8.decoder))) { final trimmed = line.trim(); if (trimmed.isEmpty) { currentEvent = null; continue; } if (trimmed.startsWith('event:')) { currentEvent = trimmed.substring(6).trim(); if (currentEvent == 'summary') { return; } continue; } if (trimmed.startsWith('data:') && currentEvent == 'message') { final dataStr = trimmed.substring(5).trim(); if (dataStr.isEmpty) continue; try { final jsonChunk = jsonDecode(dataStr); final content = jsonChunk['content'] as String?; if (content != null && content.isNotEmpty) { yield content; } } catch (_) {} } } } else { throw Exception('$name returned status ${response.statusCode}'); } } }