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.
This commit is contained in:
+145
-1
@@ -2,9 +2,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'screens/history_screen.dart';
|
||||
import 'screens/home_search_screen.dart';
|
||||
import 'screens/oracle_chat_screen.dart';
|
||||
import 'screens/provider_bakeoff_screen.dart';
|
||||
import 'services/words_repository.dart';
|
||||
import 'widgets/gradient_star_badge.dart';
|
||||
|
||||
import 'g4f/client.dart';
|
||||
import 'g4f/models.dart';
|
||||
import 'g4f/providers/chatgpt_oss.dart';
|
||||
import 'g4f/providers/pollinations.dart';
|
||||
import 'g4f/providers/teach_anything.dart';
|
||||
import 'g4f/providers/yqcloud.dart';
|
||||
import 'g4f/providers/deep_ai.dart';
|
||||
import 'g4f/providers/phind_ai.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await WordsRepository().init();
|
||||
@@ -73,7 +84,9 @@ class _Words999AppState extends State<Words999App> {
|
||||
}),
|
||||
),
|
||||
),
|
||||
home: const MainNavigationContainer(),
|
||||
home: const bool.fromEnvironment('ORACLE_BAKEOFF')
|
||||
? const ProviderBakeoffScreen()
|
||||
: const MainNavigationContainer(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -119,6 +132,137 @@ class _MainNavigationContainerState extends State<MainNavigationContainer> {
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: GestureDetector(
|
||||
onLongPress: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const ProviderBakeoffScreen()),
|
||||
);
|
||||
},
|
||||
child: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const OracleChatScreen()),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.auto_awesome),
|
||||
label: const Text("ОРАКУЛ"),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _G4FTestHelper {
|
||||
Future<String> testAI() async {
|
||||
final client = G4FClient();
|
||||
// We access the providers from the client's internal list by just creating them here to test directly.
|
||||
// Or simply test the main client logic. To test all, we will test them individually.
|
||||
|
||||
// We import them dynamically inside the test to keep main.dart clean long-term
|
||||
final results = <String>[];
|
||||
final messages = [Message(role: Role.user, content: "Коротко ответь 'Работает' и добавь одно случайное эмодзи.")];
|
||||
|
||||
// Yqcloud
|
||||
try {
|
||||
print("⏳ Тестируем Yqcloud...");
|
||||
results.add("📡 Yqcloud: " + await _testProvider(client, "Yqcloud", messages));
|
||||
print("✅ Yqcloud ответил!");
|
||||
} catch (e) {
|
||||
print("❌ Yqcloud Ошибка: $e");
|
||||
results.add("❌ Yqcloud Ошибка: $e");
|
||||
}
|
||||
|
||||
// TeachAnything
|
||||
try {
|
||||
print("⏳ Тестируем TeachAnything...");
|
||||
results.add("📡 TeachAnything: " + await _testProvider(client, "TeachAnything", messages));
|
||||
print("✅ TeachAnything ответил!");
|
||||
} catch (e) {
|
||||
print("❌ TeachAnything Ошибка: $e");
|
||||
results.add("❌ TeachAnything Ошибка: $e");
|
||||
}
|
||||
|
||||
// ChatGptOss
|
||||
try {
|
||||
print("⏳ Тестируем ChatGptOss...");
|
||||
results.add("📡 ChatGptOss: " + await _testProvider(client, "ChatGptOss", messages));
|
||||
print("✅ ChatGptOss ответил!");
|
||||
} catch (e) {
|
||||
print("❌ ChatGptOss Ошибка: $e");
|
||||
results.add("❌ ChatGptOss Ошибка: $e");
|
||||
}
|
||||
|
||||
// Pollinations
|
||||
try {
|
||||
print("⏳ Тестируем Pollinations...");
|
||||
results.add("📡 Pollinations: " + await _testProvider(client, "Pollinations", messages));
|
||||
print("✅ Pollinations ответил!");
|
||||
} catch (e) {
|
||||
print("❌ Pollinations Ошибка: $e");
|
||||
results.add("❌ Pollinations Ошибка: $e");
|
||||
}
|
||||
|
||||
// DeepAi
|
||||
try {
|
||||
print("⏳ Тестируем DeepAi...");
|
||||
results.add("📡 DeepAi: " + await _testProvider(client, "DeepAi", messages));
|
||||
print("✅ DeepAi ответил!");
|
||||
} catch (e) {
|
||||
print("❌ DeepAi Ошибка: $e");
|
||||
results.add("❌ DeepAi Ошибка: $e");
|
||||
}
|
||||
|
||||
// PhindAi
|
||||
try {
|
||||
print("⏳ Тестируем PhindAi...");
|
||||
results.add("📡 PhindAi: " + await _testProvider(client, "PhindAi", messages));
|
||||
print("✅ PhindAi ответил!");
|
||||
} catch (e) {
|
||||
print("❌ PhindAi Ошибка: $e");
|
||||
results.add("❌ PhindAi Ошибка: $e");
|
||||
}
|
||||
|
||||
// DeepInfraWebView
|
||||
try {
|
||||
print("⏳ Тестируем DeepInfraWebView (в скрытом браузере)...");
|
||||
String finalResult = "";
|
||||
await for (final chunk in client.chat.completions.createStream(messages: messages)) {
|
||||
finalResult += chunk;
|
||||
}
|
||||
results.add("📡 DeepInfraWebView: $finalResult");
|
||||
print("✅ DeepInfraWebView ответил!");
|
||||
} catch (e) {
|
||||
print("❌ DeepInfraWebView Ошибка: $e");
|
||||
results.add("❌ DeepInfraWebView Ошибка: $e");
|
||||
}
|
||||
|
||||
print("🎉 Все тесты завершены!");
|
||||
return results.join("\\n\\n");
|
||||
}
|
||||
|
||||
Future<String> _testProvider(G4FClient client, String providerName, List<Message> messages) async {
|
||||
try {
|
||||
dynamic provider;
|
||||
switch (providerName) {
|
||||
case "Yqcloud": provider = Yqcloud(); break;
|
||||
case "TeachAnything": provider = TeachAnything(); break;
|
||||
case "ChatGptOss": provider = ChatGptOss(); break;
|
||||
case "Pollinations": provider = Pollinations(); break;
|
||||
case "DeepAi": provider = DeepAi(); break;
|
||||
case "PhindAi": provider = PhindAi(); break;
|
||||
}
|
||||
|
||||
final stream = provider.createAsyncGenerator(
|
||||
provider.defaultModel,
|
||||
messages,
|
||||
stream: false,
|
||||
);
|
||||
return await stream.join();
|
||||
} catch (e) {
|
||||
return "ОШИБКА: $e";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user