FlaskでPDFをテキストに変換するアプリをGPT-4で10分で作ってみる

高速な開発が重要視される現代において、短時間で効果的なアプリケーション開発が求められています。本記事では、PythonとFlaskを使用して、GPT-4の力を活用し、たった10分でPDFからテキストに変換するウェブアプリを構築する方法をご紹介します。

## プロンプトを考える

まずはフローを考える

```
以下の条件でFlaskでWebアプリをHTMLレンダリングで作成したい。


## メインの処理

- ユーザーが/sampleにアクセス
- PDFファイルをアップロード
- アップロードされたファイルの中の文字を文字列に変換

## フロント側のデザイン

- bootstrapを使ってヘッダーを作成
- ヘッダーの中はHome, Menu Login, Aboutの4つ
- flaskでヘッダーに通じる簡単なアクセスを/sampleと同じデザインテンプレートでHello WorldとPタグ表示させる
- CSSは全てのPathで同じものを使う
- PDFのアップロードする場所はシンプルなコンテンツカードにする

## その他の条件
- pythonファイルは１ファイルで完結させること
- Python3.9.5のDockerfile, 起動までのコマンドを追記せよ
- requirements.txtは使わない
- ライブラリのバージョンは無視して構わないのでDockerfile内で必要なファイルをすべてpipコマンドでインストールせよ

```

## それによって出力されたコード

以下が指定された条件に基づくFlaskアプリケーションです。

### app.py

```python
from flask import Flask, render_template, request, redirect, url_for
import PyPDF2
import base64
import io

app = Flask(__name__)

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

@app.route('/sample', methods=['GET', 'POST'])
def sample():
    if request.method == 'POST':
        pdf_file = request.files['pdf_file']
        pdf_reader = PyPDF2.PdfFileReader(pdf_file)
        page_obj = pdf_reader.getPage(0)
        pdf_text = page_obj.extractText()
        return pdf_text
    return render_template('sample.html')

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

### templates/index.html

```html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PDF Converter</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container-fluid">
            <a class="navbar-brand" href="/">Home</a>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link" href="/sample">Menu</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">Login</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">About</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container mt-5">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">Hello World</h5>
                <p class="card-text">This is a simple card for the PDF Converter app.</p>
            </div>
        </div>
    </div>
</body>
</html>
```

### templates/sample.html

```html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PDF Converter</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container-fluid">
            <a class="navbar-brand" href="/">Home</a>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link" href="/sample">Menu</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">Login</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">About</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container mt-5">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">Upload PDF</h5>
                <form action="/sample" method="POST" enctype="multipart/form-data">
                    <input type="file" name="pdf_file" accept="application/pdf" required>
                    <button type="submit" class="btn btn-primary mt-2">Upload</button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>
```

### Dockerfile

```dockerfile
FROM python:3.9.5

WORKDIR /app

COPY app.py /app/
COPY templates /app/templates/

RUN pip install Flask PyPDF2

CMD ["python", "app.py"]
```

### 起動までのコマンド

以下のコマンドでDockerコンテナをビルドして実行します。

```bash
docker build -t pdf_converter .
docker run -p 5000:5000 pdf_converter
```

これで、ブラウザで`http://localhost:5000`にアクセスしてアプリケーションを試すことができます。


## あれれ〜おかしいぞぉ？？

エラーが出たのでコマンドとPythonファイルを修正（本当はこれは良くない）

```bash
docker build -t pdf_converter .
docker run -p get 5001:5000 pdf_converter
```

```python:app.py
from flask import Flask, render_template, request, redirect, url_for
import PyPDF2
import base64
import io

app = Flask(__name__)

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

@app.route('/sample', methods=['GET', 'POST'])
def sample():
    if request.method == 'POST':
        pdf_file = request.files['pdf_file']
        pdf_reader = PyPDF2.PdfFileReader(pdf_file)
        page_obj = pdf_reader.getPage(0)
        pdf_text = page_obj.extractText()
        return pdf_text
    return render_template('sample.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

```

## もう一度動かしてみる

![Screenshot 2023-05-08 at 23.59.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681799/6278bcc7-bb6d-bbeb-4a3e-d2e77679a907.png)


## ライブラリにエラーがあったので再度質問をして修正

```python
from flask import Flask, render_template, request, redirect, url_for
import PyPDF2
import base64
import io

app = Flask(__name__)

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

@app.route('/sample', methods=['GET', 'POST'])
def sample():
    if request.method == 'POST':
        pdf_file = request.files['pdf_file']
        pdf_reader = PyPDF2.PdfReader(pdf_file)  # ここを修正
        page_obj = pdf_reader.pages[0]  # ここも修正
        pdf_text = page_obj.extract_text()
        return pdf_text
    return render_template('sample.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
```

## 成功しました

![Screenshot 2023-05-09 at 0.03.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681799/85dd052a-3bda-577e-1b24-8bdaa2ce8993.png)