Files
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

91 lines
2.3 KiB
Dart

import '../http_util.dart';
import '../models.dart';
import 'base_provider.dart';
import 'openai_compat.dart';
/// Python `KiloCode` — OpenAI-compat gateway, no key for `kilo-auto/free`.
class KiloCode extends OpenAiCompatProvider {
KiloCode()
: super(
providerName: 'KiloCode',
apiBase: 'https://api.kilo.ai/api/gateway',
fallbackModel: 'kilo-auto/free',
supportedModels: const ['kilo-auto/free', 'kilo-auto'],
);
@override
String get url => 'https://kilo.ai';
}
/// Python `OpenCode` — `https://opencode.ai/zen/v1`, default `big-pickle`.
class OpenCode extends OpenAiCompatProvider {
OpenCode()
: super(
providerName: 'OpenCode',
apiBase: 'https://opencode.ai/zen/v1',
fallbackModel: 'big-pickle',
supportedModels: const ['big-pickle'],
);
@override
String get url => 'https://opencode.ai';
}
/// Python `G4FSpace` / `ClientFactory("default")`.
/// Anonymous calls currently return 402 cake-credits; still tried so a baked
/// session cookie or future free window works without a code change.
class G4FSpace extends BaseProvider {
@override
String get name => 'G4FSpace';
@override
String get url => 'https://g4f.space';
@override
bool get working => true;
@override
List<String> get models => const ['auto', 'gpt-4o', 'openai'];
@override
String get defaultModel => 'auto';
static const _bases = [
'https://g4f.space/api/auto',
'https://g4f.space/api/pollinations',
'https://g4f.space/v1',
];
@override
Stream<String> createAsyncGenerator(
String model,
List<Message> messages, {
bool stream = false,
}) async* {
final errors = <String>[];
for (final base in _bases) {
try {
final inner = OpenAiCompatProvider(
providerName: 'G4FSpace',
apiBase: base,
fallbackModel: model.isEmpty ? defaultModel : model,
supportedModels: models,
);
final text = await inner
.complete(model.isEmpty ? defaultModel : model, messages)
.timeout(requestTimeout);
if (looksLikeModelOutput(text)) {
yield text;
return;
}
errors.add('$base unusable');
} catch (e) {
errors.add('$base: $e');
}
}
throw Exception('G4FSpace failed: ${errors.join(' | ')}');
}
}