[flutter] ChatGPT 챗 봇 샘플

sanghun park·2023년 3월 19일
0
post-thumbnail

나의 API Key

우선 flutter 에서 chat GPT 를 사용하려면 이 링크에 들어가서 API Key를 발급 받아야 한다. 사이트에 접속 후, 로그인/회원가입을 한 후 , 우측 상단의 Personal 클릭 , View API keys 클릭.

여기서 Create new secret key 를 누르고 발급 받으면 된다.

설정

http 패키지가 필요하므로, 먼저 pubspec.yaml파일에 http 패키지를 추가해 주어야 한다.

프로젝트 코드

OpenAI API에 요청을 보내고 응답을 처리하는 코드

Future<String> generateResponse(String input) async {
  String token = "Bearer 네이티브 앱 키";

  var response = await http.post(
      Uri.parse(
          "https://api.openai.com/v1/engines/text-davinci-003/completions"),
      headers: {
        "Content-Type": "application/json",
        "Authorization": token,
      },
      body: jsonEncode({
        "prompt": input,
        "temperature": 0.5,
        "max_tokens": 50,
        "top_p": 1,
        "frequency_penalty": 0,
        "presence_penalty": 0
      }));
  if (response.statusCode == 200) {
    Map<String, dynamic> data = jsonDecode(utf8.decode(response.bodyBytes));
    String text = data["choices"][0]["text"].toString().trim();
    return text;
  } else {
    throw Exception("Failed to generate response: ${response.statusCode}");
  }
}

pub.dev 에 sdk 가 있지만 나는 그 라이브러리를 사용하지 않고 해보려고 한다.
( chat_gpt_sdk / pub.dev <= 라이브러리 사용방법을 볼 수 있음 )

코드 설명

prompt : ChatGPT에게 전달할 사용자 질문을 뜻한다.

temperature : 응답 생성 시 사용되는 온도 값으로, 온도가 높을수록 다양한 응답을 생성한다. 그만큼 불일치한 응답을 생성할 가능성도 높아진다고 한다. (기본값: 0.5)

max_tokens : 생성되는 응답의 최대 길이를 나타낸다. (기본값: 50)

top_p : 응답 생성 시 사용되는 확률 분포의 상위 p%를 사용한다. (기본값: 1)

frequency_penalty : 빈번한 단어나 구문을 생성하는 것을 방지하는데 사용된다. (기본값: 0)

presence_penalty : 특정 키워드를 포함하지 않는 응답을 생성하는 것을 방지하는 데 사용된다. (기본값: 0)

이러한 설정들은 본인이 사용하고자 하는 목적에 따라 조절하여 사용하면 될 것 같다!

  • 나는 여기서 401 Error로 인해 계속 익셉션으로 빠졌다.. 왜인가 하면 String token = "Bearer 네이티브 앱 키"; 이부분에서 Bearer을 빼고 나의 네이티브 앱 키만 넣어서 실행시켰다.

채팅 스크린 코드

import 'package:chat_gpt/model/message_model.dart';
import 'package:flutter/material.dart';
import 'chatMessage.dart';
import 'controller/gpt_controller.dart';

class ChatBotScreen extends StatefulWidget {
  const ChatBotScreen({super.key});

  @override
  State<ChatBotScreen> createState() => _ChatBotScreenState();
}

class _ChatBotScreenState extends State<ChatBotScreen> {
  final TextEditingController _controller = TextEditingController();
  final List<MessageModel> _message = [];

  void _sendMessage(String text) async {
    setState(() {
      _message.add(MessageModel(
          userMessage: text, botMessage: '', messageType: MessageType.user));
      isLoding = true;
    });

    String response = await generateResponse(text);

    setState(() {
      _message.add(MessageModel(
          userMessage: '', botMessage: response, messageType: MessageType.bot));
      isLoding = false;
    });
    _controller.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xff343541),
      appBar: AppBar(
        backgroundColor: const Color(0xff444654),
        title: const Text("chatGPT ChatBot"),
        centerTitle: true,
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _message.length,
              itemBuilder: (context, index) {
                var message = _message[index];
                return ChatMessageWidget(
                    userMessage: message.userMessage,
                    botMessage: message.botMessage,
                    messageType: message.messageType);
              },
            ),
          ),
          Row(
            children: [
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8),
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: "메세지를 입력하세요! ",
                      fillColor: Color(0xff444654),
                      filled: true,
                      border: InputBorder.none,
                    ),
                  ),
                ),
              ),
              IconButton(
                  onPressed: () {
                    _sendMessage(_controller.text);
                  },
                  icon: const Icon(
                    Icons.send,
                    color: Color.fromRGBO(142, 142, 160, 1),
                  ))
            ],
          )
        ],
      ),
    );
  }
}
  • 사용자와 봇의 메세지 데이터를 사용하기위해 MessageModel 을 List 변수로 생성 했다.

_sendMessage()

  • TestEdittingController 를 사용하여 사용자가 입력한 텍스트를 받아 MessageModel 리스트에 추가한다.
  • OpenAI API 호출하여 이에 대한 답변을 받아올 함수 gnerateResponse() 를 response라는 스트링 변수에 담아 둔다.
  • 받아온 결과 값을 MessageModel 에 담아준 후 컨트롤러를 clear 시킨다.

위젯 코드

import 'package:chat_gpt/model/message_model.dart';
import 'package:flutter/material.dart';

class ChatMessageWidget extends StatelessWidget {
  final String userMessage;
  final String botMessage;
  final MessageType messageType;
  const ChatMessageWidget(
      {required this.userMessage,
      required this.botMessage,
      required this.messageType,
      super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 10),
      padding: const EdgeInsets.all(16),
      color: messageType == MessageType.user
          ? const Color(0xff343541)
          : const Color(0xff444654),
      child: Row(
        children: [
          messageType == MessageType.user
              ? Container(
                  margin: const EdgeInsets.only(right: 16),
                  child: const CircleAvatar(
                    child: Icon(Icons.person),
                  ),
                )
              : const CircleAvatar(
                  backgroundColor: Color.fromRGBO(16, 163, 127, 1),
                ),
          // Image.asset(
          //     '',
          //     color: Colors.white,
          //     scale: 1.5,
          //   ),
          Expanded(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Container(
                  padding: const EdgeInsets.all(8),
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.all(Radius.circular(8)),
                  ),
                  child: messageType == MessageType.user
                      ? Text(
                          userMessage,
                          style: Theme.of(context)
                              .textTheme
                              .bodyLarge
                              ?.copyWith(color: Colors.white),
                        )
                      : Text(
                          botMessage,
                          style: Theme.of(context)
                              .textTheme
                              .bodyLarge
                              ?.copyWith(color: Colors.white),
                        )),
            ],
          ))
        ],
      ),
    );
  }
}
  • 화면에 뿌려질 UI 에 대한 코드라 따로 설명할 부분은 없는 것 같다. 굳이 하자면 사용자일때와 봇일때를 구분하여 UI를 다르게 보여지도록 삼항연산자를 사용한 거,,?

모델 구성

enum MessageType { user, bot }

class MessageModel {
  late String userMessage;
  late String botMessage;
  late MessageType messageType;

  MessageModel(
      {required this.userMessage,
      required this.botMessage,
      required this.messageType});
}
  • enum 변수를 만든 이유는 위에서 얘기했듯이 사용자일때와 봇일때를 구분하기 위해서 생성했다. MessageModel에 담을 데이터가 사용자가 쓴 텍스트 일 경우에는 MessageType을 user로 넘겨주고, 봇일 경우에는 bot으로 넘겨줘서 이 결과에 따라 삼항 연산자를 사용하여 UI를 각각 그려주었다.

  • 나는 몇달전에 ChatGPT 라는 것을 알게 되었다. 처음에는 인공지능이라는 분야에 대해 크게 관심이 없었는데 프로그램을 공부하고 앱개발을 공부 하다보니 인공지능이라는게 없어서는 안될 서비스라는 것을 느끼게 되었다. 그래서 핫한 ChatGPT 를 이용하여 간단한 샘플을 만들어 보자 ! 해서 만들게 되었다. 많은 개발자 분들에게는 간단하고 쉬운 샘플일 지라도 나에게는 얻을 거리가 많은 샘플 만들기 였던 것 같다 ...

예를 들면 enum 변수를 만들어서 각 상황에 맞게 UI를 구성할 수 있는 것,
http를 이용한 api 통신에 대해 부족한 점을 공부 할 수 있었고, 제일 간단하게 생각했던 UI 그리기 에서도 각 decoration 기능에는 어떤것들이 있는지 자세하게 알게 해주는 등..

profile
개발자를 꿈꾸는 학생

0개의 댓글