Save verified Mithqal AI project progress

This commit is contained in:
Hamza Ayed
2026-10-01 01:02:03 +03:00
parent f0a444ca46
commit e1f981d29e
111 changed files with 1589 additions and 295 deletions
@@ -29,6 +29,15 @@ class ApiRepository {
return data['model'] as String? ?? 'نموذج غير معروف';
}
Future<List<String>> getAvailableModels() async {
final response = await http.get(Uri.parse('$_baseUrl/v1/models'));
_checkStatus(response);
final data = jsonDecode(response.body) as Map<String, dynamic>;
return (data['data'] as List<dynamic>)
.map((model) => (model as Map<String, dynamic>)['id'] as String)
.toList();
}
Future<String> _userId() async {
final cached = _cachedUserId;
if (cached != null) return cached;
@@ -145,7 +154,26 @@ class ApiRepository {
return message['content'] as String? ?? 'لم يصل نص في الإجابة.';
}
Stream<String> completeStream(List<ChatMessage> messages) async* {
Future<String> askWorkspaceAgent(String task, {String? model}) async {
final response = await http
.post(
Uri.parse('$_baseUrl/v1/agent/workspace'),
headers: const {'Content-Type': 'application/json'},
body: jsonEncode({'task': task, if (model != null) 'model': model}),
)
.timeout(const Duration(minutes: 10));
_checkStatus(response);
final data = jsonDecode(response.body) as Map<String, dynamic>;
final result = data['result'] as String? ?? '';
final files = (data['files'] as List<dynamic>? ?? const []).cast<String>();
if (files.isEmpty) return result;
return '$result\n\nالمصادر المقروءة: ${files.join('، ')}';
}
Stream<String> completeStream(
List<ChatMessage> messages, {
String? model,
}) async* {
final client = http.Client();
try {
final request =
@@ -155,6 +183,7 @@ class ApiRepository {
'Accept': 'application/x-ndjson',
})
..body = jsonEncode({
if (model != null && model.isNotEmpty) 'model': model,
'messages':
messages
.map(
@@ -0,0 +1,88 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:local_notifier/local_notifier.dart';
class CompletionNotificationService {
CompletionNotificationService._();
static final instance = CompletionNotificationService._();
final _plugin = FlutterLocalNotificationsPlugin();
bool _initialized = false;
Future<void> initialize() async {
if (kIsWeb || _initialized) return;
if (_isDesktop) {
await localNotifier.setup(appName: 'Mithqal AI');
_initialized = true;
return;
}
const settings = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
),
);
await _plugin.initialize(settings);
_initialized = true;
}
Future<bool> requestPermission() async {
if (kIsWeb) return false;
await initialize();
if (_isDesktop) return true;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return await _plugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.requestNotificationsPermission() ??
true;
case TargetPlatform.iOS:
return await _plugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin
>()
?.requestPermissions(alert: true, badge: true, sound: true) ??
false;
default:
return true;
}
}
Future<void> showFinished({required bool succeeded}) async {
if (kIsWeb || !_initialized) return;
final title = succeeded ? 'اكتملت الإجابة' : 'تعذر إكمال الطلب';
final body = succeeded
? 'انتهى النموذج من معالجة طلبك.'
: 'افتح التطبيق لمراجعة الخطأ.';
if (_isDesktop) {
LocalNotification(title: title, body: body).show();
return;
}
const android = AndroidNotificationDetails(
'generation_complete',
'اكتملت المهام',
channelDescription: 'تنبيه عند انتهاء توليد الإجابة أو مهمة الوكيل',
importance: Importance.defaultImportance,
priority: Priority.defaultPriority,
);
const details = NotificationDetails(
android: android,
iOS: DarwinNotificationDetails(),
);
await _plugin.show(
1001,
title,
body,
details,
);
}
bool get _isDesktop =>
defaultTargetPlatform == TargetPlatform.windows ||
defaultTargetPlatform == TargetPlatform.linux ||
defaultTargetPlatform == TargetPlatform.macOS;
}