Files
999/lib/g4f/providers/teach_anything.dart
Alma Alexyz fbf04d90db feat: embed a Flutter G4F client with Cronet, cookie jar, and origin WebView
Port the Oracle off the Python g4f container onto on-device providers: Chromium HTTP via Cronet, a shared cookie session, IterList retry, hosted OpenAI-compat aggregators, and same-origin WebView fallbacks instead of CORS fetch.
2026-09-01 22:05:38 +05:00

95 lines
2.6 KiB
Dart

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<String> get models => ['gemma'];
@override
String get defaultModel => 'gemma';
@override
Stream<String> createAsyncGenerator(
String model,
List<Message> 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<String> _rest(List<Message> 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<String> _viaWebView(List<Message> 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;
}
}