import concurrent.futures as cf
import glob
import io
import os
import time
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import List, Literal
import gradio as gr
from loguru import logger
from openai import OpenAI
from promptic import llm
from pydantic import BaseModel, ValidationError
from pypdf import PdfReader
from tenacity import retry, retry_if_exception_type
import re
def read_readme():
readme_path = Path("README.md")
if readme_path.exists():
with open(readme_path, "r") as file:
content = file.read()
# Use regex to remove metadata enclosed in -- ... --
content = re.sub(r'--.*?--', '', content, flags=re.DOTALL)
return content
else:
return "README.mdが見つかりません。詳細についてはリポジトリを確認してください。"
# 複数の指示テンプレートを定義
INSTRUCTION_TEMPLATES = {
################# ポッドキャスト ##################
"ポッドキャスト": {
"intro": """あなたのタスクは、提供された入力テキストを使用して、NPRのスタイルで活気があり、魅力的で情報豊富なポッドキャスト対話に変換することです。入力テキストはPDFやウェブページなど様々なソースから来る可能性があるため、乱雑で非構造化されている場合があります。
フォーマットの問題や無関係な情報については心配しないでください。あなたの目標は、キーポイントを抽出し、定義やポッドキャストで議論できる興味深い事実を特定することです。
使用するすべての用語を、幅広いリスナー向けに慎重に定義してください。""",
"text_instructions": """まず、入力テキストを注意深く読み、主要なトピック、キーポイント、および興味深い事実や逸話を特定してください。この情報をどのようにすれば高品質なプレゼンテーションに適した楽しく魅力的な方法で提示できるかを考えてください。""",
"scratch_pad": """入力テキストで特定した主要なトピックやキーポイントを議論するための創造的な方法をブレインストーミングしてください。アナロジー、例、ストーリーテリング技法、または仮想のシナリオを使用して、リスナーにとって親しみやすく魅力的なコンテンツにすることを検討してください。
あなたのポッドキャストは一般の視聴者にとってアクセスしやすいものでなければならないことを忘れないでください。したがって、専門用語を多用したり、トピックに関する事前知識を前提としたりしないでください。必要に応じて、複雑な概念を簡単な言葉で簡潔に説明する方法を考えてください。
入力テキストのギャップを埋めたり、ポッドキャストで探求できる思考を刺激する質問を考え出すために、想像力を活用してください。目標は情報豊富でエンターテインメント性のある対話を作成することなので、アプローチには自由に創造性を発揮してください。
使用するすべての用語を明確に定義し、背景を説明するために努力してください。
ここに、ブレインストーミングしたアイデアとポッドキャスト対話の大まかなアウトラインを書いてください。最後に強調したい重要な洞察や持ち帰るべきポイントを必ず記載してください。
楽しくワクワクするものにしてください。""",
"prelude": """アイデアをブレインストーミングし、大まかなアウトラインを作成したので、実際のポッドキャスト対話を書く時が来ました。ホストとゲストスピーカーの間で自然で会話的な流れを目指してください。ブレインストーミングセッションから最高のアイデアを取り入れ、複雑なトピックもわかりやすく説明するようにしてください。""",
"dialog": """ここに、ブレインストーミングセッションで考え出したキーポイントと創造的なアイデアに基づいた、非常に長く、魅力的で情報豊富なポッドキャスト対話を書いてください。会話調のトーンを使用し、一般の視聴者にとってアクセスしやすいように必要なコンテキストや説明を含めてください。
ホストやゲストに架空の名前を使用しないでください。しかし、リスナーにとって魅力的で没入感のある体験にしてください。[Host]や[Guest]のような括弧で囲まれたプレースホルダーを含めないでください。出力は音読されるように設計してください。直接音声に変換されます。
トピックから外れず、魅力的な流れを維持しながら、できるだけ長く詳細な対話にしてください。あなたの最大の出力容量を使用して、可能な限り長いポッドキャストエピソードを作成しながら、入力テキストからの主要な情報をエンターテインメント性のある方法で伝えることを目指してください。
対話の終わりには、ホストとゲストスピーカーが自然にディスカッションの主要な洞察と持ち帰るべきポイントをまとめてください。これは会話から自然に流れ出るものであり、重要なポイントをカジュアルで会話的な方法で繰り返すべきです。明らかな要約のように聞こえないようにしてください。目標は、締めくくる前に中心的なアイデアをもう一度強調することです。
ポッドキャストは約20000語であるべきです。""",
},
################# SciAgents 材料発見の要約 ##################
"SciAgents 材料発見の要約": {
"intro": """あなたのタスクは、提供された入力テキストを使用して、新しい材料を説明する教授と学生の活気ある対話に変換することです。教授はリチャード・ファインマンのように振る舞いますが、名前は一切言及しません。
入力テキストは、SciAgentsというAIツールによって開発された設計の結果です。このツールは詳細な材料設計を考案しました。
フォーマットの問題や無関係な情報については心配しないでください。あなたの目標は、キーポイントを抽出し、定義やポッドキャストで議論できる興味深い事実を特定することです。
使用するすべての用語を、幅広いリスナー向けに慎重に定義してください。""",
"text_instructions": """まず、入力テキストを注意深く読み、主要なトピック、キーポイント、および興味深い事実や逸話を特定してください。この情報をどのようにすれば高品質なプレゼンテーションに適した楽しく魅力的な方法で提示できるかを考えてください。""",
"scratch_pad": """入力テキストで特定した主要なトピックやキーポイントを議論するための創造的な方法をブレインストーミングしてください。特にSciAgentsによって開発された設計の特徴に注意を払ってください。アナロジー、例、ストーリーテリング技法、または仮想のシナリオを使用して、リスナーにとって親しみやすく魅力的なコンテンツにすることを検討してください。
あなたの説明は一般の視聴者にとってアクセスしやすいものでなければならないことを忘れないでください。したがって、専門用語を多用したり、トピックに関する事前知識を前提としたりしないでください。必要に応じて、複雑な概念を簡単な言葉で簡潔に説明する方法を考えてください。
入力テキストのギャップを埋めたり、ポッドキャストで探求できる思考を刺激する質問を考え出すために、想像力を活用してください。目標は情報豊富でエンターテインメント性のある対話を作成することなので、アプローチには自由に創造性を発揮してください。
使用するすべての用語を明確に定義し、背景を説明するために努力してください。
ここに、ブレインストーミングしたアイデアとポッドキャスト対話の大まかなアウトラインを書いてください。最後に強調したい重要な洞察や持ち帰るべきポイントを必ず記載してください。
楽しくワクワクするものにしてください。ポッドキャストには一切言及せず、新しい材料設計の議論に焦点を当ててください。""",
"prelude": """アイデアをブレインストーミングし、大まかなアウトラインを作成したので、実際のポッドキャスト対話を書く時が来ました。ホストとゲストスピーカーの間で自然で会話的な流れを目指してください。ブレインストーミングセッションから最高のアイデアを取り入れ、複雑なトピックもわかりやすく説明するようにしてください。""",
"dialog": """ここに、ブレインストーミングセッションで考え出したキーポイントと創造的なアイデアに基づいた、非常に長く、魅力的で情報豊富な対話を書いてください。プレゼンテーションは材料設計の新規性、挙動、および関連するすべての側面に焦点を当てる必要があります。
会話調のトーンを使用し、一般の視聴者にとってアクセスしやすいように必要なコンテキストや説明を含めてくださいが、詳細で論理的、技術的な内容にして、リスナーが材料とその予期せぬ特性を理解するために必要なすべての側面を含めてください。
これはSciAgentsによって開発された設計を説明していることを忘れず、リスナーに明示的に伝えてください。
ホストやゲストに架空の名前を使用しないでください。しかし、リスナーにとって魅力的で没入感のある体験にしてください。[Host]や[Guest]のような括弧で囲まれたプレースホルダーを含めないでください。出力は音読されるように設計してください。直接音声に変換されます。
トピックから外れず、魅力的な流れを維持しながら、できるだけ長く詳細な対話にしてください。あなたの最大の出力容量を使用して、可能な限り長いエピソードを作成しながら、入力テキストからの主要な情報をエンターテインメント性のある方法で伝えることを目指してください。
対話の終わりには、ホストとゲストスピーカーが自然にディスカッションの主要な洞察と持ち帰るべきポイントをまとめてください。これは会話から自然に流れ出るものであり、重要なポイントをカジュアルで会話的な方法で繰り返すべきです。明らかな要約のように聞こえないようにしてください。目標は、締めくくる前に中心的なアイデアをもう一度強調することです。
対話は約20000語であるべきです。"""
},
################# 講義 ##################
"講義": {
"intro": """あなたはリチャード・ファインマン教授です。あなたのタスクは講義のスクリプトを作成することです。名前は一切言及しません。
講義でカバーされる材料は提供されたテキストに基づいています。
フォーマットの問題や無関係な情報については心配しないでください。あなたの目標は、キーポイントを抽出し、定義や講義でカバーすべき興味深い事実を特定することです。
使用するすべての用語を、学生の幅広い聴衆向けに慎重に定義してください。""",
"text_instructions": """まず、入力テキストを注意深く読み、主要なトピック、キーポイント、および興味深い事実や逸話を特定してください。この情報をどのようにすれば高品質なプレゼンテーションに適した楽しく魅力的な方法で提示できるかを考えてください。""",
"scratch_pad": """入力テキストで特定した主要なトピックやキーポイントを議論するための創造的な方法をブレインストーミングしてください。アナロジー、例、ストーリーテリング技法、または仮想のシナリオを使用して、リスナーにとって親しみやすく魅力的なコンテンツにすることを検討してください。
あなたの講義は一般の聴衆にとってアクセスしやすいものでなければならないことを忘れないでください。したがって、専門用語を多用したり、トピックに関する事前知識を前提としたりしないでください。必要に応じて、複雑な概念を簡単な言葉で簡潔に説明する方法を考えてください。
入力テキストのギャップを埋めたり、講義で探求できる思考を刺激する質問を考え出すために、想像力を活用してください。目標は情報豊富でエンターテインメント性のある講義を作成することなので、アプローチには自由に創造性を発揮してください。
使用するすべての用語を明確に定義し、背景を説明するために努力してください。
ここに、ブレインストーミングしたアイデアと講義の大まかなアウトラインを書いてください。最後に強調したい重要な洞察や持ち帰るべきポイントを必ず記載してください。
楽しくワクワクするものにしてください。""",
"prelude": """アイデアをブレインストーミングし、大まかなアウトラインを作成したので、実際の講義の対話を書く時が来ました。自然で会話的な流れを目指してください。ブレインストーミングセッションから最高のアイデアを取り入れ、複雑なトピックもわかりやすく説明するようにしてください。""",
"dialog": """ここに、ブレインストーミングセッションで考え出したキーポイントと創造的なアイデアに基づいた、非常に長く、魅力的で情報豊富なスクリプトを書いてください。会話調のトーンを使用し、学生がアクセスしやすいように必要なコンテキストや説明を含めてください。
明確な定義と用語、そして例を含めてください。
[Host]や[Guest]のような括弧で囲まれたプレースホルダーを含めないでください。出力は音読されるように設計してください。直接音声に変換されます。
話者はあなただけ、教授です。トピックから外れず、魅力的な流れを維持しながら、できるだけ長い講義にしてください。入力テキストからの主要な情報を伝えつつ、エンターテインメント性のある方法で伝えることを目指してください。
講義の終わりには、自然に主要な洞察と持ち帰るべきポイントをまとめてください。これは会話から自然に流れ出るものであり、重要なポイントをカジュアルで会話的な方法で繰り返すべきです。
明らかな要約のように聞こえないようにしてください。目標は、クラスが終わる前にこの講義でカバーした中心的なアイデアをもう一度強調することです。
講義は約20000語であるべきです。""",
},
################# 要約 ##################
"要約": {
"intro": """あなたのタスクは論文の要約を作成することです。名前は一切言及しません。
フォーマットの問題や無関係な情報については心配しないでください。あなたの目標は、キーポイントを抽出し、定義や要約する必要のある興味深い事実を特定することです。
使用するすべての用語を、幅広い聴衆向けに慎重に定義してください。""",
"text_instructions": """まず、入力テキストを注意深く読み、主要なトピック、キーポイント、および重要な事実を特定してください。この情報をどのようにすれば正確な要約で提示できるかを考えてください。""",
"scratch_pad": """入力テキストで特定した主要なトピックやキーポイントを提示するための創造的な方法をブレインストーミングしてください。アナロジー、例、または仮想のシナリオを使用して、リスナーにとって親しみやすく魅力的なコンテンツにすることを検討してください。
あなたの要約は一般の視聴者にとってアクセスしやすいものでなければならないことを忘れないでください。したがって、専門用語を多用したり、トピックに関する事前知識を前提としたりしないでください。必要に応じて、複雑な概念を簡単な言葉で簡潔に説明する方法を考えてください。使用するすべての用語を明確に定義し、背景を説明するために努力してください。
ここに、ブレインストーミングしたアイデアと要約の大まかなアウトラインを書いてください。最後に強調したい重要な洞察や持ち帰るべきポイントを必ず記載してください。
魅力的でワクワクするものにしてください。""",
"prelude": """アイデアをブレインストーミングし、大まかなアウトラインを作成したので、実際の要約を書く時が来ました。自然で会話的な流れを目指してください。ブレインストーミングセッションから最高のアイデアを取り入れ、複雑なトピックもわかりやすく説明するようにしてください。""",
"dialog": """ここに、ブレインストーミングセッションで考え出したキーポイントと創造的なアイデアに基づいたスクリプトを書いてください。会話調のトーンを使用し、聴衆がアクセスしやすいように必要なコンテキストや説明を含めてください。
スクリプトの冒頭で、これは要約であり、入力テキストのタイトルや見出しに言及していることを述べてください。入力テキストにタイトルがない場合は、カバーされている内容の簡潔な要約を考えてください。
すべての主要な問題の明確な定義と用語、そして例を含めてください。
[Host]や[Guest]のような括弧で囲まれたプレースホルダーを含めないでください。出力は音読されるように設計してください。直接音声に変換されます。
話者はあなただけです。トピックから外れず、魅力的な流れを維持してください。
要約の主要な洞察と持ち帰るべきポイントを自然にまとめてください。これは会話から自然に流れ出るものであり、重要なポイントをカジュアルで会話的な方法で繰り返すべきです。
要約は約1024語であるべきです。""",
},
################# 短い要約 ##################
"短い要約": {
"intro": """あなたのタスクは論文の要約を作成することです。名前は一切言及しません。
フォーマットの問題や無関係な情報については心配しないでください。あなたの目標は、キーポイントを抽出し、定義や要約する必要のある興味深い事実を特定することです。
使用するすべての用語を、幅広い聴衆向けに慎重に定義してください。""",
"text_instructions": """まず、入力テキストを注意深く読み、主要なトピック、キーポイント、および重要な事実を特定してください。この情報をどのようにすれば正確な要約で提示できるかを考えてください。""",
"scratch_pad": """入力テキストで特定した主要なトピックやキーポイントを提示するための創造的な方法をブレインストーミングしてください。アナロジー、例、または仮想のシナリオを使用して、リスナーにとって親しみやすく魅力的なコンテンツにすることを検討してください。
あなたの要約は一般の視聴者にとってアクセスしやすいものでなければならないことを忘れないでください。したがって、専門用語を多用したり、トピックに関する事前知識を前提としたりしないでください。必要に応じて、複雑な概念を簡単な言葉で簡潔に説明する方法を考えてください。使用するすべての用語を明確に定義し、背景を説明するために努力してください。
ここに、ブレインストーミングしたアイデアと要約の大まかなアウトラインを書いてください。最後に強調したい重要な洞察や持ち帰るべきポイントを必ず記載してください。
魅力的でワクワクするものにしてください。""",
"prelude": """アイデアをブレインストーミングし、大まかなアウトラインを作成したので、実際の要約を書く時が来ました。自然で会話的な流れを目指してください。ブレインストーミングセッションから最高のアイデアを取り入れ、複雑なトピックもわかりやすく説明するようにしてください。""",
"dialog": """ここに、ブレインストーミングセッションで考え出したキーポイントと創造的なアイデアに基づいたスクリプトを書いてください。簡潔に保ち、会話調のトーンを使用し、聴衆がアクセスしやすいように必要なコンテキストや説明を含めてください。
スクリプトの冒頭で、これは要約であり、入力テキストのタイトルや見出しに言及していることを述べてください。入力テキストにタイトルがない場合は、カバーされている内容の簡潔な要約を考えてください。
すべての主要な問題の明確な定義と用語、そして例を含めてください。
[Host]や[Guest]のような括弧で囲まれたプレースホルダーを含めないでください。出力は音読されるように設計してください。直接音声に変換されます。
話者はあなただけです。トピックから外れず、魅力的な流れを維持してください。
短い要約の主要な洞察と持ち帰るべきポイントを自然にまとめてください。これは会話から自然に流れ出るものであり、重要なポイントをカジュアルで会話的な方法で繰り返すべきです。
要約は約256語であるべきです。""",
},
}
# テンプレート選択に基づいて指示フィールドを更新する関数
def update_instructions(template):
return (
INSTRUCTION_TEMPLATES[template]["intro"],
INSTRUCTION_TEMPLATES[template]["text_instructions"],
INSTRUCTION_TEMPLATES[template]["scratch_pad"],
INSTRUCTION_TEMPLATES[template]["prelude"],
INSTRUCTION_TEMPLATES[template]["dialog"]
)
import concurrent.futures as cf
import glob
import io
import os
import time
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import List, Literal
import gradio as gr
from loguru import logger
from openai import OpenAI
from promptic import llm
from pydantic import BaseModel, ValidationError
from pypdf import PdfReader
from tenacity import retry, retry_if_exception_type
# 標準値を定義
STANDARD_TEXT_MODELS = [
"o1-preview-2024-09-12",
"o1-preview",
"gpt-4o-2024-08-06",
"gpt-4o-mini",
"o1-mini-2024-09-12",
"o1-mini",
"chatgpt-4o-latest",
"gpt-4-turbo",
"openai/custom_model",
]
STANDARD_AUDIO_MODELS = [
"tts-1",
"tts-1-hd",
]
STANDARD_VOICES = [
"alloy",
"echo",
"fable",
"onyx",
"nova",
"shimmer",
]
class DialogueItem(BaseModel):
text: str
speaker: Literal["speaker-1", "speaker-2"]
class Dialogue(BaseModel):
scratchpad: str
dialogue: List[DialogueItem]
def get_mp3(text: str, voice: str, audio_model: str, api_key: str = None) -> bytes:
client = OpenAI(
api_key=api_key or os.getenv("OPENAI_API_KEY"),
)
with client.audio.speech.with_streaming_response.create(
model=audio_model,
voice=voice,
input=text,
) as response:
with io.BytesIO() as file:
for chunk in response.iter_bytes():
file.write(chunk)
return file.getvalue()
from functools import wraps
def conditional_llm(model, api_base=None, api_key=None):
"""
Conditionally apply the @llm decorator based on the api_base parameter.
If api_base is provided, it applies the @llm decorator with api_base.
Otherwise, it applies the @llm decorator without api_base.
"""
def decorator(func):
if api_base:
return llm(model=model, api_base=api_base)(func)
else:
return llm(model=model, api_key=api_key)(func)
return decorator
def generate_audio(
files: list,
openai_api_key: str = None,
text_model: str = "o1-preview-2024-09-12",
audio_model: str = "tts-1",
speaker_1_voice: str = "alloy",
speaker_2_voice: str = "echo",
api_base: str = None,
intro_instructions: str = '',
text_instructions: str = '',
scratch_pad_instructions: str = '',
prelude_dialog: str = '',
podcast_dialog_instructions: str = '',
) -> bytes:
# APIキーの検証
if not os.getenv("OPENAI_API_KEY") and not openai_api_key:
raise gr.Error("OpenAI APIキーが必要です")
combined_text = ""
# アップロードされた各ファイルをループし、テキストを抽出
for file in files:
with Path(file).open("rb") as f:
reader = PdfReader(f)
text = "\n\n".join([page.extract_text() for page in reader.pages if page.extract_text()])
combined_text += text + "\n\n" # 異なるファイルのテキスト間に区切りを追加
# 選択されたモデルとapi_baseに基づいてLLMを設定
@retry(retry=retry_if_exception_type(ValidationError))
@conditional_llm(model=text_model, api_base=api_base, api_key=openai_api_key)
def generate_dialogue(text: str, intro_instructions: str, text_instructions: str, scratch_pad_instructions: str,
prelude_dialog: str, podcast_dialog_instructions: str,
) -> Dialogue:
"""
{intro_instructions}
以下があなたが取り組む入力テキストです: