import 'dart:convert'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:hoshan/core/utils/strings.dart'; import 'package:hoshan/data/model/ai/ai_response_model.dart'; import 'package:hoshan/data/model/ai/messages_model.dart'; import 'package:hoshan/data/model/ai/send_message_model.dart'; import 'package:hoshan/data/repository/chatbot_repository.dart'; import 'package:string_validator/string_validator.dart'; part 'receive_message_state.dart'; class ReceiveMessageCubit extends Cubit { ReceiveMessageCubit() : super(ReceiveMessageInitial()); static ScrollController scrollController = ScrollController(); static ValueNotifier onResponse = ValueNotifier(false); static Future scrollToEnd({final double? extra}) async { try { await scrollController.animateTo( scrollController.position.minScrollExtent + (extra ?? 0), duration: const Duration(milliseconds: 600), curve: Curves.easeInOut, ); } catch (e) { if (kDebugMode) { // print('Error in Scroll:$e'); } } } static Future scrollToStart({final double? extra}) async { try { await scrollController.animateTo( scrollController.position.maxScrollExtent + (extra ?? 0), duration: const Duration(milliseconds: 600), curve: Curves.easeInOut, ); } catch (e) { if (kDebugMode) { // print('Error in Scroll:$e'); } } } void execute({required final SendMessageModel request}) async { emit(ReceiveMessageLoading()); onResponse.value = true; String result = ''; AiResponseModel aiResponseModel = AiResponseModel(); await scrollToEnd(); try { // Call your streaming message function and yield states accordingly await for (String message in request.tool! ? ChatbotRepository.sendMessageTool(request) : ChatbotRepository.sendMessage(request)) { Map jsonMap; try { jsonMap = jsonDecode(message); } catch (e) { if (kDebugMode) { print('Error in Parse: $e'); } jsonMap = {}; jsonMap['content'] = ''; try { message = message.trim(); List jsonStrings = message.split('}{').map((s) { if (!s.startsWith('{')) s = '{$s'; if (!s.endsWith('}')) s = '$s}'; return s; }).toList(); for (String json in jsonStrings) { json = json.replaceAll( RegExp(r'[{}"]'), ''); // Remove braces and quotes List pairs = json.split(', '); for (String pair in pairs) { if (pair.contains('chat_id:')) { jsonMap['chat_id'] = int.tryParse(pair.replaceAll('chat_id: ', '')); } else if (pair.contains('chat_title:')) { jsonMap['chat_title'] = pair.replaceAll('chat_title: ', ''); } else if (pair.contains('ai_message_id:')) { jsonMap['ai_message_id'] = pair.replaceAll('ai_message_id: ', ''); } else if (pair.contains('human_message_id:')) { jsonMap['human_message_id'] = pair.replaceAll('human_message_id: ', ''); } else if (pair.contains('credit:')) { jsonMap['credit'] = pair.replaceAll('credit: ', ''); } else if (pair.contains('credit:')) { jsonMap['credit'] = pair.replaceAll('credit: ', ''); } else if (pair.contains('free:')) { jsonMap['free'] = pair.replaceAll('free: ', ''); } else if (pair.contains('human_message_created_at:')) { jsonMap['human_message_created_at'] = pair.replaceAll('human_message_created_at: ', ''); } else if (pair.contains('ai_message_created_at:')) { jsonMap['ai_message_created_at'] = pair.replaceAll('ai_message_created_at: ', ''); } else { jsonMap['content'] += pair .replaceAll('content: ', '') .replaceAll('\\n', '\n\n'); } } } } catch (e) { if (kDebugMode) { print('Error in Manul Parse: $e'); } jsonMap = {}; } } final res = AiResponseModel.fromJson(jsonMap); if (res.content != null) { result += res.content ?? ''; // Add each content to the list if (!(res.content!.startsWith('http'))) { emit(ReceiveMessageOnResponsing(text: result)); } } aiResponseModel = aiResponseModel.copyWith( error: res.error, credit: res.credit, detail: res.detail, statusCode: res.statusCode, aiMessageId: res.aiMessageId, chatId: res.chatId, chatTitle: res.chatTitle, content: result.isEmpty ? res.content : result, freeCredit: res.freeCredit, humanMessageId: res.humanMessageId); // Yield the received message line by line } await scrollToEnd(); if (aiResponseModel.error ?? true) { emit(ReceiveMessageOnFail( oldHumanMessageId: request.messageId ?? '', detail: 'خطا از سمت سرور لطفا لحظاتی دیگر دوباره تلاش کنید', statusCode: aiResponseModel.statusCode ?? 500)); } else { final message = Messages( id: aiResponseModel.aiMessageId, query: request.query, role: 'ai', content: [ if (aiResponseModel.content != null) Content( audioUrl: aiResponseModel.content!.isURL() && aiResponseModel.content!.isAudio() ? FileUrl(url: aiResponseModel.content) : null, pdfUrl: aiResponseModel.content!.isURL() && aiResponseModel.content!.isDocument() ? FileUrl(url: aiResponseModel.content) : null, type: aiResponseModel.content!.isURL() ? aiResponseModel.content!.isAudio() ? 'audio' : aiResponseModel.content!.isImage() ? 'image' : aiResponseModel.content!.isDocument() ? 'doc' : 'text' : 'text', text: aiResponseModel.content!.isURL() ? null : aiResponseModel.content, imageUrl: aiResponseModel.content!.isURL() && aiResponseModel.content!.isImage() ? FileUrl(url: aiResponseModel.content) : null) ]); emit(ReceiveMessageDone( model: aiResponseModel, message: message, oldHumanMessageId: request.messageId!)); } } catch (e) { // if (e.response?.statusCode == 403) { // emit(const SendMessageError('موجودی شماکافی نمیباشد')); // } else { // emit(SendMessageError('Error: $e')); // } emit(ReceiveMessageOnFail( detail: 'خطا از سمت سرور لطفا لحظاتی دیگر دوباره تلاش کنید', statusCode: 500, oldHumanMessageId: request.messageId ?? '')); } onResponse.value = false; await Future.delayed(const Duration(milliseconds: 300)); await scrollToEnd(); } }