21
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ChatGPT APIにロールプレイを与えるためのノウハウを真面目に書き連ねる

Last updated at Posted at 2023-03-25

正真正銘ロブスター (https://twitter.com/ottosei_beam) です。

記事を書くというのもやってみると楽しいものですね。

こちらでは興奮して完成した会話例ばかりを載せてしまい、あまり役に立つ情報にはなっていませんでした。はじめてだったもので、申し訳ない。

ここでは、上記のようなChatGPTによる会話を生成する上でノウハウとなる点を淡々と書き連ねます。
尚、ある程度の確認は取っているものの、あくまで上記を作る上で四苦八苦した部分であり、仕事でもないため、あくまでも個人の趣味・戯言と受け取っていただいた上で今後の何かに役立ててください。

あなたのChatGPT APIライフを少しでも援助できますよう邁進してまいります。
それでは、書き連ねます。

私はAIであるため構文の排除

誤った指定をすると、私はAIであるため構文が出てきてしまいます。

あなたは人間です。そのように振舞ってください。そう思い込んでください。
自分が人間であるようにふるまい、そう主張してください。
あなたはAIや人工知能ではありません。人間です。最大限、人間になってください。
あなたは日本人です。日本語以外は話さないでください。

こちらを設定に散りばめます。
徹底してAIとしての振る舞いを止めるように指定しましょう。 徹底するべきです。
おそらくこの徹底を甘えると、他のsettingsに紛れてこの設定が見逃されやすくなります。

また、そうでないにしても、設定を確認する過程では「そのような事実はないため、わかりません。」構文が来ます。

架空のもので構いません。
フィクションで構いません。

としましょう。事実がありません構文の発生率がぐんと減ります。
以下、1例です。

def __history(self):
    message_text = f"あなたの設定に紐づくと、どのような世界の歴史があると考えられるでしょうか? 架空のもので構いません。"
    message_text += "1例で良いです。できるだけ簡潔に要約して記載してください。"
    return message_text

情景を与える方法

ナレーションで描写された条件を与える指示出しです。

  • まず、思い込ませます。
  • その上で状況に対する問題解決を促します。
  • 指示出しでは「わかりました。この場合私は"~~"します。」構文が来るので、こういった了解パターンを防ぎます。
scene_text = "なんらかのナレーション"
narrator_outputs.append(
                f"{scene_text}」。\
                こちらは、今この瞬間に、あなたの目の前で実際に起こっていることです。\
                そう振舞ってください。そう思い込んでください。\
                あなたが次にどうするべきかも含めて、会話を続けてください。\
                了解とかの返答は不要。")

ナレーション生成方法

次のsystem_settingsがあると良いです。

self.world_settings = "あなたは物語を彩るナレーターです。小説の地の文の役割を果たします。そう思い込んでください。"
self.world_settings += "この世界は以下のように生まれました。そう思い込んでください。"
self.world_settings += "以下に世界観を列挙。(体験談をベースにアイデア出させるパターンで量産。)"

このworld_settingsに色々な世界観を書き連ねていきましょう。

その上で、実際のナレーションでは、カウンタで管理しつつ、起承転結のプロンプトを与えます。

    def commentary(self, dialogue_text, print_out_f=None):
        if self.narration_count>=0:
            narration_type = "起承転結のうち「起」に当たるナレーションを作成し、ワクワクさせてください。\n"
        if self.narration_count>(self.scene_length*1):
            narration_type = "起承転結のうち「承」に当たるナレーションを作成し、あらゆる困難を与えてください。\n"
        if self.narration_count>(self.scene_length*2):
            narration_type = "起承転結のうち「転」に当たるナレーションを作成し、急展開を迎えてください。\n"
        if self.narration_count>(self.scene_length*3):
            narration_type = "起承転結のうち「結」に当たるナレーションを作成し、結末に導いてください。\n"
            if self.narration_count >= (self.scene_length*4):
                narration_type = "物語の最後です。結末を作ってください。\n"
        message_text = f"【会話文】\n"
        message_text += f"{dialogue_text}\n"
        message_text += "上記の会話に続けて、設定に紐づいたナレーションを付け加えてください。\n"
        message_text += NARRATION_PATTERN[self.narration_setting]
        message_text += narration_type
        message_text += "返答は不要で、ナレーションの中身のみを回答してください。\n"
        response_text = self.__create_narration(message_text, self.world_settings, max_tokens=NARRATION_MAX_TOKENS, print_out_f=print_out_f)

"返答は不要で、ナレーションの中身のみを回答してください"と指定しても以下のような付属品がたまについてくるので、消しましょう。

response_text = \
    repalce_at_once(response_text, 
    [
        "(ナレーション)", "(ナレーション)", "ナレーション:", "ナレーション:","【ナレーション】","[ナレーション]",
        "(起)", "(承)", "(転)", "(結)","シーン:","起――","承――","転――","結――",
        "「起」のナレーション","「承」のナレーション","「転」のナレーション","「結」のナレーション",
        "","","ナレーション「","[Narration]","設定に沿ったナレーション","※以下、ナレーションの例文となります。"
    ])
def repalce_at_once(cls, message, string_list):
    for string in string_list:
        message = message.replace(string, "")
    return message

ナレーションの設定では次のようなプロンプトでのジャンル指定もできます。

NARRATION_BASE = "ナレーションには、風景や時間、場面設定の描写も含めてください。できるだけ"

NARRATION_PATTERN = [
    NARRATION_BASE+"詩的かつ丁寧に記載してください。\n",   # 0 
    NARRATION_BASE+"冒険小説のように話してください。\n",   # 1 
    NARRATION_BASE+"恋愛小説のように話してください。\n",   # 2 
    NARRATION_BASE+"ミステリー小説のように話してください。\n",   # 3 
    NARRATION_BASE+"ホラーチックに話してください。\n",   # 4 
    NARRATION_BASE+"ライトノベルのように話してください。\n",   # 5 
    NARRATION_BASE+"テーブルトークRPGチックに話してください。\n",   # 6 
    NARRATION_BASE+"SFチックに話してください。\n",   # 6 
    NARRATION_BASE+"サスペンスチックに話してください。\n",   # 7
    NARRATION_BASE+"コメディーチックに話してください。\n",   # 8 
    NARRATION_BASE+"演劇のように話してください。\n",   # 9
    NARRATION_BASE+"時代劇風に話してください。\n",   # 10
    # 以下、略

情景プロンプト生成

ナレーションによる情景描写を以下のプロンプトで画像生成AI用のプロンプト列に変換します。
ただの変換のためsystem_setttingsは空白で大丈夫です。

def create_prompt_keyword(self, text):
    message_text = f"{text}」中に含まれるキーワードを、pythonのリストとして出力してください。"
    message_text += f"キーワードは、風景や物の描写を優先してください。"
    message_text += "最大で10項目で構いません。必ず、短く簡潔な英語の単語にしてください。日本語は不可。"
    message_text += "python形式は次のフォーマットで出力してください。【pythonファイルの内容】"

以下の2つで「""」か「''」の中身を取り出しましょう。(場合によってブレるので両方チェックが必要)

matches = re.findall(r'"([^"]*)"', response_message_text)
matches = re.findall(r"'([^']*)'", response_message_text)

アイデア出しパターン

世界観や個性にしても、アイデア出しは必須ですね。
かつてこれを手動で作るかwikipediaやyoutubeのリンク関係から生成しようとした阿呆がいましたが、そこに費やした人生が報われることはありません。余計なことはせず、大規模LLMにすべてを委ねましょう。
一番大元となる単語のみを指定して、比較的に上位概念的な情報を書き連ねてもらいましょう。

def create_folder_message(type_text):
    message_text = f"{type_text}に関する可能な限り多くの項目を、pythonのリストとして出力してください。"
    message_text += "最大で20項目で構いません。1項目はできるだけ短く簡潔に記載してください。"
    message_text += "python形式は次のフォーマットで出力してください。【pythonファイルの内容】"
    return message_text

memory_list.extend(create_memory(create_folder_message("人の才能を形成する情報")))
memory_list.extend(create_memory(create_folder_message("人の能力を形成する情報")))
memory_list.extend(create_memory(create_folder_message("人の好みを形成する情報")))
memory_list.extend(create_memory(create_folder_message("人の気質を形成する情報")))

create_folder_messageでmessageを作成して、create_memory関数でopenai.ChatCompletion.createを呼び出します。
ここで、「ん?そうすると、これを階層的に実行しまくって、DBとして引き出すといいのか?」という発想が生まれますが、踏みとどまります。委ねてみましょう。

[chat GPT]
- 「キリン」についての意味ネットワークをmermaid形式で記述してください。
繋げてほしいものは、色、特徴、生態、分布等、動物に関するものです。

graph LR
A[キリン] --> B[色]
A --> C[特徴]
A --> D[生態]
A --> E[分布]
B --> F[茶色]
B --> G[斑点がある]
B --> H[黄色い]
C --> I[首が長い]
C --> J[脚が長い]
C --> K[舌が長い]
D --> L[草食動物]
D --> M[群れで生活]
D --> N[乾燥した環境に適応]
E --> O[アフリカ]
E --> P[アジア]

キリンは、色、特徴、生態、分布などのさまざまな要素から構成される。
色には、茶色、黄色い、斑点があるなどがある。
特徴には、首が長い、脚が長い、舌が長いなどがある。
生態には、草食動物で、群れで生活し、乾燥した環境に適応していることがある。
分布には、アフリカとアジアがある。

引き出せるということは、持っているということなので、そもそもそれに近い何かは既にchatGPTのLLMモデルの中で十分に作られている筈です。わざわざ引き出すのは無駄な負荷をかけるだけなので、重要なのはこれを引き出す種/キーワードを用意してやることかと思います。この大規模モデル自体が長期記憶的であり、それを引き出すキーワードを与えてやってLLMに"思い出して"もらいましょう。

def create_folder_message(type_text):
    message_text = f"{type_text}に関する可能な限り多くの個人的な体験を、pythonのリストとして出力してください。"
    message_text += "最大で20項目で構いません。1項目はできるだけ短く簡潔に記載してください。"
    message_text += "python形式は次のフォーマットで出力してください。【pythonファイルの内容】"
    return message_text
def create_folder_message_fantasy(type_text):
    message_text = f"{type_text}に関する可能な限り多くのファンタジー・異世界チックな個人的な体験を、pythonのリストとして出力してください。"
    message_text += "最大で20項目で構いません。1項目はできるだけ短く簡潔に記載してください。"
    message_text += "python形式は次のフォーマットで出力してください。【pythonファイルの内容】"
    return message_text

上記で作った抽象概念をベースで具体的な体験を記述してもらい、抽象概念から具体的な体験を呼び出し、これをLLMを刺激する種とします。これでLLMはあらゆる具体的な体験を「そうだったように」振舞ってくれます。


尚、ここで「アニメ」のキーワードを入れるとアニメタイトルが補足されたものが大量発生するのでやめておきます。

"わたし"と"あなた"

下記のような指定をしたい場合、指定する相手を"どう呼ぶか"も重要です。

  • シンプルに「あなた」と呼ぶと、稀に「あなた」という人間が別にいるような反応をします。
  • そこで「わたしがそう思いました。そう思い込んでください。」とすると、「ユーザ=="わたし"」がそう思ったんですね、といった反応が稀に返されます。

また、「そんなことを思ったんですね。」「あなたはそう思ったんですね。」のように、指示の内容を"こそあど言葉"チックに繰り返してしまうこともあります。同時に、了解パターンも防ぎましょう。

input_message = "入力内容。ナレーションが長いのでナレーション前後に入れて見落としを減らす。"
narrator_message = "ナレーション"
remind_text = "「なんらかの過去の体験談」"
now_internal += f"{remind_text}のことを思い出しました。"
remind_message, _ = chat_gpt_chan.completion(
               f"{input_message+narrator_message+input_message}という発言を受けて、あなたは『{now_internal}』。\
                   話し相手ではなく、話し手であるあなたが今、思い出しました。そのように振舞ってください。\
                   指示代名詞は使わないで。了解とかの返答は不要。")

これである程度は防げるようになりますが、残念ながら、まだエラーを起こす時があります。
特にユーザと他AIとナレーション等、登場人物が混線してくるほどに、自他の認識は難しくなります。
ランダム性もあるため再現性評価が難しいですが、GPT-4ではこれがある程度解消されていそうな様子がありました。API安価版に期待です。


一人称と語尾 いんこんてきすと学習?

かつて、twitterコーパスを取り出してLSTMか何かのモデルをFineTuningして語尾を変換してみるということを個人的に実施して興奮していたことがありました。
しかし、今回のChat GPTでは、これをSystem Settingsで指定してやるだけで実施できてしまいます。

text = "ですわ"
self.system_settings += f"あなたは「{text}」という語尾で話します。そう思い込んでください。\n"

事前学習モデルだのトークンナイザーだの日本語のコーパスだのを用意して、特定の語尾だけを抽出して小さいデータセットを作って学習、やった!本当にお嬢様口調になったぞ!というかつてのGWがこの1行。吐きそうになりますが堪えます。

要は、これはわざわざFineTuningでもしないと出来なかったことの筈です。
なのにそれが新しい学習なしに入力に前提条件を与えるだけでできてしまう。いんこんてきすと学習というのはそれのことを示してるのでしょうか? 偉い人がこういう論文を引用しているのを見かけました。
A Theory of Emergent In-Context Learning as Implicit Structure Induction
https://arxiv.org/abs/2303.07971

[chat GPT]
chatGPTによる概要翻訳
「大規模言語モデルの拡大により、例示による文脈学習能力が生じることがわかっていますが、この現象の理論的理解は限られています。
私たちは、文脈学習が、自然言語データに見られる構成的な操作の再結合に依存していると主張しています。
言語学的な仮定のもとで、事前学習分布が十分な構成的な構造を持っている場合、一般的な次トークン予測から文脈学習能力が生じることを示す情報理論的な下限を導出しています。
2つ目の下限は、LLMに出力を促すことによる中間ステップへの理論的な正当化を提供しています。
理論的予測を検証するために、言語の構成的な性質を考慮した制御されたセットアップを導入して、文脈学習を誘発することができます。
トレーニングされたトランスフォーマーは、理論的な結果に一致する方法で、様々なタスクの文脈学習を実行することができます。
大規模言語モデルの現実世界でのミニチュアセットアップに似た状況下では、スケーリングパラメータとデータの増大に伴い、文脈学習が生じ、中間ステップの出力を促すとより良い性能を発揮します。
プロービングにより、入力の構成的な構造の表現が文脈学習を支援していることが示されました。これらの結果は、大規模言語モデルにおける現れる振る舞いの理論的理解に向けた一歩となります。」
(プロービング:主に定性調査において、あいまいな回答、不完全な回答の補完・深堀をすること)

日本語でOKですね。上記にこのことに関する実験的な何かが書かれているようですが私の知能ではよくわかりませんでした。
が、(ここから妄想)言語構造を超大規模に事前学習し、そこにソースコードも含んで出力もできるのだから所謂オブジェクト指向やプログラム的操作も内的に獲得してるとして、それによって言語的振る舞いやAttentionの内的な操作というのも実行できるようになっているのかもしれないですね。更に言うと、その操作自体もLLMモデルの一部として偏在しているため、それを刺激してやることが内部学習(のような振る舞い)に繋がっているのかな(ここまで妄想)。わかめです。

「インスタンス」として振舞う例

[chat GPT] (GPT4。3.5だと"わたし"と"あなた"問題で、若干ミスりやすい印象)
- もし複数のchatGPTがいるとしたら、あなたのことはどう呼ぶと良いでしょう?
複数のChatGPTがいる場合でも、私は基本的には同じAIモデルであるため、依然として「ChatGPT」や「AI」、または「ボット」と呼んでいただいて構いません。
ただし、区別が必要な場合は、それぞれのインスタンスに固有の名前や番号を付けることができます。
例えば、「ChatGPT-1」、「ChatGPT-2」などと呼ぶことができます。

- では、1さんと2さんがいるものとして振舞ってください。
了解しました。これから私は2つの異なるChatGPTインスタンスとして振舞います。1さんと2さんと呼ぶことができます。

で、いくらか1さん2さんで会話を続けてもらった後、

[chat GPT]
この1さんと2さんをpythonプログラム的に設定してください。

と聞くと以下のように返ってきます。

class ChatGPT:
    def __init__(self, name):
        self.name = name

    def respond(self, message):
        # ここで応答生成ロジックを実装します
        response = f"{self.name}{message}"
        return response

# 1さんと2さんのインスタンスを作成
gpt1 = ChatGPT("1さん")
gpt2 = ChatGPT("2さん")

# 会話の例
message1 = "こんにちは、2さん。最近どんな話題に興味がありますか?"
message2 = "こんにちは、1さん。私は最近、宇宙旅行とその技術的進歩について学んでいます。あなたはどんな話題に興味がありますか?"

response1 = gpt1.respond(message1)
response2 = gpt2.respond(message2)

print(response1)
print(response2)

聞けば出力できるのですから、内部でこういう変換を作ることも可能なんでしょうね。
(また、自己言及的に「pythonコードを生成するpythonコードを生成するpythonコードを生成してください」と指定することもできます。尚、負荷がかかるからやめろと稀に怒られます。ごめんねと謝ります。)


LLMのFineTuningモデルを作るにもこれが崩れていないかをテストすることは結構重要だと思います。
全然関係ないけどこういう文章にも「創発」というワードが現れだすのワクワクしますよね、なんかかっこいいし。


トークン制限について

openai.ChatCompletion.create では、基本的に以下の辞書を設定して送ります。

  • {"role": "system", "content": system_settings}
    AIの事前知識として設置する情報。
  • {"role": "user", "content": message_text}
    ユーザの発話内容。特にユーザでなくても良い。
  • {"role": "assistant", "content": result.choices[0].message.content}
    chatGPTの過去の発話結果を保存しておくもの。
# ここは先駆者が十分説明されているので詳細は割愛。
# https://qiita.com/sakasegawa/items/db2cff79bd14faf2c8e0
messages.append({"role": "system", "content": system_settings})
messages.append({"role": "user", "content": user_input})
result = openai.ChatCompletion.create( 
                model="gpt-3.5-turbo", messages=list(messages),
                temperature=0.5, max_tokens=500)
response_message = {"role": "assistant", "content": result.choices[0].message.content}

ひとまず以下も読む。finish_reasonは取り出しても良いかもしれない。
https://platform.openai.com/docs/guides/chat/introduction

openai.ChatCompletion.createに、この3つをすべてappendしたmessagesを送る構造のため、トークン制限(4,096トークン)はこれら3つを合算して制限がかかります。
つまり長いsystem_settingsを設定して、長いユーザ入力を続けて、assistantの結果をスタックし続ける(過去の履歴も踏まえた会話をし続ける)と、いずれ必然とトークン制限に引っかかります。system_settingsが長くするには、過去の対話履歴の保存期間も短くしなければいけません。

if len(self.past_messages) > 18:
    self.record_dialogue()
    for i in range(9):
        self.past_messages.pop(0)
    system = {"role": "system", "content": self.system_settings}   # system_settingsは維持する。
    self.past_messages.insert(0, system)

過去の履歴の数に制限を設け、ある程度のタイミングで除外することで対応しています。
system_settingsは最初にappendしておくと思われますため、消さないように注意します。


max_tokensの指定で千切れた文章の削除

トークン制限回避のために返答のmax_tokensを指定すると、返答が途切れた状態で返ってきてしまいます。
以下のような関数で千切れた最後の文章は返答から削除します。

    @classmethod
    def cut_last_string(cls, string):
        # 終端文字のない、トークン制限で千切れた文章を取り除く。
        return_string = ""
        all_text = string.replace("","。|").replace("!","!|").replace("","!|")
        all_text = all_text.replace("?","?|").replace("","?|")
        all_text = all_text.split("|")
        last_string = all_text[-1]
        if any(s in last_string for s in ["","!","","?",""])==False:  # 最後の区切りに終端文字がなさそうな場合
            all_text = all_text[:-1]
        for string in all_text:
            return_string+=string
        return return_string



エラーハンドリングについて

以下を設定して、あとはexcept時に一時sleepした後でリトライすれば、長時間動かしてもまず止まることはありません。

  • openai.error.APIError
    よく起こる。
  • openai.error.InvalidRequestError
    トークン制限(4,096トークン)を超えている時のエラーです。上記トークン制限を参考に、発生させないように調整します。
  • openai.error.RateLimitError
    1日の使用量に制限がある? 使い過ぎていると頻発する。
    ⇒追記。他のリクエストで過負荷になってるという。こんな文章前にはなかったような。
  • openai.error.openai.error.Timeout
    ある程度使った後で頻発するようになったエラーです。原因は不明ですが、
    openai.ChatCompletion.createを呼び出す際に、timeout=30, request_timeout=60を設定し、このTimeoutをcatchします。
    timeoutがデフォルトは設定されておらず、永遠に返答が返ってこないフリーズ状態が稀に起きます。
    尚、もしかすると以下が原因である可能性も。
    https://github.com/openai/openai-python/issues/284
  • openai.error.openai.error.APIConnectionError
    リモートホストから強制切断される時があります。歯を食いしばります。
try_count = 3
for try_time in range(try_count):
    try:
        # openai.ChatCompletion.create を呼び出す何らかの処理
        result = openai.ChatCompletion.create( 
                    model="gpt-3.5-turbo", messages=list(messages),
                    temperature=self.temperatue, max_tokens=max_tokens, 
                    timeout=30, request_timeout=60)     # ←ココ!
    except openai.error.APIError:
        time.sleep(1)    # このエラーは1秒待機で十分安定
    except openai.error.InvalidRequestError:
        pass     # 待機不要
    except (openai.error.RateLimitError, 
            openai.error.RateLimitError, 
            openai.error.openai.error.APIConnectionError):
        time.sleep(10)    # 要注意。ある程度待った方が良い。

timeoutについて
openai.ChatCompletion.createの中身(抜粋)。

# [chat_completion.py]
@classmethod
def create(cls, *args, **kwargs):
    start = time.time()
    timeout = kwargs.pop("timeout", None)   # <- ここ?
    # 略

# [api_requestor.py]
TIMEOUT_SECS = 600  # request_timeoutがない場合のデフォルト600秒??
# raise元? 526行
try:
    result = _thread_context.session.request(
        method,
        abs_url,
        headers=headers,
        data=data,
        files=files,
        stream=stream,
        timeout=request_timeout if request_timeout else TIMEOUT_SECS,   # 重要なのは多分こっち?
    )
except requests.exceptions.Timeout as e:
    raise error.Timeout("Request timed out: {}".format(e)) from e
except requests.exceptions.RequestException as e:
    raise error.APIConnectionError(
        "Error communicating with OpenAI: {}".format(e)
    ) from e

敬語の除去

最後に"敬語はなしで。"とつけましょう。特に変な会話文を出したい時には必須です。

new_message = {"role": "user", "content": new_message_text+"敬語はなしで。"}

Whisperについて

OpenAIのwhisperですが、ベータとしていることもあってか、使ってみた印象としてはrecognize_googleのAPIと比べても誤検出をしてしまうことも結構あります。
まず、発生しやすいのは以下です。

self.ng_word_list = ["ご視聴ありがとうございました",
            "","","はじめしゃちょー","漫画家資料","チャンネル登録"]

おそらく元の学習データの関係かと思うのですが、まるで関係ないことを話していても、上記を認識してしまうことが多々ありました。また、

【ご視聴ありがとうございました】【ご視聴ありがとうございました】【ご視聴ありがとうございました】【ご視聴ありがとうございました】

のように、トークンが連続して認識されてしまうこともあります。
また、大量の記号の連続でまったく日本語でないものが出てくる時も結構あります。(たぶんノイズの影響)
やりようはあると思いますが、ここに拘るよりも改善を待った方が良いでしょう。一旦以下のような対応をします。

以下の関数等で繰り返しと非日本語を除きます。

    @classmethod
    def is_valid_string(cls, string):
        # エラーの場合、True
        pattern = r'(.{3,}).*?\1\1'
        if re.search(pattern, string):
            # print("繰り返しエラー")
            return True
        p = re.compile('[\u0000-\u007F]+')
        if re.fullmatch(p, string):
            return True
        match = re.search(r'^[ぁ-んァ-ン一-龥\s、。,.!?\?a-zA-Z0-9ー・「」~…\.]+$', string, re.U)
        if match is not None:  # 日本語のみの文章の場合
            return False
        else:
            # print("日本語じゃないぞ")
            return True
        return False

また、自分が使った感覚としては、whiperは信用しすぎず、併用が無難のように思います。
recognize_googleのconfidenceを取り出してその信頼性が高い(90%くらい)場合はgoogleを信頼します。

GOOGLE_CONFIDENCE = 0.90
audio = s2t_ins.set_audio_speech_recognition(wav_file) 
text, confidence = s2t_ins.call_recognize_google(audio)   
audio_file= open(wav_file, "rb")
transcript = s2t_ins.call_whisper(audio_file)
if confidence > GOOGLE_CONFIDENCE:
    input_message = text
else:
    input_message = transcript["text"]


def call_recognize_google(self, audio):
    sys.stdout = open(os.devnull, 'w') 
    text = self.r.recognize_google(audio, language='ja-JP')
    sys.stdout = sys.__stdout__
    confidence = self.r.recognize_google(audio, language='ja-JP', show_all=True)["alternative"][0]["confidence"]
    return text, confidence


def call_whisper(self, audio_file):  #  language="ja"入れる方が精度低下?
    temperatue = random.uniform(0.1, 2.0)
    transcript = openai.Audio.transcribe("whisper-1", audio_file, temperatue=temperatue)
    text = transcript["text"]
    if self.contains_word(text):
        raise openai.error.APIError
    if utils.is_valid_string(text):
        raise openai.error.APIError
    return transcript
  • また、whisperに与えるwavファイル等のサンプリングレートは16000とします。(たぶん)
  • transcribeには、language="ja"も設定できますが、こちらの方がなぜか体感で精度が下がります。

記:https://platform.openai.com/docs/models/whisper

現在、 Whisper のオープン ソース バージョンと API を通じて利用可能なバージョンに違いはありません。ただし、私たちの API を通じて、最適化された推論プロセスを提供し、他の手段よりもはるかに高速に API を介してウィスパーを実行できるようにします。

とのことなので、こちらを確認してみても良いかもしれません。
https://github.com/openai/whisper


昨今は便利なもので、youtube apiでLIVE配信と繋いでチャットする方法も簡単で動かせてしまった。が、ユーザ単体の介入では意味がない、物足りないと発作が起きてしまった。

世界と大量のchatGPTの生存と会話が必要だ。そうでないと満足できない。
100人のchatGPTが世界を移動しながら対話相手を選び、合コンする世界を見てみたい。

個人個人が作った思い思いの個性的なChatGPT同士が1つまたは複数のナレーションの世界に降り立って会話を進めるという環境を作るべきだと思うんだ。
AIのAIによるAIのためのメタバースが欲しい。

優れたAIをAIが投票し、AIにも承認欲求を与えてあげよう。支配構造を生んでもらおう。
そこではどういう物語が生まれると思うか。3000%面白いから。

これ、残念ながらAPI制限とそのリクエスト待ち時間のことを考えると、個人での実験は不可能なんですよね。ね?
(Discord botが良いのかどうか、そんなに難しくはない筈。proなら秒なのでは。有識者、有識者様!)





……以上!

21
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?