4

챗GPT MS애저톤

AIFactory

[교육-서비스] GPT Question Maker: PDF로 만든 문제 & 풀이 제공

rungji
2023.04.24 13:14
571

서비스 소개

다가온 시험기간. 강의자료만 붙들고 외우고 있는 당신. 당신의 실력이 어느 정도인지 파악하고 싶지 않으신가요?

“Chatster”를 통해 당신이 가지고 있는 PDF로 문제를 만들고 당신의 실력을 테스트해보세요.

🤷서비스 배경

  • 공부를 하다 보면, 개념은 알지만 이 개념을 통해서 어떻게 문제가 나올 지 모르기에, 본인이 정확하게 무엇을 모르는지도 모르는 경우가 많습니다. 이에 불편함을 느낀 저희는 PDF를 첨부하면 문제를 만들어주는 서비스를 개발하게 되었습니다.

🤷‍♀️서비스 대상

  • 교수님 혹은 선생님이 주신 강의자료로부터 문제를 만들어서 본인의 실력을 테스트해보고 싶은 학생

🤷‍♂️서비스 목적

  • 본인이 공부한 강의자료를 바탕으로 만들어진 문제를 풀어 봄으로써, 메타 인지 능력을 향상시키고자 하여 이 서비스를 고안하게 되었습니다.

※ 메타 인지란? 자기 자신이 인지하고 있음을 아는 것, 즉 "자신이 알고 있는지 모르고 있는지를 안다"라는 뜻입니다.

서비스 플로우

https://cdn.aifactory.space/images/20230424204348_DXjt.png

1. Main Page: PDF를 업로드하고 해당 PDF에서 문제를 출제할 페이지와 출제할 문제 수를 입력하는 페이지

2. Loading Page: GPT가 문제를 생성하는 동안 표시되는 페이지

3. Questions Page: GPT가 출제한 문제를 화면에 제시하여 웹상에서 직접 문제풀이가 가능하도록 함

4. Answers Page: 오답 여부를 파악하고, 풀이를 확인할 수 있는 페이지로, 출제된 문제를 TXT 파일 형태로 다운로드받을 수 있음

서비스 링크

배포 링크: https://port-0-ms-azure-17xqnr2llgujko5k.sel3.cloudtype.app/

git repository: https://github.com/wldnd2/MS_Azure.git

※ 배포 툴 (cloudtype) 의 무료 용량 제한으로 인해, 배포 링크를 통해 실행하게 되면 1페이지당 1문제씩만 문제 생성이 가능합니다. 더욱 자유로운 사용을 위해선 로컬을 통해 테스트해보심을 추천드립니다!🤓

데모 영상

사용된 스택

front-end: html, css

back-end: flask, python

distribute: cloudtype

기대 효과 & 확장 가능성

  • 학생들은 이 서비스를 이용하여 본인이 공부하던 강의자료를 바탕으로 만들어진 문제를 통해 자신이 정확하게 알고있는 것과 모르고 있는 것이 무엇인지를 알 수 있을 것입니다.
  • 특히, 문제을 출제해 줄 뿐만 아니라 요약 기능을 추가한다면 시험을 대비하여 강의 자료를 단기간에 암기하는 것에도 도움을 줄 것입니다.
  • 논문이나 전공 서적 등의 PDF 파일을 이용하여 문제를 추출하여 학습하는 데 사용한다면, 학습 효율을 극대화시킬 것이라고 기대됩니다.
  • 학원 선생님 등 문제 제작에 많은 시간을 소모하는 이들에게도 이 서비스는 유용하게 사용될 수 있습니다.

Team INFO

팀 Chatster(ChatGPT + Master) | 경북대학교 컴퓨터학부 소속

전지웅(팀장) jun000628@naver.com

김민주 kimminju77786@gmail.com

김현지 khj011030@gmail.com

이은지 leeej106@knu.ac.kr

최희정 nuly7029@gmail.com

코드 공유 (자세한 사항은 github를 확인해주세요.)

run.py

# -*- coding: utf-8 -*-
"""
    pip install flask
    pip install openai
    pip install PyPDF2
    pip install numpy

    실행: python run.py
"""
import os
import json
import openai
import secrets
import numpy as np
from PyPDF2 import PdfReader
from pdf import pdf_processing
from generate_txt import generate_txt_file
from werkzeug.utils import secure_filename
from flask import Blueprint, send_file, request, redirect, url_for, render_template, Flask, session

app = Flask(__name__)
app.secret_key = secrets.token_hex(16)
app.jinja_env.add_extension('jinja2.ext.loopcontrols')

UPLOAD_FOLDER = os.getcwd() + '/uploads'  # 절대 파일 경로
ALLOWED_EXTENSIONS = set(['pdf'])
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 8 * 1024 * 1024 # 16MB로 업로드 크기 제한, RequestEntityTooLarge : 크기 초과시 이 예외 발생, 처리 필요

GPT_answer = []
User_answer = []
global false_answer
false_answer = 0

def allowed_file(filename):
    return '.' in filename and \\
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    global false_answer
    GPT_answer.clear()
    User_answer.clear()
    false_answer = 0
    if request.method == 'POST':
        result = request.form # start_page, end_page, num_of_questions 변수 저장
        file = request.files['myfile']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            session['filename'] = filename
            session['result'] = result
            return redirect(url_for('questions'))
    return render_template('fileupload.html') # GET

@app.route('/questions', methods=['GET', 'POST'])
def questions():
    if request.method == 'POST':
        for key, value in request.form.items():
            User_answer.append(int(value))
        return redirect(url_for('check'))
    else:
        GPT_answer.clear()
        User_answer.clear()
        filename = session.get('filename')
        result = session.get('result')
        result["filename"] = filename
        question = pdf_processing(result["filename"], result["start_page"], result["end_page"], result["num_of_questions"], result["api"])
        Qna_result = {}
        Qna_number = 1
        # print("***********{ PDF RESULT }***********")
        # print(question)
        print("\\n***********{ Questions PROCESSING }*************")
        for key, value in question.items():
            try:
                if(value[0] == "[" and value[-1] == "]"):
                    print("***********{ List processing }***********")
                    value = json.loads(value)
                    for item in value:
                        Qna_result[Qna_number] = item
                        Qna_number += 1
                else:
                    print("***********{ Json processing }***********")
                    Qna_result[Qna_number] = json.loads(value)
                    Qna_number += 1
            except:
                print("***********{ PASS!!!! }*************")
                continue
        print("\\n***********{ FINAL RESULT }*************")
        print(Qna_result)
        print("*******************************************")
        for key, value in Qna_result.items():
            GPT_answer.append(int(value["정답"]))
        print(Qna_result)
        session["GPT_QUESTIONS"] = json.dumps(Qna_result)
        return render_template('questions.html', result=Qna_result)

@app.route('/check', methods=['GET', 'POST'])
def check():
    if request.method == 'POST':
        GPT_response = json.loads(session.get('GPT_QUESTIONS', '{}'))
        print(GPT_response)
        generate_txt_file(GPT_response)
        # 다운로드할 파일 경로 설정
        filepath = os.path.join(os.getcwd(), 'GPT_questions.txt')
        # 파일 다운로드 함수 호출
        return send_file(filepath, as_attachment=True)
    else:
        print("********** CHECK ***********")
        print(GPT_answer)
        print(User_answer)
        false_answer = np.equal(GPT_answer,User_answer)
        false_ans_num = len(false_answer) - sum(false_answer)
        print(false_answer)
        print(false_ans_num)
        GPT_response = json.loads(session.get('GPT_QUESTIONS', '{}'))
        return render_template('check.html', check_result=GPT_response, false_num=false_ans_num, false_answer=false_answer)

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

pdf.py

import os
from werkzeug.utils import secure_filename
from flask import Blueprint, send_file, request, redirect, url_for, render_template, Flask
from PyPDF2 import PdfReader
import openai, json

def pdf_processing(filename:str, start_page, end_page, num_of_questions_per_page, api):
    """ PDF 추출 Setting """
    reader = PdfReader("./uploads/" + filename)
    pages = reader.pages
    # txt = open("./downloads/" + filename + "_questions.txt", 'w', encoding='utf-8')
    questions = {}
    questions_number = 1
    cur_page = 0 # 현재 페이지
    """ ChatGPT Setting """
    OPEN_AI_API_KEY = api # 각자 키 입력 (<https://platform.openai.com/account/api-keys> 확인 ㄱ)
    openai.api_key = OPEN_AI_API_KEY
    model = "gpt-3.5-turbo"
    messages = [ # system content 손 볼 필요 있음
            {"role": "system", "content": "사용자가 전송하는 내용을 토대로 문제를 정확히 1개만 출제해. { 문제 : 질문, 1 : 첫 번째 선택지, 2 : 두 번째 선택지, 3: 세 번째 선택지, 4: 네 번째 선택지, 정답: 정답번호, 해설: 해설 } 이러한 json형태로 출력해."}
    ]

    """ JSON Setting """
    json_file_path = "./downloads/questions.json"
    json_data = {}
    json_data['questions'] = []

    for page in pages: # 페이지별 문제 추출
        cur_page += 1 # 현재 페이지 수
        if cur_page < int(start_page) or cur_page > int(end_page): # start_page ~ end_page 까지만 작동
            continue

        query = page.extract_text() # 각 페이지에서 text 추출하여 query에 저장
        print(f"-- {cur_page} 페이지 문제 추출 중 --")
        messages.append({"role": "user", "content": query})

        for i in range(int(num_of_questions_per_page)):
            # ChatGPT API 호출하기
            response = openai.ChatCompletion.create(
                model=model,
                messages=messages
            )
            answer = response['choices'][0]['message']['content']
            print('answer: ',answer)
            questions[questions_number] = answer
            questions_number += 1

        # 다음 페이지를 위해 messages에서 현재 페이지의 text로 작성된 user content 삭제
        messages.pop()
    # txt.close()
    return questions

generate_txt.py

def generate_txt_file(GPT_questions):
    with open('GPT_questions.txt', 'w', encoding='utf-8') as f:
        for key, value in GPT_questions.items():
            f.write(f"문제 {key}: {value['문제']}\\n")
            question_num = 1
            while True:
                print("ddd")
                try:
                    f.write(f"{question_num}. {value[str(question_num)]}\\n")
                    question_num += 1
                except:
                    break
            f.write(f"정답: {value['정답']}\\n")
            f.write(f"해설: {value['해설']}\\n\\n")

 

4
3개의 댓글
로그인 후 이용해주세요!