본문 바로가기

Flutter

Chat GPT 만들기 , 음성입력 gpt 3.5 turbo 202312

 

 

0.  package 설치및 . GPT  APi 키 발급받기 . 

https://platform.openai.com/api-keys

https://pub.dev/packages/chat_gpt_flutter

 

chat_gpt_flutter | Flutter Package

Integration of ChatGPT API using Flutter framework.

pub.dev

api 키만 따로 클래스를 만들어 저장해 둔다. 

class APIKey {
  static const apiKey = "*********************************";
}

1.  한글깨짐 문제 해결 : 및 . 기존방식으로 안되는 부분 수정 . 현재 업데이트된 방식입니다.

기존 코드들은 다빈치용 인줄 모르고 고생좀 했습니다. 

({
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "user", "content": message}
  ],
  "max_tokens": 500,
}),
var parsedReponse = jsonDecode(utf8.decode(response.bodyBytes));

 

2. 스크롤 업데이트로 하단 유지하기

var scrollController = ScrollController();
scrollMethod() { // autoScroll for list builder
  scrollController.animateTo(scrollController.position.maxScrollExtent,
      duration: Duration(milliseconds: 500), curve: Curves.easeOut);
}

 

3. 사용된 패키지.  와 모델 . 

import 'package:speech_to_text/speech_to_text.dart';
import 'package:avatar_glow/avatar_glow.dart';
import 'package:http/http.dart' as http;

 

enum ChatMessageType {user,bot}

class ChatMessage{
  String text;
  ChatMessageType type;
  ChatMessage({required this.text, required this.type});
}

 

4. api_service.dart

import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:noti_local/gpt_chat/api_key.dart';

class GptApiService {
  String baseUrl = 'https://api.openai.com/v1/chat/completions';

  Map<String, String> header = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ${APIKey.apiKey}',
  };

  sendMessage(String message) async {
    print('sendmsg = $message');
    var response = await http.post(
      Uri.parse(baseUrl),
      headers: header,
      body: jsonEncode({
        "model": "gpt-3.5-turbo",
        "messages": [
          {"role": "user", "content": message}
        ],
        "max_tokens": 500,
      }),
    );
    print(response.body);
    var replyRes = jsonDecode(utf8.decode(response.bodyBytes));
    String reply = replyRes['choices'][0]['message']['content'];
    print('json model msg : $reply');
    return reply;
  }
}

 

.5. 메인 스크린 페이지 소스. 

import 'package:avatar_glow/avatar_glow.dart';
import 'package:flutter/material.dart';
import 'package:noti_local/a_drawer.dart';
import 'package:noti_local/gpt_chat/api_service.dart';
import 'package:noti_local/gpt_chat/model_chat.dart';
import 'package:speech_to_text/speech_to_text.dart';

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

  @override
  State<ChatGptHome> createState() => _ChatGptHomeState();
}

class _ChatGptHomeState extends State<ChatGptHome> {
  SpeechToText speechToText = SpeechToText();
  String textChat = 'Chat Gpt Test';
  bool isListening = false;
  final List<ChatMessage> message = []; // for chat
  //
  String textVoice = " Click Hold for Speech to Text";
  GptApiService gptApiService = GptApiService();

  var scrollController = ScrollController();
  scrollMethod() { // autoScroll for list builder
    scrollController.animateTo(scrollController.position.maxScrollExtent,
        duration: Duration(milliseconds: 500), curve: Curves.easeOut);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: AvatarGlow(
        glowColor: Colors.blue,
        endRadius: 90.0,
        repeat: true,
        showTwoGlows: true,
        repeatPauseDuration: const Duration(milliseconds: 100),
        animate: isListening,
        duration:const  Duration(milliseconds: 100),
        child: GestureDetector(
          onTapDown: (voice) async {
            if (!isListening) {
              var available = await speechToText.initialize();
              if (available) {
                setState(() {
                  scrollMethod();
                  isListening = true;
                  speechToText.listen(onResult: (result) {
                    setState(() {
                      //결과를 다시 setState해야 화면이 갱신된다.
                      textVoice = result.recognizedWords;
                      print('textVoice : $textVoice');
                      scrollMethod();
                    });
                  });
                });
              }
            }
          },
          onTapUp: (voice) async {
            speechToText.stop();
            setState(() {
              isListening = false;
              scrollMethod();
            });
            message.add(ChatMessage(text: textVoice, type: ChatMessageType.user));
            var msg = await gptApiService.sendMessage(textVoice); // 안되면 Static 으로 변경한다.
            print('msg : $msg');
            setState(() {
              message.add(ChatMessage(text: msg, type: ChatMessageType.bot));
              scrollMethod();
            });
          },
          child: CircleAvatar(radius: 35, child: Icon(isListening ? Icons.mic : Icons.mic_none, color: Colors.white)),
        ),
      ),
      drawer: ADrawer(),
      appBar: AppBar(title: Text('chat gpt')),
      body: Container(
        alignment: Alignment.center,
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        margin: EdgeInsets.only(bottom: 150),
        padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
        child: Column(
          children: [
            Text(textVoice, style: TextStyle(color: isListening ? Colors.white70 : Colors.white38, fontSize: 28)),
            SizedBox(height: 12),
            //
            Expanded(
                child: Container(
              decoration: BoxDecoration(color: Colors.brown, borderRadius: BorderRadius.circular(20)),
              child: ListView.builder(
                controller: scrollController,
                  physics: const BouncingScrollPhysics(),
                  shrinkWrap: true,
                  itemCount: message.length,
                  itemBuilder: (context, index) {
                  var chat = message[index];

                    return chatBubble(chatText: chat.text, type: chat.type);
                  }),
            )),

          ],
        ),
      ),
    );
  }

  Widget chatBubble({required chatText, required ChatMessageType type}) {
    scrollMethod();
    return Row(
      children: [
        CircleAvatar(
          child: Icon(Icons.person, color: Colors.white),
        ),
        const SizedBox(height: 12),
        Container(
          width:MediaQuery.of(context).size.width*0.8,
          padding: EdgeInsets.all(10),
          margin: EdgeInsets.only(bottom: 10),
          decoration: const BoxDecoration(color: Colors.white38),
          child: Text('$chatText', style: TextStyle(fontSize: 15)),
        ),
      ],
    );
  }

  //
}