[Flutter] GPT를 활용한 나만의 영어 공부 앱 만들어보기

조성우·2023년 7월 7일
1

Flutter

목록 보기
3/3
post-thumbnail

평소 영어공부를 하면서 ChatGPT를 자주 활용하는데, 보통 물어보는 질문은 2가지이다.

  1. 영어 본문을 읽거나 듣는 중

    "It’s time for me to hit the sack"
    What is the meaning of the sentence above?

  2. 영작을 하는 중

    "I'm gonna go to a college"
    Is the above sentence correct and natural?


ChatGPT API 요청 혹은 앱 이용 시 매번 위 문장을 입력해야 하니 마침 Flutter를 배워보던 참에 직접 나만의 앱을 간단하게 만들어보기로 했다.


우선 코드는 아래처럼 작성하였다.

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

const apiKey = 'api_key';
const apiUrl = 'https://api.openai.com/v1/completions';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatefulWidget {
  const FirstPage({Key? key}) : super(key: key);

  
  State<FirstPage> createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
  final TextEditingController _controller = TextEditingController();

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("EG: English with GPT"),
      ),
      body: Column(
        children: [
          TextField(
            controller: _controller,
            maxLines: null,
          ),
          const SizedBox(height: 16),
          TextButton(
            onPressed: () {
              setState(() {
                _controller.text += '\nWhat is the meaning of the sentence above?';  // 해당 문장의 의미를 묻는 프롬프트 추가
              });
            },
            child: const Text('Meaning'),
          ),
          const SizedBox(height: 16),
          TextButton(
            onPressed: () {
              setState(() {
                _controller.text += '\nIs the above sentence correct and natural?';  // 해당 문장이 올바르고 자연스러운지 묻는 프롬프트 추가
              });
            },
            child: const Text('Correct & Natural'),
          ),
          const SizedBox(height: 32),
          ElevatedButton(
            onPressed: () {
              String prompt = _controller.text;
              Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => ResultPage(prompt)));  // "Get Result" 버튼을 누르면 ResultPage로 이동
            },
            child: const Text("Get Result"),
          )
        ],
      ),
    );
  }
}

class ResultPage extends StatefulWidget {
  final String prompt;
  const ResultPage(this.prompt, {super.key});

  
  State<ResultPage> createState() => _ResultPageState();
}

class _ResultPageState extends State<ResultPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Result from GPT"),
      ),
      body: FutureBuilder<String>(
        future: generateText(widget.prompt),  // GPT에 결과를 요청하기 위해 generateText 함수 호출
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());  // API 응답을 기다리는 동안 로딩 표시
          } else if (snapshot.hasError) {
            return Text('Error: ${snapshot.error}');
          } else {
            return Text('${snapshot.data}');  // 받아온 텍스트 표시
          }
        },
      ),
    );
  }
}

Future<String> generateText(String prompt) async {
  final response = await http.post(
    Uri.parse(apiUrl),
    headers: {'Content-Type': 'application/json','Authorization': 'Bearer $apiKey'},
    body: jsonEncode({
      "model": "text-davinci-003",
      'prompt': prompt,
      'max_tokens': 1000,
      'temperature': 0,
      'top_p': 1,
      'frequency_penalty': 0,
      'presence_penalty': 0
    }),
  );

  Map<String, dynamic> newresponse = jsonDecode(utf8.decode(response.bodyBytes));

  return newresponse['choices'][0]['text'];  // API 응답에서 받아온 텍스트를 추출하여 반환
}

FirstPageResultPage로 나뉘어지며

  • FirstPage는 사용자가 TextField에 GPT에 질의할 내용을 입력할수 있게 해놓았으며, 위에서 언급한 두 가지의 질의(프롬프트)를 손쉽게 추가할 수 있도록 두개의 버튼을 만들었다.
    'Get Result' 버튼을 누르면 입력된 내용을 prompt 변수에 담아 ResultPage로 이동한다.

  • ResultPage는 비동기 함수가 존재하므로 데이터를 모두 받아오기전 화면을 그려줄수 있는 FutureBuilder를 사용하여 화면을 표시한다. generateText() 함수를 통해 API 요청으로 prompt의 결과를 받아와 화면에 표시한다.

참고로 text-davinci-003를 사용한 이유는 위 목적으로 사용 시 충분한 답변 능력을 갖고 있다고 판단하였기 때문이다.


아래는 실행 화면이다.

(https://github.com/zosungwoo/TIL/tree/main/Flutter/EG)

0개의 댓글

관련 채용 정보