평소 영어공부를 하면서 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를 사용한 이유는 위 목적으로 사용 시 충분한 답변 능력을 갖고 있다고 판단하였기 때문이다.
아래는 실행 화면이다.