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:
@@ -0,0 +1,90 @@
|
||||
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(' | ')}');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user