| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- import 'dart:convert';
- import 'package:electronic_assistant/base/base_controller.dart';
- import 'package:electronic_assistant/data/bean/agenda.dart';
- import 'package:electronic_assistant/data/bean/chat_item.dart';
- import 'package:electronic_assistant/data/bean/file_chat_item.dart';
- import 'package:electronic_assistant/data/bean/progressing_chat_item.dart';
- import 'package:electronic_assistant/data/bean/reference_chat_item.dart';
- import 'package:electronic_assistant/data/repositories/account_repository.dart';
- import 'package:electronic_assistant/data/repositories/chat_repository.dart';
- import 'package:electronic_assistant/data/repositories/talk_repository.dart';
- import 'package:electronic_assistant/module/chat/start/view.dart';
- import 'package:electronic_assistant/resource/colors.gen.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:pull_to_refresh/pull_to_refresh.dart';
- import 'package:uuid/uuid.dart';
- import '../../data/bean/stream_chat_origin_data.dart';
- import '../../data/bean/talks.dart';
- import '../../data/consts/error_code.dart';
- import '../../router/app_pages.dart';
- import '../../utils/http_handler.dart';
- class ChatController extends BaseController {
- final RefreshController refreshController =
- RefreshController(initialLoadStatus: LoadStatus.loading);
- final ScrollController listScrollController = ScrollController();
- final TextEditingController inputController = TextEditingController();
- final RxList chatItems = [].obs;
- final Rxn<TalkBean> talkInfo = Rxn<TalkBean>();
- final Rxn<Agenda> agenda = Rxn<Agenda>();
- @override
- void onInit() {
- super.onInit();
- loadMoreHistory();
- checkArguments();
- }
- @override
- void onReady() {
- super.onReady();
- if (accountRepository.userInfo?.profession == null ||
- accountRepository.userInfo?.post == null) {
- showStartSheet();
- }
- }
- void checkArguments() {
- List<dynamic> arguments = Get.arguments ?? [];
- if (arguments.isEmpty) {
- return;
- }
- if (arguments.length > 1 && arguments[1] is Agenda) {
- agenda.value = arguments[1];
- }
- if (arguments[0] is TalkBean) {
- talkInfo.value = arguments[0];
- sendInitialMessage();
- } else if (arguments[0] is String) {
- talkRepository
- .talkInfo(arguments[0])
- .then((response) => talkInfo.value = response.talkInfo)
- .then((_) => sendInitialMessage());
- }
- }
- void sendInitialMessage() {
- final talkInfo = this.talkInfo.value;
- if (talkInfo == null) {
- return;
- }
- chatItems.insert(
- 0,
- FileChatItem(talkInfo,
- id: const Uuid().v4(),
- conversationId: "",
- role: "user",
- content: "",
- createTime: DateTime.now().toString()));
- if (agenda.value != null) {
- _sendMessage("以这份谈话为背景,你为我执行“${agenda.value?.content}”这一事项");
- }
- }
- onSendClick() {
- if (inputController.text.isEmpty) {
- return;
- }
- String chatContent = inputController.text;
- inputController.clear();
- _sendMessage(chatContent);
- }
- void onAddFileClick() {
- Get.toNamed(RoutePath.fileSearch)?.then((talkInfo) {
- if (talkInfo is TalkBean) {
- this.talkInfo.value = talkInfo;
- agenda.value = null;
- sendInitialMessage();
- }
- });
- }
- Future<void> loadMoreHistory() {
- bool isEmpty = chatItems.isEmpty;
- return chatRepository
- .chatHistory(chatItems.isEmpty ? null : chatItems.last.id)
- .then((value) => chatItems.addAll(value))
- .whenComplete(() => refreshController.loadComplete())
- .whenComplete(() {
- if (isEmpty) {
- _scrollToBottom();
- }
- });
- }
- void showStartSheet() {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- showModalBottomSheet(
- context: Get.context!,
- isScrollControlled: true,
- barrierColor: ColorName.black55,
- backgroundColor: ColorName.transparent,
- builder: (BuildContext context) {
- return const ChatStartPage();
- },
- );
- });
- }
- void _sendMessage(String chatContent) {
- chatItems.insert(0, createUserChatItem(chatContent));
- ProgressingChatItem progressingChatItem = ProgressingChatItem(
- id: const Uuid().v4(),
- conversationId: chatItems.last.conversationId,
- role: "assistant",
- content: "",
- createTime: DateTime.now().toString(),
- );
- chatItems.insert(0, progressingChatItem);
- _scrollToBottom();
- chatRepository
- .streamChat(chatContent,
- talkId: talkInfo.value?.id, agendaId: agenda.value?.id)
- .then((stream) {
- stream.listen((event) {
- try {
- Map<String, dynamic> json = jsonDecode(event.data);
- if (json.isEmpty) {
- return;
- }
- StreamChatOriginData data = StreamChatOriginData.fromJson(json);
- if (data.choices == null || data.choices!.isEmpty) {
- return;
- }
- Delta? delta = data.choices![0].delta;
- if (delta == null) {
- return;
- }
- progressingChatItem.append(delta.content ?? "");
- } catch (ignore) {}
- }, onDone: () {
- progressingChatItem.content = progressingChatItem.streamContent.value;
- progressingChatItem.isFinished.value = true;
- }, onError: (error) {
- progressingChatItem.isFailed.value = true;
- progressingChatItem.error.value = "网络错误,请检查网络连接";
- debugPrint("error: $error");
- debugPrintStack();
- });
- }).catchError((error) {
- progressingChatItem.isFailed.value = true;
- if (error is ServerErrorException) {
- progressingChatItem.error.value = error.message ?? "服务出错,请稍后再试";
- if (error.code == ErrorCode.errorCodeNoLogin) {
- Get.toNamed(RoutePath.login)?.then((loginSuccess) async {
- if (loginSuccess != null && loginSuccess) {
- _clearChat();
- await loadMoreHistory();
- _sendMessage(chatContent);
- }
- });
- } else if (error.code == ErrorCode.errorCodeNoProfession) {
- showStartSheet();
- }
- } else {
- progressingChatItem.error.value = "网络错误,请检查网络连接";
- debugPrint("error: $error");
- debugPrintStack();
- }
- });
- }
- void _clearChat() async {
- return chatItems.clear();
- }
- void _scrollToBottom() {
- Future.delayed(const Duration(milliseconds: 300), () {
- listScrollController.animateTo(
- 0,
- duration: const Duration(milliseconds: 300),
- curve: Curves.easeOut,
- );
- });
- }
- createUserChatItem(String chatContent) {
- final id = const Uuid().v4();
- final conversationId =
- chatItems.isEmpty ? "" : chatItems.last.conversationId;
- const role = "user";
- final content = chatContent;
- final createTime = DateTime.now().toString();
- final talkInfo = this.talkInfo.value;
- return talkInfo == null
- ? ChatItem(
- id: id,
- conversationId: conversationId,
- role: role,
- content: chatContent,
- createTime: createTime)
- : ReferenceChatItem(
- talkInfo: talkInfo,
- id: id,
- conversationId: conversationId,
- role: role,
- content: content,
- createTime: createTime);
- }
- onDeleteReference() {
- talkInfo.value = null;
- agenda.value = null;
- }
- }
|