開発に使える？ChatGPTとプロンプトエンジニアリング

こんにちは！逆瀬川 ([@gyakuse](https://twitter.com/gyakuse)) です！
今日は開発に使うときのプロンプトの例を紹介します。ただ、これは一例に過ぎず、もっと雑な表現や工夫されたプロンプトを使っても良いでしょう。大事なのは、どのように情報を与えるとうまくin-context learningしてくれそうか、ということを考えながらプロンプトを渡してあげることだと思います。

## だいじなこと

- ChatGPTのGPT-4を使いましょう
- ChatGPTをそのまま使う場合、[オプトアウト申請](https://docs.google.com/forms/d/1t2y-arKhcjlKc1I5ohl9Gb16t6Sq-iaybVFEbLFFjaI/viewform?ts=63cec7c0&edit_requested=true)し、[受理されたことを確認しましょう](https://twitter.com/gyakuse/status/1642848107284295680)
    - オプトアウトしていても[他者に会話履歴が見える状態になる等のトラブル](https://www.techno-edge.net/article/2023/03/27/1067.html)もあったため、API経由のほうが安全です
    - 会社のプログラム等は情シス部門と連携を取り、会社のポリシーを検討をしましょう

## 実装を依頼するプロンプト

「行いたいこと」「処理の流れ」「参照ドキュメント」という順で書いてあげると良いです。

### サンプルプロンプト


    Google ColaboratoryでWhisper APIとChatGPT APIを使った議事録サマリー生成システムを実装したいと思っています。処理の流れ、参照ドキュメント等について遵守し、プログラムを出力してください。
    
    #  処理の流れ
    
    - Google Colaboratory上での音声のアップロード
    - 音声をWhisper APIで文字起こしにする
    - 文字起こしに対して以下の処理を行う
        - 2500字より小な文字数であればChatGPT APIでそのまま要約する
        - それ以上の文字数であれば2500字ずつ要約する (情報損失回避のため50字程度のオーバーラップ部分を設ける)
            - 要約を結合して、さらなる要約をかける
    - 作成された要約を表示する
    
    # 参照ドキュメント: Whisper API
    
    ```
    import openai
    audio_file= open("/path/to/file/audio.mp3", "rb")
    transcript = openai.Audio.transcribe("whisper-1", audio_file)
    ```
    
    response
    
    - text：文字起こし全体
    - duration：秒数
    - language：言語
    
    # 参照ドキュメント: ChatGPT API
    
    ```
    import openai
    openai.api_key = "sk-..."  # APIキー
    
    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo", 
        messages=[{"role": "user", "content": "こんにちは！"}]
    )
    ```
    
    response
    
    - choices：返答一覧
        - choices[0].message.contentとアクセスすることで、返答メッセージが表示されます。
    - id：リクエストID
    - model：使用したモデル
    - object：使用したAPIオブジェクト
    
    # 処理
    
    それでは実装してください。

### サンプルレスポンス (GPT-4)

>以下がGoogle Colaboratory上でWhisper APIとChatGPT APIを使った議事録サマリー生成システムの実装です。必要なライブラリをインストールして、APIキーを設定した後にこのコードを実行してください。

```python
# 必要なライブラリのインストール
!pip install openai

# ライブラリのインポート
import openai
from google.colab import files

# APIキーの設定
openai.api_key = "sk-..."

# Google Colaboratory上での音声ファイルのアップロード
uploaded = files.upload()
file_name = list(uploaded.keys())[0]

# 音声ファイルをWhisper APIで文字起こしにする
with open(file_name, "rb") as audio_file:
    transcript = openai.Audio.transcribe("whisper-1", audio_file)

transcript_text = transcript['text']

# 文字起こしをChatGPT APIで要約する
def summarize(text):
    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": f"次の文章を要約してください：{text}"}],
    )
    return completion.choices[0].message.content

# 文字数が2500字以下であれば、そのまま要約する
if len(transcript_text) <= 2500:
    summary = summarize(transcript_text)
else:
    summaries = []
    start = 0
    end = 2500

    # 2500字ずつ分割し、要約する
    while start < len(transcript_text):
        if end > len(transcript_text):
            end = len(transcript_text)

        segment = transcript_text[start:end]
        summaries.append(summarize(segment))

        start = end - 50
        end += 2450

    # 要約を結合し、さらに要約する
    combined_summary = " ".join(summaries)
    summary = summarize(combined_summary)

# 作成された要約を表示する
print(summary)
```

>このコードは、Google Colaboratory上で音声ファイルをアップロードし、Whisper APIを使って文字起こしを行い、ChatGPT APIを使って要約を作成します。要約が作成されたら、画面に表示されます。

### サンプルレスポンス (GPT-3.5)

>以下が、Google Colaboratory上でWhisper APIとChatGPT APIを使った議事録サマリー生成システムのプログラムです。

```python
import openai
import io
import math

# APIキーの設定
openai.api_key = "YOUR_API_KEY"

# 音声ファイルのアップロード
from google.colab import files
uploaded = files.upload()

# Whisper APIでの文字起こし
audio_file = io.BytesIO(uploaded['AUDIO_FILE_NAME'])
transcript = openai.Audio.transcribe("whisper-1", audio_file)

# 要約の初期化
summary = ""

# 要約処理
if len(transcript["text"]) <= 2500:
  # 2500字以下の場合、そのままChatGPT APIで要約
  completion = openai.Completion.create(
      model="text-davinci-002",
      prompt=f"要約してください：\n{transcript['text']}\n要約：",
      max_tokens=100,
      n=1,
      stop=None,
      temperature=0.5,
  )
  summary = completion.choices[0].text
else:
  # 2500字より長い場合、2500字ずつ要約し、結合してから再度要約
  texts = [transcript["text"][i:i+2500] for i in range(0, len(transcript["text"]), 2450)]
  summaries = []
  for text in texts:
    completion = openai.Completion.create(
        model="text-davinci-002",
        prompt=f"要約してください：\n{text}\n要約：",
        max_tokens=100,
        n=1,
        stop=None,
        temperature=0.5,
    )
    summaries.append(completion.choices[0].text)
  summary = " ".join(summaries)
  completion = openai.Completion.create(
      model="text-davinci-002",
      prompt=f"要約してください：\n{summary}\n要約：",
      max_tokens=100,
      n=1,
      stop=None,
      temperature=0.5,
  )
  summary = completion.choices[0].text

# 要約の表示
print(summary)
```

>上記のプログラムでは、まずAPIキーを設定しています。その後、Google Colaboratory上で音声ファイルをアップロードし、Whisper APIで文字起こしを行います。次に、文字起こしの文字数によって要約処理を行います。2500文字以下の場合はそのままChatGPT APIで要約し、2500文字より長い場合は2500文字ずつ要約を行ってから結合し、再度ChatGPT APIで要約を行います。最後に、要約を表示します。

### GPT-4 vs GPT-3.5

- GPT-3.5では参照ドキュメントで示されたChatGPT APIのリクエスト方法を採用できていません
- 要約処理が関数化されていません
- これは言語モデルの事前知識に依存した部分ですが、アップロードされたファイルの参照が適切ではありません

特に提示されたドキュメントを忠実に参照する部分でGPT-4が優れています。GPT-3.5では忠実に参照させるために余計なプロンプトが必要です。また、参照してほしいドキュメントが長い場合、8k contextが扱えるGPT-4が適切です。

## 実装の機能追加

機能追加や修正においては「相談内容」「修正リスト」「既存の実装」「参照ドキュメント」という順に書いて上げると良いです。

### サンプルプロンプト

    Google ColaboratoryでWhisper APIとChatGPT APIを使った議事録サマリー生成システムを実装しましたがいくつか修正したいことがあります。修正リストと既存の実装と参照ドキュメントを参考に修正したプログラムを出力してください。
        
    # 修正リスト
    
    - transcript['text']ではなく、transcript.textとアクセスする
    - 最後に要約をGoogleのText-to-Speechで音声合成する
    
    # 既存の実装
    
    ```
    # ライブラリのインポート
    import openai
    from google.colab import files
    
    # APIキーの設定
    openai.api_key = "sk-..."
    
    # Google Colaboratory上での音声ファイルのアップロード
    uploaded = files.upload()
    file_name = list(uploaded.keys())[0]
    
    # 音声ファイルをWhisper APIで文字起こしにする
    with open(file_name, "rb") as audio_file:
        transcript = openai.Audio.transcribe("whisper-1", audio_file)
    
    transcript_text = transcript['text']
    
    # 文字起こしをChatGPT APIで要約する
    def summarize(text):
        completion = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[{"role": "user", "content": f"次の文章を要約してください：{text}"}],
        )
        return completion.choices[0].message.content
    
    # 文字数が2500字以下であれば、そのまま要約する
    if len(transcript_text) <= 2500:
        summary = summarize(transcript_text)
    else:
        summaries = []
        start = 0
        end = 2500
    
        # 2500字ずつ分割し、要約する
        while start < len(transcript_text):
            if end > len(transcript_text):
                end = len(transcript_text)
    
            segment = transcript_text[start:end]
            summaries.append(summarize(segment))
    
            start = end - 50
            end += 2450
    
        # 要約を結合し、さらに要約する
        combined_summary = " ".join(summaries)
        summary = summarize(combined_summary)
    
    # 作成された要約を表示する
    print(summary)
    ```
    
    # 参照ドキュメント: GoogleのText-to-Speech
    
    ```
    """Synthesizes speech from the input string of text or ssml.
    Make sure to be working in a virtual environment.
    
    Note: ssml must be well-formed according to:
        https://www.w3.org/TR/speech-synthesis/
    """
    from google.cloud import texttospeech
    
    # Instantiates a client
    client = texttospeech.TextToSpeechClient()
    
    # Set the text input to be synthesized
    synthesis_input = texttospeech.SynthesisInput(text="Hello, World!")
    
    # Build the voice request, select the language code ("en-US") and the ssml
    # voice gender ("neutral")
    voice = texttospeech.VoiceSelectionParams(
        language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
    )
    
    # Select the type of audio file you want returned
    audio_config = texttospeech.AudioConfig(
        audio_encoding=texttospeech.AudioEncoding.MP3
    )
    
    # Perform the text-to-speech request on the text input with the selected
    # voice parameters and audio file type
    response = client.synthesize_speech(
        input=synthesis_input, voice=voice, audio_config=audio_config
    )
    
    # The response's audio_content is binary.
    with open("output.mp3", "wb") as out:
        # Write the response to the output file.
        out.write(response.audio_content)
        print('Audio content written to file "output.mp3"')
    ```

### サンプルレスポンス (GPT-4)

>以下に修正後のプログラムを示します。

```python
# ライブラリのインポート
import openai
from google.colab import files
from google.cloud import texttospeech

# APIキーの設定
openai.api_key = "sk-..."

# Google Colaboratory上での音声ファイルのアップロード
uploaded = files.upload()
file_name = list(uploaded.keys())[0]

# 音声ファイルをWhisper APIで文字起こしにする
with open(file_name, "rb") as audio_file:
    transcript = openai.Audio.transcribe("whisper-1", audio_file)

transcript_text = transcript.text

# 文字起こしをChatGPT APIで要約する
def summarize(text):
    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": f"次の文章を要約してください：{text}"}],
    )
    return completion.choices[0].message.content

# 文字数が2500字以下であれば、そのまま要約する
if len(transcript_text) <= 2500:
    summary = summarize(transcript_text)
else:
    summaries = []
    start = 0
    end = 2500

    # 2500字ずつ分割し、要約する
    while start < len(transcript_text):
        if end > len(transcript_text):
            end = len(transcript_text)

        segment = transcript_text[start:end]
        summaries.append(summarize(segment))

        start = end - 50
        end += 2450

    # 要約を結合し、さらに要約する
    combined_summary = " ".join(summaries)
    summary = summarize(combined_summary)

# 作成された要約を表示する
print(summary)

# 要約をGoogleのText-to-Speechで音声合成する
client = texttospeech.TextToSpeechClient()

synthesis_input = texttospeech.SynthesisInput(text=summary)

voice = texttospeech.VoiceSelectionParams(
    language_code="ja-JP", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL
)

audio_config = texttospeech.AudioConfig(
    audio_encoding=texttospeech.AudioEncoding.MP3
)

response = client.synthesize_speech(
    input=synthesis_input, voice=voice, audio_config=audio_config
)

# 音声ファイルを出力する
with open("summary_output.mp3", "wb") as out:
    out.write(response.audio_content)
    print('Audio content written to file "summary_output.mp3"')

# 音声ファイルをダウンロードする
files.download("summary_output.mp3")
```

>修正点:
>
>transcript['text'] を transcript.text に変更しました。
>最後に要約をGoogleのText-to-Speechで音声合成し、出力ファイルをダウンロードできるようにしました。この部分では、言語コードを日本語に設定するために、language_code="ja-JP" を使用しています。必要に応じて言語コードを変更してください。

### レスポンスについて

- language_codeが自動的にja-JPになっていて嬉しいです


## おわりに

見てきたとおり、GPT-4を使うとわりと簡単に実装や実装の修正ができます。
参照したいドキュメントを検索してきて抽出する処理や、処理の流れを生成させることで、もっと簡単にプログラムの自動生成や修正ができるかもしれません。たとえば、Webサイト作成においては、NextJSやCSSフレームワーク(Tailwindなど)のドキュメントをembeddingsにしてvector storeに入れておき、必要なドキュメントを都度取得してプロンプトに入れるような自動化が検討できます。