import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import '../http_client.dart'; import '../http_util.dart'; import '../models.dart'; import 'base_provider.dart'; import 'webview_base_provider.dart'; class TeachAnything extends BaseProvider { @override String get name => 'TeachAnything'; @override String get url => 'https://www.teach-anything.com'; @override bool get working => true; @override Duration get requestTimeout => const Duration(seconds: 90); @override List get models => ['gemma']; @override String get defaultModel => 'gemma'; @override Stream createAsyncGenerator( String model, List messages, { bool stream = false, }) async* { try { yield await _rest(messages); return; } catch (e) { debugPrint('TeachAnything REST failed, trying origin WebView: $e'); } yield await _viaWebView(messages); } Future _rest(List messages) async { final prompt = formatPrompt(messages); final req = http.Request('POST', Uri.parse('$url/api/generate')); req.headers.addAll({ 'accept': '*/*', 'accept-language': 'en-US,en;q=0.9', 'cache-control': 'no-cache', 'content-type': 'application/json', 'origin': url, 'referer': '$url/', 'user-agent': kDesktopUserAgent, }); req.body = jsonEncode({'prompt': prompt}); final response = await g4fHttp.send(req).timeout(requestTimeout); if (response.statusCode != 200) { throw Exception('$name returned status ${response.statusCode}'); } final fullText = utf8.decode(await response.stream.toBytes()).trim(); if (!looksLikeModelOutput(fullText)) throw Exception('$name empty'); return fullText; } Future _viaWebView(List messages) async { final promptJson = jsonEncode(formatPrompt(messages)); final raw = await runOriginWebView( originUrl: url, timeout: requestTimeout, functionBody: ''' const prompt = $promptJson; const r = await fetch('/api/generate', { method: 'POST', headers: { 'content-type': 'application/json', 'accept': '*/*' }, credentials: 'same-origin', body: JSON.stringify({ prompt }) }); if (!r.ok) throw new Error('status ' + r.status); return await r.text(); ''', ); final text = raw.trim(); if (!looksLikeModelOutput(text)) { throw Exception( 'TeachAnything WebView unusable: ${text.substring(0, text.length.clamp(0, 180))}', ); } return text; } }