Flutter Chat with GPT: Real-Time Chat, File Sharing, and More
import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:file_picker/file_picker.dart'; import 'package:http/http.dart' as http; import 'package:muse_nepu_course/home.dart'; import 'package:uuid/uuid.dart'; import 'package:path_provider/path_provider.dart'; import 'package:mime/mime.dart'; import 'package:flutter/services.dart' show rootBundle; import 'dart:convert'; import 'dart:io'; import 'package:image_picker/image_picker.dart';
class chat_gpt extends StatefulWidget { @override _chat_gptState createState() => _chat_gptState(); }
class _chat_gptState extends State<chat_gpt> { List<types.Message> _messages = []; final _user = const types.User( id: '82091008-a484-4a89-ae75-a22bf8d6f3ac', ); var _filteredStringList = []; var _stringList = []; //从assets/prompts.json中读取数据,并转换为List<Map<String, String>> void loadprompts() async { String prompt = await rootBundle.loadString('assets/prompts.json'); _stringList = json.decode(prompt); _filteredStringList = List.from(_stringList); }
int _selectedIndex = -1; @override void initState() { super.initState(); _loadMessages(); }
void onSearch(String keyword) { SchedulerBinding.instance!.addPostFrameCallback(() { setState(() { _filteredStringList = _stringList.where((item) { return item['act']!.contains(keyword) || item['prompt']!.contains(keyword); }).toList(); }); }); }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Chat with GPT'),
//加入返回按鈕
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
//跳转到成绩页面
Navigator.push(context, MaterialPageRoute(builder: (context) {
return HomePage();
}));
},
),
actions:
void _addMessage(types.Message message) { setState(() { _messages.insert(0, message); }); }
void _handleAttachmentPressed() {
showModalBottomSheet
void _handleFileSelection() async { final result = await FilePicker.platform.pickFiles( type: FileType.any, );
if (result != null && result.files.single.path != null) {
final message = types.FileMessage(
author: _user,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
mimeType: lookupMimeType(result.files.single.path!),
name: result.files.single.name,
size: result.files.single.size,
uri: result.files.single.path!,
);
_addMessage(message);
}
}
void _handleImageSelection() async { final result = await ImagePicker().pickImage( imageQuality: 70, maxWidth: 1440, source: ImageSource.gallery, );
if (result != null) {
final bytes = await result.readAsBytes();
final image = await decodeImageFromList(bytes);
final message = types.ImageMessage(
author: _user,
createdAt: DateTime.now().millisecondsSinceEpoch,
height: image.height.toDouble(),
id: const Uuid().v4(),
name: result.name,
size: bytes.length,
uri: result.path,
width: image.width.toDouble(),
);
_addMessage(message);
}
}
void _handleMessageTap(BuildContext _, types.Message message) async { if (message is types.FileMessage) { var localPath = message.uri;
if (message.uri.startsWith('http')) {
try {
final index = _messages.indexWhere((element) => element.id == message.id);
final updatedMessage = (_messages[index] as types.FileMessage).copyWith(
isLoading: true,
);
setState(() {
_messages[index] = updatedMessage;
});
final client = http.Client();
final request = await client.get(Uri.parse(message.uri));
final bytes = request.bodyBytes;
final documentsDir = (await getApplicationDocumentsDirectory()).path;
localPath = '$documentsDir/${message.name}';
if (!File(localPath).existsSync()) {
final file = File(localPath);
await file.writeAsBytes(bytes);
}
} finally {
final index = _messages.indexWhere((element) => element.id == message.id);
final updatedMessage = (_messages[index] as types.FileMessage).copyWith(
isLoading: null,
);
setState(() {
_messages[index] = updatedMessage;
});
}
}
}
}
void _handlePreviewDataFetched( types.TextMessage message, types.PreviewData previewData, ) { final index = _messages.indexWhere((element) => element.id == message.id); final updatedMessage = (_messages[index] as types.TextMessage).copyWith( previewData: previewData, );
setState(() {
_messages[index] = updatedMessage;
});
}
void _handleSendPressed(types.PartialText message) { final textMessage = types.TextMessage( author: _user, createdAt: DateTime.now().millisecondsSinceEpoch, id: const Uuid().v4(), text: message.text, );
_addMessage(textMessage);
print(message.text);
//打印最近20条消息
print(_messages.sublist(0, 20));
}
void _loadMessages() async { final response = await rootBundle.loadString('assets/messages.json'); final messages = (jsonDecode(response) as List) .map((e) => types.Message.fromJson(e as Map<String, dynamic>)) .toList();
setState(() {
_messages = messages;
});
} }
class _SearchBarDelegate extends SearchDelegate
_SearchBarDelegate({required this.onSearch});
@override
List
@override Widget buildLeading(BuildContext context) { return IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { close(context, ''); }, ); }
@override Widget buildResults(BuildContext context) { onSearch(query); return const SizedBox.shrink(); }
@override Widget buildSuggestions(BuildContext context) { return Dialog( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ TextField( onChanged: (value) { onSearch(value); }, decoration: InputDecoration( hintText: 'Search', suffixIcon: Icon(Icons.search), ), ), Expanded( child: ListView.builder( itemCount: _filteredStringList.length, itemBuilder: (context, index) { String act = _filteredStringList[index]['act']!; String prompt = _filteredStringList[index]['prompt']!; return RadioListTile( title: Text('行为: $act'), subtitle: Text('语句: $prompt'), value: index, groupValue: _selectedIndex, onChanged: (value) { setState(() { _selectedIndex = value!; }); }, ); }, ), ), FlatButton( onPressed: () { Navigator.of(context).pop(_filteredStringList[_selectedIndex]); }, child: Text('OK'), ), ], ), ); } }
原文地址: https://www.cveoy.top/t/topic/lQr9 著作权归作者所有。请勿转载和采集!