Spaces:
Build error
Build error
/* | |
Right Vote - A web app for election prediction and manifesto comparison with machine learning and NLP. | |
Nilakna Warushavithana, September 2024 | |
*/ | |
import 'package:flutter/material.dart'; | |
import 'package:http/http.dart' as http; | |
import 'dart:convert'; | |
class ChatBotPanelGenerator extends StatefulWidget { | |
const ChatBotPanelGenerator({super.key}); | |
_ChatBotPanelState createState() => _ChatBotPanelState(); | |
} | |
class _ChatBotPanelState extends State<ChatBotPanelGenerator> { | |
final TextEditingController _chatController = TextEditingController(); | |
final ScrollController _scrollController = ScrollController(); | |
List<Map<String, dynamic>> _chatHistory = []; | |
void getAnswer() async { | |
final url = "https://85a9-35-196-250-8.ngrok-free.app/ask"; | |
final uri = Uri.parse(url); | |
try { | |
final response = await http.post( | |
uri, | |
headers: {"Content-Type": "application/json"}, | |
body: jsonEncode(<String, String>{ | |
"question": _chatController.text | |
}), //send the question to the server | |
); | |
//for debugging the http request and reponse | |
// print("Request Body: ${jsonEncode(<String, String>{ | |
// 'question': _chatController.text | |
// })}"); | |
// print("Response Body: ${response.body}"); | |
if (response.statusCode == 200) { | |
final data = json.decode(response.body); | |
setState(() { | |
_chatHistory.add({ | |
"time": DateTime.now(), | |
"message": data["answer"], | |
"isSender": false, | |
}); //update chat history with the answer | |
}); | |
// Ensure scrolling happens after the state has been updated | |
WidgetsBinding.instance.addPostFrameCallback((_) { | |
if (_scrollController.hasClients) { | |
_scrollController.animateTo( | |
_scrollController.position.maxScrollExtent, | |
duration: const Duration(milliseconds: 300), | |
curve: Curves.easeOut, | |
); | |
} | |
}); | |
} else { | |
// print("Error: ${response.statusCode}"); //debugging | |
// print(response.body); //debugging | |
setState(() { | |
_chatHistory.add({ | |
"time": DateTime.now(), | |
"message": "Error: ${response.statusCode}", | |
"isSender": false, | |
}); | |
}); | |
} | |
} catch (e) { | |
// print("Exception: $e"); //debugging | |
setState(() { | |
_chatHistory.add({ | |
"time": DateTime.now(), | |
"message": "Exception: $e", | |
"isSender": false, | |
}); | |
}); | |
} | |
} | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text( | |
"Chat", | |
style: TextStyle(fontWeight: FontWeight.bold), | |
), | |
), | |
body: Stack( | |
children: [ | |
Container( | |
//get max height | |
height: MediaQuery.of(context).size.height - 160, | |
child: ListView.builder( | |
itemCount: _chatHistory.length, | |
// shrinkWrap: false, | |
controller: _scrollController, | |
padding: const EdgeInsets.only(top: 10, bottom: 10), | |
physics: const BouncingScrollPhysics(), | |
itemBuilder: (context, index) { | |
return Container( | |
padding: | |
EdgeInsets.only(left: 14, right: 14, top: 10, bottom: 10), | |
child: Align( | |
alignment: (_chatHistory[index]["isSender"] | |
? Alignment.topRight | |
: Alignment.topLeft), | |
child: Container( | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(20), | |
boxShadow: [ | |
BoxShadow( | |
color: Colors.grey.withOpacity(0.5), | |
spreadRadius: 2, | |
blurRadius: 5, | |
offset: const Offset(0, 3), | |
), | |
], | |
color: (_chatHistory[index]["isSender"] | |
? Colors.blue[100] | |
: Colors.white), | |
), | |
padding: EdgeInsets.all(16), | |
child: Text(_chatHistory[index]["message"], | |
style: TextStyle( | |
fontSize: 15, | |
color: _chatHistory[index]["isSender"] | |
? Colors.black | |
: Colors.black)), | |
), | |
), | |
); | |
}, | |
), | |
), | |
Align( | |
alignment: Alignment.bottomCenter, | |
child: Container( | |
padding: | |
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), | |
height: 60, | |
width: double.infinity, | |
color: Colors.white, | |
child: Row( | |
children: [ | |
Expanded( | |
child: Container( | |
decoration: const BoxDecoration(), | |
child: Padding( | |
padding: const EdgeInsets.all(4.0), | |
child: TextField( | |
decoration: const InputDecoration( | |
hintText: "Type a message", | |
border: InputBorder.none, | |
contentPadding: EdgeInsets.all(8.0), | |
), | |
controller: _chatController, | |
), | |
), | |
), | |
), | |
const SizedBox( | |
width: 4.0, | |
), | |
MaterialButton( | |
onPressed: () { | |
setState(() { | |
if (_chatController.text.isNotEmpty) { | |
_chatHistory.add({ | |
"time": DateTime.now(), | |
"message": _chatController.text, | |
"isSender": true, | |
}); | |
getAnswer(); | |
_chatController.clear(); | |
} | |
}); | |
_scrollController.jumpTo( | |
_scrollController.position.maxScrollExtent, | |
); | |
}, | |
shape: RoundedRectangleBorder( | |
borderRadius: BorderRadius.circular(80.0)), | |
padding: const EdgeInsets.all(0.0), | |
child: Ink( | |
decoration: const BoxDecoration( | |
color: Colors.blue, | |
borderRadius: BorderRadius.all(Radius.circular(50.0)), | |
), | |
child: Container( | |
constraints: const BoxConstraints( | |
minWidth: 88.0, | |
minHeight: | |
36.0), // min sizes for Material buttons | |
alignment: Alignment.center, | |
child: const Icon( | |
Icons.send, | |
color: Colors.white, | |
)), | |
), | |
) | |
], | |
), | |
), | |
) | |
], | |
), | |
); | |
} | |
} | |