평소 영어공부를 하면서 ChatGPT를 자주 활용하는데, 보통 물어보는 질문은 2가지이다.
영어 본문을 읽거나 듣는 중
"It’s time for me to hit the sack"
What is the meaning of the sentence above?
영작을 하는 중
"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 응답에서 받아온 텍스트를 추출하여 반환
}
FirstPage와 ResultPage로 나뉘어지며
FirstPage는 사용자가 TextField에 GPT에 질의할 내용을 입력할수 있게 해놓았으며, 위에서 언급한 두 가지의 질의(프롬프트)를 손쉽게 추가할 수 있도록 두개의 버튼을 만들었다.
'Get Result' 버튼을 누르면 입력된 내용을 prompt 변수에 담아 ResultPage로 이동한다.
ResultPage는 비동기 함수가 존재하므로 데이터를 모두 받아오기전 화면을 그려줄수 있는 FutureBuilder를 사용하여 화면을 표시한다. generateText() 함수를 통해 API 요청으로 prompt의 결과를 받아와 화면에 표시한다.
참고로 text-davinci-003를 사용한 이유는 위 목적으로 사용 시 충분한 답변 능력을 갖고 있다고 판단하였기 때문이다.
아래는 실행 화면이다.



