8bbc9dbff2
- Flutter + PocketBase dental lab management system - Clinic & lab dashboards, job tracking, patient management - Product catalog, finance tracking, multi-language support - AI assistant integration, realtime notifications - Windows installer (Inno Setup) included - Developed by kovakyazilim.com
72 lines
2.2 KiB
Dart
72 lines
2.2 KiB
Dart
import 'dart:async';
|
||
import 'dart:convert';
|
||
import 'package:http/http.dart' as http;
|
||
|
||
class AiService {
|
||
static const _baseUrl = 'https://api.featherless.ai/v1';
|
||
static const _apiKey =
|
||
'rc_e10f49aaa4f7af03dcd9da115cfc12cc1988665e895955c11f77788ee5ad93c6';
|
||
static const _model = 'Qwen/Qwen2.5-7B-Instruct';
|
||
|
||
AiService._();
|
||
static final instance = AiService._();
|
||
|
||
Stream<String> streamChat({
|
||
required String systemPrompt,
|
||
required List<Map<String, String>> messages,
|
||
}) async* {
|
||
final client = http.Client();
|
||
try {
|
||
final request = http.Request(
|
||
'POST',
|
||
Uri.parse('$_baseUrl/chat/completions'),
|
||
);
|
||
request.headers.addAll({
|
||
'Authorization': 'Bearer $_apiKey',
|
||
'Content-Type': 'application/json',
|
||
});
|
||
request.body = jsonEncode({
|
||
'model': _model,
|
||
'messages': [
|
||
{'role': 'system', 'content': systemPrompt},
|
||
...messages,
|
||
],
|
||
'stream': true,
|
||
'max_tokens': 2048,
|
||
'temperature': 0.7,
|
||
});
|
||
|
||
final response = await client.send(request);
|
||
if (response.statusCode != 200) {
|
||
final body = await response.stream.bytesToString();
|
||
String msg = 'API hatası ${response.statusCode}';
|
||
try {
|
||
final j = jsonDecode(body) as Map<String, dynamic>;
|
||
msg = (j['error'] as Map?)?['message'] as String? ?? msg;
|
||
} catch (_) {}
|
||
throw Exception(msg);
|
||
}
|
||
|
||
final lines = response.stream
|
||
.transform(utf8.decoder)
|
||
.transform(const LineSplitter());
|
||
|
||
await for (final line in lines) {
|
||
if (!line.startsWith('data: ')) continue;
|
||
final payload = line.substring(6).trim();
|
||
if (payload == '[DONE]') break;
|
||
try {
|
||
final j = jsonDecode(payload) as Map<String, dynamic>;
|
||
final choices = j['choices'] as List?;
|
||
if (choices == null || choices.isEmpty) continue;
|
||
final delta = choices.first['delta'] as Map<String, dynamic>?;
|
||
final content = delta?['content'] as String?;
|
||
if (content != null && content.isNotEmpty) yield content;
|
||
} catch (_) {}
|
||
}
|
||
} finally {
|
||
client.close();
|
||
}
|
||
}
|
||
}
|