List 로만 만들어 보는 GPt 및 bard용 챗 ListView 입니다.
패키지 없이 리스트로 구성하면 여러 응용이 가능 합니다.
통신을 위해 json 변환기와 http 는 import 해줍니다.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
- Chatting 에 쓸 List를 위해 Model Class를 만듭니다.
- text 는 채팅 메시지 이고 , bool은 Ai 와 나를 구분해 추력하기 위해 사용합니다.
class ChatMessage {
final String text;
final bool iAm;
ChatMessage({required this.text, required this.iAm});
}
GptChatLister 라는 StateFull 위젯을 생성합니다.
class GptChatLister extends StatefulWidget {
const GptChatLister({super.key});
@override
State<GptChatLister> createState() => _GptChatListerState();
}
일단 Gemini를 위한 연결입니다. 무료이니까요 . // GPT 3.5 연결은 제일 아래에 있습니다. 응용해보세요
GPT자꾸 쓰니 요금이 올라갑니다.정말입니다. ( 딸라 달라고 합니다 ~ ).
Http 연결할 ~ . Url , 해더, 를 설정하고 , 채팅메시지를 기록할 List 도 생성합니다.
채팅 텍스트 입력을 위한 텍스트 콘트롤러를 만들고, inProgress 는 시작을 false 로 합니다. false 는 입력하는 내가 되고 . Ture면 Ai 가 됩니다.
class _GptChatListerState extends State<GptChatLister> {
final header = {'Content-Type': 'application/json'};
final baseUrl =
'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${APIKey.apiKey}';
final List<ChatMessage> _chatMessage = [];
final TextEditingController _chatController = TextEditingController();
bool inProgress = false;
텍스트 입력을 하면 항상 따라다니는 dispose textcontroller.dispose().
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_chatController.dispose();
}
화면에서 Text입력후 Onpress 로 호출하는 onSendPressed 메써드 입니다.
- 채팅 메시지 리스트에 TextField의 값을 저장합니다. 채팅창에 표시SetState
- TextField 값을 sendMessageToList로 전달하고 받아오는 코드를 작성
- 받아온 response 값을 채팅메시지 리스트에 저장 . 채팅 데 표시 SetState
- 입력이 완료되었으므로 TextField를 .clear()합니다.
void onSendPressed() async {
ChatMessage chatMessage = ChatMessage(text: _chatController.text, iAm: true);
setState(() => _chatMessage.insert(0, chatMessage));
final response = await sendMessageToList(chatMessage.text);
ChatMessage chatAi = ChatMessage(text: response, iAm: false);
setState(() => _chatMessage.insert(0, chatAi));
_chatController.clear();
}
버튼을 누른후 . 누른 메써드에서 값을 가져오기 위해 호출하는 Future 메써드로
String message 를 받아서 body 를 구성합니다.
final respon = await http.post(Uri.parse(baseUrl), headers: header, body: jsonEncode(datass));
받아온 response는 값이 많습니다. 그중에서 TEXT만 추출합니다.
final tttt = result['candidates'][0]['content']['parts'][0]['text'];
성공시 return tttt; 로 받아온 Text 응답을 버튼을 눌러서 호출된 곳으로 돌려줍니다.
Future<String> sendMessageToList(String message) async {
setState(() => inProgress = true);
var datass = {
'contents': [
{
'parts': [
{'text': message}
]
}
]
};
final respon = await http.post(Uri.parse(baseUrl), headers: header, body: jsonEncode(datass));
if (respon.statusCode == 200) {
var result = jsonDecode(respon.body);
final tttt = result['candidates'][0]['content']['parts'][0]['text'];
setState(() => inProgress = false);
return tttt;
} else {
setState(() => inProgress = false);
throw Exception('API request failed with status code: ${respon.statusCode}');
}
이제 화면을 구성합니다 .Scaffold를 구성하며 ListView 를 만듭니다.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Chat List')),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
reverse: true,
itemCount: _chatMessage.length,
itemBuilder: (BuildContext context, int index) {
return _build_Message(_chatMessage[index]);
},
),
),
Divider(height: 1.0),
뷰의 내용은 따로 메써드 위젯을 만듭니다.
_build_Message(_chatMessage[index]);
inProgress로 진행중임을 프로그래스 바로 보여주게 됩니다.
inProgress ? LinearProgressIndicator() : Container(),
채팅 입력을 아 onpress로 채팅메시지를 전달하는 화면 아래 텍스트필드와 버튼입니다.
Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _chatController,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
hintText: 'Type here',
border: InputBorder.none
),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: onSendPressed,
),
iAm 의 값을 True 냐 False 냐에 따라 . 좌우 배치를 하고 채팅말머리를 만들어 채팅 매시지의
리스트 내용을 보여 줍니다.
Widget _build_Message(ChatMessage message) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Column(
crossAxisAlignment: message.iAm ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
message.iAm ? 'Me' : 'Ai',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(message.text),
],
),
),
);
}
전체 코드
class ChatMessage {
final String text;
final bool iAm;
ChatMessage({required this.text, required this.iAm});
}
class GptChatLister extends StatefulWidget {
const GptChatLister({super.key});
@override
State<GptChatLister> createState() => _GptChatListerState();
}
class _GptChatListerState extends State<GptChatLister> {
final header = {'Content-Type': 'application/json'};
final baseUrl =
'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${APIKey.apiKey}';
final List<ChatMessage> _chatMessage = [];
final TextEditingController _chatController = TextEditingController();
bool inProgress = false;
Future<String> sendMessageToList(String message) async {
setState(() => inProgress = true);
var datass = {
'contents': [
{
'parts': [
{'text': message}
]
}
]
};
final respon = await http.post(Uri.parse(baseUrl), headers: header, body: jsonEncode(datass));
if (respon.statusCode == 200) {
var result = jsonDecode(respon.body);
final tttt = result['candidates'][0]['content']['parts'][0]['text'];
print(tttt);
// _chatMessage.insert(0, tttt);
setState(() => inProgress = false);
return result['candidates'][0]['content']['parts'][0]['text'];
} else {
setState(() => inProgress = false);
throw Exception('API request failed with status code: ${respon.statusCode}');
}
}
void onSendPressed() async {
ChatMessage chatMessage = ChatMessage(text: _chatController.text, iAm: true);
setState(() => _chatMessage.insert(0, chatMessage));
final response = await sendMessageToList(chatMessage.text);
ChatMessage chatAi = ChatMessage(text: response, iAm: false);
setState(() => _chatMessage.insert(0, chatAi));
_chatController.clear();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_chatController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Chat List')),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
reverse: true,
itemCount: _chatMessage.length,
itemBuilder: (BuildContext context, int index) {
return _build_Message(_chatMessage[index]);
},
),
),
Divider(height: 1.0),
inProgress ? LinearProgressIndicator() : Container(),
Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _chatController,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
hintText: 'Type here',
border: InputBorder.none
),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: onSendPressed,
),
],
),
),
],
),
);
}
Widget _build_Message(ChatMessage message) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Column(
crossAxisAlignment: message.iAm ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
message.iAm ? 'Me' : 'Ai',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(message.text),
],
),
),
);
}
//
}
Gpt3.5 사용할때는 http를
아래처럼 구성합니다. ${APIKey.apiKey} GPT키로 입력 하거나 클래스를 만들어서 사용합니다.
Uri uri = Uri.parse("https://api.openai.com/v1/chat/completions");
Map<String, dynamic> body = {
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": message}
],
"max_tokens": 500,
};
final response = await http.post(
uri,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ${APIKey.apiKey}",
},
body: json.encode(body),
);
Map<String, dynamic> reponse = json.decode(response.body);
String receiveMsg = reponse['choices'][0]['message']['content'];
return receiveMsg;
'Flutter' 카테고리의 다른 글
flutter State Management 상태관리 어떤걸 쓰지? getx provoder bloc.... (0) | 2024.02.01 |
---|---|
Bloc 에서 if 는 되는데 Switch는 안되는 이유와 해결법 (0) | 2024.01.20 |
Flutter Google Bard Gemini chat채팅 봇 만들기. (1) | 2023.12.30 |
API Key Hiding with DotEnv. Api 키 보안 관리하기. 키를 환경설정 파일로 숨기는 방법 (1) | 2023.12.17 |
simple 코인 어플 만들기, 암호화 화폐 Bitcoin App , json으로 (0) | 2023.12.16 |