ChatGPTにライブのMCをしてもらった

# MCをしたくない
私は都内でときどきバンド活動をしていて、数ヶ月に一回ライブを行う。
ライブでは原則MCを行う必要があり、それが本当に嫌。「何をしゃべってもいい」というオープンな状況が苦手すぎる。
2022年6月に行ったライブでは、ライブ前に録音したMCをサンプラーでタイミングよく流すという、謂わば"事前収録MC"を敢行した。そういう変なことする方が恥ずかしいことなんだけど

2023年7月にはバンドの2nd EPのRelease Partyを開催した。そこでやってみた"ChatGPTによる自動MC"について本記事で説明する。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ぺんぎんの憂鬱はたなさんの収録MCから転じてついにChatGPTがMCするライブになりました　大興奮</p>&mdash; Arisa (@arising_liver) <a href="https://twitter.com/arising_liver/status/1680185436264878080?ref_src=twsrc%5Etfw">July 15, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### システム概要
下記を満たすようなコードをPythonで書いてくださいとChatGPTにお願いした。
1. Twitterで質問を募集し、ツイートを取得する
2. ChatGPTにバンドの情報と状況説明、Twitterの質問などをインプットし、MCの文章を生成してもらう
3. 出てきた文章を音声に変換する

#### 利用したもの
* 実行環境: Google Colaboratory
* ツイート取得: Twitter API
* 文章生成: OpenAI API
* 音声変換: Google Cloud Text-to-Speech AI

#### 検討したけど不採用になったもの
* Google Formとスプレッドシート
Twitterで回答を集めるよりも安価で手軽そうだったが、せっかくなのでリアルタイムでTwitterにもたくさん質問が投稿されて盛り上がったらいいなと思った。結局全然そうならなかった

* 音声合成ライブラリ pyttsx3
ChatGPTの回答を音声に変換するtext-to-speechのツールとして最初に使おうと思ったが、エラーが出ないのに音声として出力されなくて、悲しいのでやめた。最後のリリースが2020年みたいなので、バージョン的に何か無理だったのかなと思うけど、単に私が何かミスっていた可能性も高い

## 実際のコード
明らかに効率悪い部分もあるけど、きれいにするための知識や素養があまりないのでこのまま…

### 事前に実行しておくコード
Colabo上で動かすので、最初に!pipでいくつかインストールする。

```python:事前実行:インストール
!pip install openai
!pip install --upgrade google-cloud-texttospeech
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/content/xxx.json"
```

色々インポートして、各種API認証を行い、関数を作っておく。

```python:事前実行:API認証、関数など
import tweepy
import random
import openai
from google.cloud import texttospeech
from IPython.display import Audio

# Twitter APIの認証情報を設定
consumer_key = 'xxx'
consumer_secret = 'xxx'
access_token = 'xxx'
access_token_secret = 'xxx'
#Twitter Deverloper Portalで取得したベアラートークンを設定
bearer_token = 'xxx'

# OpenAI GPT-3 APIの認証情報を設定
openai.api_key = 'xxx'

# Google Cloud Text-to-Speechの認証情報を設定
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/content/xxx.json"

client = tweepy.Client(bearer_token, consumer_key, consumer_secret, access_token, access_token_secret)


# ツイートの検索と取得
def get_tweets(keyword):
    tweets = client.search_recent_tweets(query=keyword, max_results=10)
    tweets_data = tweets.data
    return tweets_data

# ランダムにツイートを選ぶ関数
def select_random_tweet(tweets):
    tweet = random.choice(tweets)
    # ツイート内のハッシュタグ部分は何度も読み上げるとうざいので削除
    refined_tweet_list = tweet.text.replace("#ぺんぎんの憂鬱AIMC", "")
    return refined_tweet_list

# バンドの説明とツイートを組み合わせた質問文を生成する関数
def generate_band_question(band_description, tweet):
    prompt = f"{band_description}\n\n{tweet}"
    return prompt

# ChatGPTから回答を取得する関数
def get_chatgpt_answer(message):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=message,
        max_tokens=1000,
        n=1,
        stop=None,
        temperature=0.7
    )
    return response.choices[0].message.get('content', '')

# 回答を音声で出力する関数
def generate_audio_response(text1, text2):
    client = texttospeech.TextToSpeechClient()
    voice = texttospeech.VoiceSelectionParams(
        language_code="ja-JP",
        ssml_gender=texttospeech.SsmlVoiceGender.FEMALE
    )
    audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)

    response = client.synthesize_speech(
        input=texttospeech.SynthesisInput(text=text1+text2),
        voice=voice,
        audio_config=audio_config
    )

    audio_data = response.audio_content
    return Audio(audio_data)

```
### ライブ時に実行するコード

あとは現場で実行してみるだけ。今回は2パターンの使い方をした。
①バンド情報をインプットして、場面に応じたMCをしてもらう
②Twitterと連携してお客さんからのリアルタイムな質問に回答してもらう


#### ①バンド情報をインプットして、場面に応じたMCをしてもらう
```python: ライブ時：アンコール
# バンドの説明とツイートを組み合わせた質問文の生成と回答の取得
band_description = "ぺんぎんの憂鬱は都内でときどき活動している、Gt.&Vo.たなによるソロプロジェクト。\
以下略"

question = "上記を参考に、ChatGPTには今日のぺんぎんの憂鬱のライブのMCを行なってほしいです。\
下記の要素を入れて200字以内で文章を生成してください\
・これで本編は終了であること\
・ありさちゃんの出演に感謝\
・次はアンコールなので、お客さんにアンコールの催促をしてもらうよう呼びかける"

prompt = generate_band_question(band_description, question)
message = [{'role': 'user', 'content': prompt}]
answer = get_chatgpt_answer(message)

print("ChatGPT Answer:")
print(answer)


# 回答を音声で出力
audio_response = generate_audio_response(answer, " ")
audio_response
```

```py:実際の回答
ChatGPT Answer:
皆さん、本編も終わりとなりますが、ぺんぎんの憂鬱のライブを楽しんでいただけましたでしょうか。本当にありがとうございました。
そして、今回のライブにはありさちゃんも出演してくれました。彼女の素晴らしいパフォーマンスに心から感謝しています。彼女の歌声とぺんぎんの憂鬱の音楽が融合した瞬間、特別な空気が生まれましたね。
さて、次はアンコールです！皆さん、ぺんぎんの憂鬱の音楽に魅了されていることと思います。その熱い気持ちを込めて、アンコールを催促していただけませんか？一緒に声を合わせて、彼らに素晴らしいアンコールパフォーマンスを引き出しましょう！
```

#### ②Twitterと連携してお客さんからのリアルタイムな質問に回答してもらう
```py:ライブ時：質問回答
# Twitterと連携するver.
# ツイートの検索
keyword = "#ぺんぎんの憂鬱AIMC -from:mofmofpenguin -is:retweet"
tweets = get_tweets(keyword)

# ランダムなツイートを選ぶ
question = select_random_tweet(tweets)

# バンドの説明とツイートを組み合わせた質問文の生成と回答の取得
band_description = "ぺんぎんの憂鬱は都内でときどき活動している、Gt.&Vo.たなによるソロプロジェクト。\
中略\
今日のサポートメンバーはギターが大串、ベースが坪田、ドラムが三浦です。上記を参考にして、１００字以内で端的にお客さんからの質問に回答してください。"

prompt = generate_band_question(band_description, question)
message = [{'role': 'user', 'content': prompt}]
answer = get_chatgpt_answer(message)
print("Question:")
print(question)
print("ChatGPT Answer:")
print(answer)

# 音声で出力するときにわかりやすいように質問の後に「回答」って言わせる
question_kaito = question + "回答。"

# 回答を音声で出力
audio_response = generate_audio_response(question_kaito, answer)
audio_response
```

```py:実際の回答
Question:
今日のライブのコンディションは？ 
ChatGPT Answer:
今日のライブのコンディションは素晴らしいです！不穏でかわいい躁鬱オルタナティブな楽曲をお届けします。お楽しみに！
```

## 難しかったところ
**1. Twitter API v2の情報が少ない**
2023年6月とかに従来のv1.1が使えなくなった？ようなので、7月時点では困っている人は多いけど参考になる記事などが少なかった。ChatGPTは3.5を使っていたので、新しい情報をとってきたりもできず（4はできるんだっけ？）、古い情報のままコードを書いてくれてしまう。大したことはしてないけど、エラーが出たときに自力で公式ドキュメントを読んだりして試行錯誤するのは大変だった。

v1.1とv2の違いぽいと思ったところは例えば、2ではbearer tokenというものが必要だったことや、ツイート検索のときのTweepyの関数が微妙に違う（[1ではsearch_tweets](https://docs.tweepy.org/en/stable/api.html)だけど、[2ではsearch_recent_tweets](https://docs.tweepy.org/en/stable/client.html)とか）ことなど…

**2. お金がかかった**
Twitter API v2では、ツイート取得するだけでBasicプランに課金する必要がありなんと100ドルもかかる。数ヶ月前まではツイート取得くらいならお金要らなかったみたいで悲しい。
OpenAIは無料枠に収まり、Google Cloudの方も従量課金と思ってたけどなんか0円みたい(ほんとか？）

**3. ChatGPTのモデル選択**
ChatGPTに作ってもらったコードの中に文章生成に使うChatGPTのモデルが出てくるのでややこしいが、最初は「text-davinci-003」というものになっていた。これを「gpt-3.5-turbo」に変えないと性能がよろしくないということにしばらく気づけず、気付いても直すのにちょっと時間がかかった。

3.5の方は「role」という概念があるようで、GPTくんに話しかけるときに自分の立ち位置を示すことができるようだった。system, assistant, userと３種類あって、systemが役の設定を与える感じ、assistantは回答の連続性に関わるぽい？、userは普通に私たちという感じか。今回の例だと、バンドの事前情報やMCをしてもらう、そしてライブ当日の流れという点でこのroleの使い所はあったかもしれないけど、よーわからんので全部userにした。

**4. Colaboのランタイムリセット**
そんなに困ったわけじゃないけど、時間制限があり90分で頭からやり直しになるので、そこだけ注意が必要だった。
ライブ直前に事前実行部分から全部まわしたら大丈夫だったね。ライブ中に実行したのは質問回答の部分だけでした。Colaboはそこも便利で好き

**5. Google Text-to-Speechの英語対応**
英語でコメントしてくれたお客さんがいて、ChatGPTの本領発揮で英語で回答してくれたんだけど、T2Sの方が日本語を選択していたので見事なひらがな英語でしゃべっていた。聞き取れたのかな？

## おわり
なんかリアルタイムでインタラクティブなおもしろ試みを行ったつもりだったが、まあ中途半端な代物だし集まった質問も10件あるかどうか、当日のQAも内輪ウケな感じになってしまった。ChatGPTが余計なこと付け足してT2Sが流暢に読み上げるMC自体はややウケだった。
ライブ中にみんなが一生懸命Twitterをしている奇異な状況が見たかったけどあんまりそういう人はいないのだ。
それによく考えると質問がリアルタイムである必要は別にない。事前に集めても全然よかったと思う。

Twitter（も名前変わったけどAPIの名前はTwitter APIのままみたいやね）に1万ちょい×しかも2ヶ月分を払ってしまったけど、これをやるためにそんなにお金払う必要はなかったと思います。悲し〜

でも無意味なものにお金を払うのは好きです。いつか意味になるかもしれないため。ツイートに協力してくれた何人かや、「すごいね」をカツアゲしてしまったメンバーたちは超ありがとう！泣
みんなすごいって言って盛り上がっちゃうかなーとか思った。そういうのはできないんだった。おわり

↓実際の様子はこちら
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0gIpCy1ums" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>