OpenAI APIを使ってレアジョブ英会話のDaily News Articleの準備を瞬殺させる

OpenAIを使い、英会話記事の要約、知らない単語の抽出、ディスカッションの回答例を自動生成してもらった
2023.03.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

オンライン英会話のレアジョブにはディスカッション用のDaily News Articleという教材があり、以下の流れでレッスンは進みます。

  • 記事に関連するアイスブレイク
  • 単語の学習(5単語固定)
  • パラグラフ単位の理解確認
  • 記事要約
  • ディスカッション

個人的には、以下のようなケースで予習が有用です。

  • 記事が長かったり難しかったりして、知らない単語が多い場合
  • ベンチマークとなるような要約がほしい場合
  • 記事のテーマに疎く、議論を膨らませにくいので、参考意見がほしい場合

このあたりのタスクをChatGPTでもおなじみOpenAIのAPIを使って瞬殺するプログラムを紹介します。

ChatGPTのウェブインターフェースは回答が完了するまで時間がかかり、ユーザー体験があまり良くないため、人間が介入しない自動化で準備をさっさと済ませ、必要に応じて他のツールを組み合わせることを想定しています。

記事一覧から気になるタイトルの記事を見つけ、URLを渡すだけなので、40秒で支度できます。

実行例

自動化プログラムはPythonで書かれています。

プログラム(prepare-for-rarejob.py)の引数に Daily News Article の URL を渡すだけです。

$ pip install -U requests beautifulsoup4 openai 
$ export OPENAI_API_KEY=...
$ python prepare-for-rarejob.py https://www.rarejob.com/dna/2023/03/25/father-of-cellphone-sees-dark-side-but-also-hope-in-new-tech
PERSONA
you're a married woman in her 30s living in Tokyo with an elementary school-aged child and a Labrador Retriever while working part-time.

URL
https://www.rarejob.com/dna/2023/03/25/father-of-cellphone-sees-dark-side-but-also-hope-in-new-tech/

TITLE
Father of cellphone sees dark side but also hope in new tech

ARTICLE
...(省略)

SUMMARY
Martin Cooper, the man credited with inventing the cellphone 50 years ago, has expressed concerns about the impacts of his invention on society, from the loss of privacy to internet addiction and content harmful to children. Cooper, who was receiving a lifetime award at a trade show in Barcelona, said he had “no way of knowing” he had made history when he made the first public call from a portable telephone in 1973. Despite his worries, he also said he believed the technology’s best days lay ahead, particularly in fields such as education and healthcare.

WORDS
1. Frets (/frɛts/) - Japanese Translation: 悩む - Definition: To worry or be anxious about something - Sample sentence: She frets over her children's safety whenever they're out of the house.

2. Impacts (/ˈɪmpækt/) - Japanese Translation: 影響 - Definition: The effect or influence that something has on someone or something - Sample sentence: The new policy will have a big impact on the company's finances.

...

10. Tuning (/ˈtuːnɪŋ/) - Japanese Translation: 調節 - Definition: To adjust or modify something to make it optimal or better - Sample sentence: He spent hours tuning his guitar to get the perfect sound for the concert.

DISCUSSION
...

Question:Internet addiction is something that can affect anyone, especially the youth. How do you think this could be combatted (ex. limit everyday usage, limit young people’s access to some sites)? Discuss.
Answer:As a married woman in my 30s living in Tokyo with an elementary school-aged child and a Labrador Retriever while working part-time, I believe that limiting everyday usage is the key to combating internet addiction. It is important to set boundaries and establish healthy habits for ourselves and our children. It may be useful to limit access to certain sites or even have set times of the day designated for internet usage. Additionally, developing offline hobbies and activities can redirect our attention away from the internet and help us find joy in other areas of our lives. As a parent, it is my responsibility to monitor my child's internet usage and educate them on the importance of balance and self-control in regards to their online activities.

...

実行プログラム

prepare-for-rarejob.py

"""
レアジョブ Daily News Articleに対して以下を実施

- 要約
- 難しい単語抽出
- ディスカッションの回答例を提示

実行

$ pip install -U requests beautifulsoup4 openai
$ export OPENAI_API_KEY=...
$ python prepare-for-rarejob-daily-news.py https://www.rarejob.com/dna/2023/03/20/google-to-expand-misinformation-prebunking-in-europe/
"""

import os
import sys

import bs4
import requests
from openai import OpenAI

# API KEY
OPEN_API_KEY = os.environ["OPEN_API_KEY"]

client = OpenAI(api_key = OPEN_API_KEY)

# Model
MODEL = "gpt-4"

# Persona
PERSONA = "you're a married woman in her 30s living in Tokyo with an elementary school-aged child and a Labrador Retriever while working part-time."
print("PERSONA")
print(PERSONA)
print()

# URL
if len(sys.argv) > 1:
    url = sys.argv[1]
else:
    url = "https://www.rarejob.com/dna/2023/03/25/father-of-cellphone-sees-dark-side-but-also-hope-in-new-tech/"

print("URL")
print(url)
print()

# Retrieve news
## XXX:If default UA is passed, the server responds with 403 error.
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
req = requests.get(url, headers=headers)
soup = bs4.BeautifulSoup(req.text, "html.parser")

# Title
title = soup.h1.text
print("TITLE")
print(title)
print()

# Article
article = soup.find("div", class_="article").text.strip()
print("ARTICLE")
print(article)
print()

# Summary
print("SUMMARY")
response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {
            "role": "user",
            "content": "Summarize in one paragraph." + article,
        },
    ],
)
print(response.choices[0].message.content.strip())
print()

# Unfamiliar words
print("WORDS")
response = client.chat.completions.create(
    model=MODEL,
    messages=[
        {
            "role": "user",
            "content": "Extract the top 10 least common words in the following article and give their pronunciations, Japanese translations, definitions, and usages."
            + article,
        },
    ],
)
print(response.choices[0].message.content.strip())
print()

# viewpoint discussions
print("DISCUSSION")
for div in soup.find_all("div", class_="discussion_cont"):
    for discussion_cont in div.find_all("li"):
        print("Question:" + discussion_cont.text)

        response = client.chat.completions.create(
            model=MODEL,
            messages=[
                {
                    "role": "user",
                    "content": discussion_cont.text
                    + "Answer in one paragraph from the perspective that "
                    + PERSONA,
                },
            ],
        )
        print("Answer:" + response.choices[0].message.content.strip())
        print()

自動化処理のポイント

自動化対応のキーポイントについて述べます。

プロンプト

プロンプト全般には最低限の指示しか与えていません。

AIはあまりに饒舌に回答する傾向があるため、「1パラグラフで答えて!」というように、簡潔な回答を依頼しています。

適宜調整してください。

ディスカッション

Viewpoint Discussionsでは状況分析系/現状分析したり、意見を述べたりします。

回答する前提となるコンテキストがないと、回答が過度に一般化されていたり、「あなたの国では?」のような制約に対して適切に回答できません。

AIくんが困っている例

  • As an AI language model, I do not have a country or nationality.
  • As an AI language model, I don't have personal ideas
  • As an AI language model, I don't have personal opinions

そのため、プログラム内でペルソナを定義し

PERSONA = "you're a married woman in her 30s living in Tokyo with an elementary school-aged child and a Labrador Retriever while working part-time."

プロンプトでこのペルソナに基づいて具体的に回答するように依頼しています。

Answer in one paragraph from the perspective that you're a married woman in her 30s living in Tokyo with an elementary school-aged child and a Labrador Retriever while working part-time.

このようにすることで、例えばインターネット中毒に対する質問に対して、子供を持つ親の立場から意見を述べてくれます。

As a parent, it is my responsibility to monitor my child's internet usage and educate them on the importance of balance and self-control in regards to their online activities.

ペルソナを詳細に設定するほど、具体的な回答を得られます。

ご自身に合わせてカスタマイズしてください。

あえて自分と真逆のペルソナを設定すると、新鮮な視点を得られたりします。

タワマン文学も可能です。

単語抽出

「未知の単語=あまり使われない単語」という前提で、記事内にある使用頻度の低い上位10位までの単語("extract the top 10 least common words") を抽出しています。

スクレイピング時の処理

このプログラムでは requestsモジュールで記事をスクレイピングしています。

デフォルトのUser-Agentでアクセスするとサーバーが403エラーを返すため、Mac ChromeのUser-Agentを渡しています。

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
req = requests.get(url, headers=headers)

最後に

OpenAI APIを使い、オンライン英会話RareJobのDaily News Article教材の予習をサクッと済ませる方法を紹介しました。

プロンプトやペルソナをいじると、より自分ごのみにカスタマイズできると思います。

それでは。