AI 탐구노트

ChatGPT를 이용해 퀴즈 프로그램 만들기 본문

DIY 테스트

ChatGPT를 이용해 퀴즈 프로그램 만들기

42morrow 2024. 9. 3. 12:27
ChatGPT의 코딩 능력을 빌어와 아이와 함께 할 수 있는 프로그램 만들기

 

유튜브에는 재미난 퀴즈를 소개하는 채널들이 있습니다. 아이와 가끔씩 들여다 보는 편인데 생각보다 재미있어서 보다보면 어느새 몇 개는 훌쩍 지나가 버리고 말죠. 아무래도 제시되는 문제들이 일반적인 것들이어서 나름 나만의 퀴즈를 만들어서 아이와 함께 해 보는 것은 어떨까 생각하게 됐고 그렇게 해 봤습니다. 

 

코딩은 ChatGPT한테 시키고 저는 그걸 옮겨서 실행만 시키는 걸로... ^^; 

 

일단 다음과 같은 프롬프트를 이용했습니다. 

퀴즈를 내는 웹 프로그램을 만들텐데 구현하려는 기능은 다음과 같아.
단, python 만으로 가능하면 그렇게 해 주고 그렇지 않으면 javascript나 html을 사용해도 좋아.

1.화면은 첨부한 이미지처럼 배경 화면은 동일하고 문제내용과 카운팅 이미지(애니메이션 GIF), 정답만 바뀌어야 해.
2.퀴즈의 수는 코드의 초기에 변수로 설정할 수 있어야 해. 기본값은 10이야.
3.각 퀴즈는 문제 표시, 3초간 카운팅, 정답 표시, 1초 쉬고 다음 퀴즈로 넘어가야 해.
4.각 퀴즈는 좌측에는 문제가 표시되고 우측에는 3초간 카운팅하는 이미지가 출력된 후 그 이미지가 없어지고 정답이 표시되어야 해.
5.퀴즈의 문제내용과 정답은 json 파일에서 읽어오도록 해야 해.
6.배경음악이 깔릴 수 있도록 해야 해.
7.어떤 브라우저에서도 실행될 수 있어야 해.

 

1, 6, 7 번의 경우, 배경 이미지, 카운팅 이미지, 배경음악 등이 별도 파일로 필요하기 때문에 실제로는 이미지 대신 텍스트로, 배경음악은 없는 상태로 진행되었습니다. 

 

Python 코드 (app.py)

ChatGPT는 python으로 flask를 웹서버로 해서 index.html을 불러오는 형태로 코드로 생성해 줬습니다. 예전에는 html에서 javascript로 로컬 리소스인 json 파일을 직접 불러올 수 없어서 이런 방식을 많이 썼을텐데, 요새는 그런 부분을 해결한 방식도 있는 걸로 아는데... 하는 생각이 들었지만 너무 깊이 들어가지 않기 위해 이 정도에서 스탑...  ^^; 이렇게 해서 생성된 코드는 다음과 같습니다.

 

코드 : app.py

from flask import Flask, jsonify, render_template
import json

app = Flask(__name__)

# JSON 파일에서 퀴즈 데이터를 읽어옵니다.
with open('quiz_data.json', 'r') as file:
    quiz_data = json.load(file)

@app.route('/api/quizzes')
def get_quizzes():
    return jsonify(quiz_data)

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

 

 

실제 화면 출력을 하는 index.html 파일은 다음과 같습니다. flask의 처리 방식 때문에 해당 파일은 templates 폴더를 만들고 이 아래에 위치해야 합니다. 

 

코드 : index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Quiz App</title>
    <style>
        body {
            background-image: url('background.jpg'); /* 배경 이미지 */
            background-size: cover;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            font-family: Arial, sans-serif;
            color: #333;
        }
        #quiz-container {
            width: 70%;
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
            display: flex;
            justify-content: space-between;
            align-items: center;
            position: relative;
        }
        #question {
            font-size: 24px;
            width: 45%;
            text-align: center;
        }
        #answer-section {
            text-align: center;
            width: 45%;
        }
        #countdown {
            font-size: 48px;
            color: #F39C12;
            background: #FAD7A0;
            border-radius: 50%;
            width: 80px;
            height: 80px;
            line-height: 80px;
            margin: 0 auto;
        }
        #answer {
            font-size: 36px;
            margin-top: 20px;
            display: none;
        }
    </style>
</head>
<body>
    <div id="quiz-container">
        <div id="question">Question will appear here</div>
        <div id="answer-section">
            <div id="countdown">3</div>
            <div id="answer">Answer will appear here</div>
        </div>
    </div>
    <audio id="background-music" src="background.mp3" loop></audio>
    <script>
        let quizzes = [];
        let currentQuiz = 0;

        function showNextQuiz() {
            if (currentQuiz < quizzes.length) {
                // 랜덤하게 퀴즈 선택
                let quizIndex = Math.floor(Math.random() * quizzes.length);
                let quiz = quizzes.splice(quizIndex, 1)[0]; // 선택된 퀴즈를 배열에서 제거
                
                document.getElementById('question').innerText = quiz.question;
                document.getElementById('answer').style.display = 'none';
                document.getElementById('countdown').style.display = 'block';
                startCountdown(3, () => {
                    document.getElementById('countdown').style.display = 'none';
                    document.getElementById('answer').innerText = quiz.answer;
                    document.getElementById('answer').style.display = 'block';
                    currentQuiz++;
                    setTimeout(showNextQuiz, 1000);
                });
            } else {
                // 퀴즈 종료 시 추가적인 작업을 여기에 구현할 수 있습니다.
                alert("퀴즈가 종료되었습니다!");
            }
        }

        function startCountdown(seconds, callback) {
            let countdownElement = document.getElementById('countdown');
            let interval = setInterval(() => {
                countdownElement.innerText = seconds;
                if (seconds <= 0) {
                    clearInterval(interval);
                    callback();
                }
                seconds--;
            }, 1000);
        }

        function loadQuizzes() {
            fetch('/api/quizzes')
                .then(response => response.json())
                .then(data => {
                    quizzes = data.quizzes;
                    showNextQuiz();
                });
        }

        document.addEventListener('DOMContentLoaded', () => {
            document.getElementById('background-music').play();
            loadQuizzes();
        });
    </script>
</body>
</html>

 

퀴즈 데이터 생성

우선 자동으로 생성된 quiz_data.json 파일은 question, answer를 가진 json 형태의 단순 파일이었고, 다시 ChatGPT에게 해당 json 포맷 형태로 퀴즈 문제를 만들어 달라고 해서 아래와 같이 채웠습니다. 문항수를 100개로 하니까 생성 토큰의 사이즈 때문인지 버벅대더니 결국은 완성을 하지 못했습니다. 로그를 보니 구분자 문제라는데... 아무래도 크기 문제로 보여서 오류 전까지 생성된 것을 옮겨서 사용했습니다. 문항 수를 줄여서 하면 문제 없을 것으로 생각됩니다. 

 

이렇게 해서 생성된 퀴즈 데이터는 다음과 같습니다.

 

코드 : quiz_data.json

{
    "quizzes": [
        {"question": "그리스 신화에서 제우스의 아내이자 결혼의 여신은 누구인가?", "answer": "헤라"},
        {"question": "그리스 신화에서 지혜의 여신이자 아테네의 수호신은 누구인가?", "answer": "아테나"},
        {"question": "그리스 신화에서 바다의 신으로, 트라이던트를 들고 있는 신은 누구인가?", "answer": "포세이돈"},
        {"question": "그리스 신화에서 태양의 신이자 예술, 음악의 신은 누구인가?", "answer": "아폴론"},
        {"question": "그리스 신화에서 사랑과 미의 여신은 누구인가?", "answer": "아프로디테"},
        {"question": "그리스 신화에서 저승의 신으로, 죽은 자의 영혼을 다스리는 신은 누구인가?", "answer": "하데스"},
        {"question": "그리스 신화에서 술과 축제의 신은 누구인가?", "answer": "디오니소스"},
        {"question": "그리스 신화에서 대지의 여신으로, 모든 생명의 어머니로 여겨지는 여신은 누구인가?", "answer": "가이아"},
        {"question": "그리스 신화에서 헤라클레스가 수행한 12가지 과업 중 첫 번째 과업은 무엇이었는가?", "answer": "네메아의 사자 퇴치"},
        {"question": "그리스 신화에서 페르세우스가 퇴치한 괴물로, 머리카락이 뱀으로 이루어진 생물은 누구인가?", "answer": "메두사"},
        {"question": "그리스 신화에서 판도라가 연 상자에서 마지막으로 남은 것은 무엇인가?", "answer": "희망"},
        {"question": "그리스 신화에서 불을 인간에게 가져다 준 티탄은 누구인가?", "answer": "프로메테우스"},
        {"question": "그리스 신화에서 에게해에 이름을 남긴 인물은 누구인가?", "answer": "테세우스"},
        {"question": "그리스 신화에서 미궁을 만든 건축가는 누구인가?", "answer": "다이달로스"},
        {"question": "그리스 신화에서 이카로스는 태양에 너무 가까이 다가가 날개가 녹았다. 그의 날개는 무엇으로 만들어졌는가?", "answer": "밀랍"},
        {"question": "그리스 신화에서 오디세우스가 집으로 돌아가는 여정에서 겪은 괴물 중 하나로, 외눈을 가진 거인은 누구인가?", "answer": "폴리페모스"},
        {"question": "그리스 신화에서 모든 것을 황금으로 변하게 만든 미다스 왕의 손은 어떤 신으로부터 얻은 능력인가?", "answer": "디오니소스"},
        {"question": "그리스 신화에서 페르세포네를 납치한 신은 누구인가?", "answer": "하데스"},
        {"question": "그리스 신화에서 파르테논 신전은 어떤 여신을 위해 지어졌는가?", "answer": "아테나"},
        {"question": "그리스 신화에서 아킬레스는 무엇으로 인해 죽음을 맞이했는가?", "answer": "발뒤꿈치에 맞은 화살"},
        {"question": "그리스 신화에서 트로이 전쟁의 원인이 된 헬레네의 남편은 누구인가?", "answer": "메넬라오스"},
        {"question": "그리스 신화에서 아르테미스는 무엇의 여신인가?", "answer": "사냥"},
        {"question": "그리스 신화에서 트로이 목마를 설계한 그리스 영웅은 누구인가?", "answer": "오디세우스"},
        {"question": "그리스 신화에서 이아손과 아르고 호의 선원들이 찾던 황금 양털은 어디에 있었는가?", "answer": "콜키스"},
        {"question": "그리스 신화에서 시지푸스는 무엇을 반복해서 굴려야 하는 형벌을 받았는가?", "answer": "큰 바위"},
        {"question": "그리스 신화에서 헤르메스는 어떤 역할을 맡고 있는 신인가?", "answer": "전령의 신"},
        {"question": "그리스 신화에서 오르페우스는 누구를 저승에서 데려오려고 했는가?", "answer": "에우리디케"},
        {"question": "그리스 신화에서 나르키소스는 무엇을 보고 사랑에 빠졌는가?", "answer": "자신의 모습"},
        {"question": "그리스 신화에서 헤라클레스는 누구의 아들로 태어났는가?", "answer": "제우스"},
        {"question": "그리스 신화에서 피그말리온은 자신이 조각한 여신과 사랑에 빠졌습니다. 이 여신은 누구인가?", "answer": "아프로디테"},
        {"question": "그리스 신화에서 아폴론은 누구를 사랑했으나 결국 나무로 변하게 되었는가?", "answer": "다프네"},
        {"question": "그리스 신화에서 페가수스는 누구의 피에서 태어났는가?", "answer": "메두사"},
        {"question": "그리스 신화에서 아틀라스는 어떤 형벌을 받았는가?", "answer": "하늘을 지탱하는 일"},
        {"question": "그리스 신화에서 제우스는 누구를 납치하여 크레타 섬으로 데려갔는가?", "answer": "에우로페"},
        {"question": "그리스 신화에서 오디세우스가 집으로 돌아오는 길에 세이렌의 노래를 피하기 위해 귀를 막은 재료는 무엇인가?", "answer": "밀랍"},
        {"question": "그리스 신화에서 오이디푸스는 자신의 아버지를 죽이고 어머니와 결혼하게 되는데, 그의 아버지는 누구인가?", "answer": "라이오스"},
        {"question": "그리스 신화에서 판은 무엇의 신인가?", "answer": "목축과 목동"},
        {"question": "그리스 신화에서 다이달로스의 아들이자 태양에 너무 가까이 다가간 인물은 누구인가?", "answer": "이카로스"},
        {"question": "그리스 신화에서 오디세우스의 아내로, 그의 귀환을 오랜 시간 기다린 여성은 누구인가?", "answer": "페넬로페"},
        {"question": "그리스 신화에서 '멈춰!'라는 의미의 주문을 걸어 움직임을 멈추게 한 괴물은 누구인가?", "answer": "메두사"},
        {"question": "그리스 신화에서 '판도라의 상자'라는 표현은 무엇을 의미하는가?", "answer": "예상치 못한 문제의 시작"},
        {"question": "그리스 신화에서 '피닉스'는 무엇을 의미하는 상징인가?", "answer": "재생과 불사"},
        {"question": "그리스 신화에서 '스핑크스'는 무슨 동물의 머리를 가지고 있는가?", "answer": "사람"},
        {"question": "그리스 신화에서 '카산드라의 저주'는 무엇을 의미하는가?", "answer": "미래를 예언할 수 있지만 아무도 믿지 않음"},
        {"question": "그리스 신화에서 '아마존'은 어떤 전사의 이름인가?", "answer": "여성 전사"},
        {"question": "그리스 신화에서 '아르고'는 무엇의 이름인가?", "answer": "배"},
        {"question": "그리스 신화에서 '타르타로스'는 무엇을 의미하는가?", "answer": "지하세계의 깊은 구덩이"},
        {"question": "그리스 신화에서 '헤시오도스'는 어떤 역할을 한 인물인가?", "answer": "시인"},
        {"question": "그리스 신화에서 '아틀란티스'는 어떤 도시로 묘사되는가?", "answer": "바다에 잠긴 도시"},
        {"question": "그리스 신화에서 '프로테우스'는 어떤 능력을 가진 신인가?", "answer": "변신"},
        {"question": "그리스 신화에서 '이카리아'는 어떤 사건으로 인해 이름이 붙여졌는가?", "answer": "이카로스의 추락"},
        {"question": "그리스 신화에서 '세이렌'은 어떤 생물로 묘사되는가?", "answer": "유혹적인 목소리를 가진 바다 생물"}
    ]
  }

 

 

완성된 파일 구조는 다음과 같습니다. templates 폴더 만든 것과 파일들 껍데기 만들어서 ChatGPT가 생성해 준 내용을 복사-붙여넣기 한 것 외에는 제가 한 일이 없습니다. 

사진 : 파일, 폴더 구조

 

python app.py 로 실행하면 다음과 같은 결과를 볼 수 있습니다. 

사진 : 문제가 표시되는 동안의 모습, 카운트 다운이 됨

 

사진 : 카운트다운 이후 정답이 표시되는 모습

 

10분 남짓한 시간동안 만든 것 치고는 잘 동작해서 만족스러웠습니다. 실제 유튜브 영상에서처럼 하려면 배경 이미지를 만들고 화면을 양쪽으로 잘 나누고 배치하며, 배경 음악도 만들어 넣고 하는 과정들이 필요하겠죠.