Closed8

マルチモーダルなコンテンツからポッドキャスト風音声を生成する「Podcastfy」を試す

kun432kun432

ここで知った。

https://x.com/rohanpaul_ai/status/1847125283498815603

GitHubレポジトリ

https://github.com/souzatharsis/podcastfy

過去に、似たようなもので、PDF2Audioとかは試したし、

https://zenn.dev/kun432/scraps/9a2bbf3119d3da

PDF2Audioのベースとなっているpdf-to-podcast、個人的にこっちはちょっとforkして修正してたりする

https://github.com/knowsuchagency/pdf-to-podcast

Podcastfyはこれらと何が違うのか?というところで、READMEを読んでみる。

Podcastfy.ai 🎙️🤖

NotebookLMのポッドキャスト機能のオープンソース代替品:GenAIによるマルチモーダルコンテンツを魅力的な多言語音声会話に変換

Podcastfyは、GenAIを使用して、マルチモーダルコンテンツ(テキスト、画像)を魅力的な多言語音声会話に変換するオープンソースのPythonパッケージです。入力コンテンツには、ウェブサイト、PDF、YouTube動画、画像などが含まれます。

主にメモ作成や調査結果の統合に重点を置くUIベースのツール(例えば、NotebookLM ❤️)とは異なり、Podcastfyは、カスタマイズと拡張を可能にする多数のマルチモーダルソースから、魅力的な会話形式のテキストと音声をプログラムで生成することに重点を置いています。

なるほど、まず入力ソースがPDFだけに限らないいろいろなコンテンツに対応している。

機能 ✨

  • 複数のソースやフォーマット(画像、ウェブサイト、YouTube、PDF)から会話形式のコンテンツを生成
  • トランスクリプトとオーディオの生成をカスタマイズ(スタイル、言語、構造、長さなど)
  • 既存の、または編集したトランスクリプトからポッドキャストを作成
  • 高度なテキスト読み上げモデルをサポート(OpenAI、ElevenLabs、Edge)
  • ローカルllmsを実行してトランスクリプトを生成(プライバシーと制御性を向上)
  • 自動化されたワークフローのためのシームレスなCLIとPythonパッケージの統合
  • グローバルなコンテンツ作成のための多言語サポート(実験的!)

TTSも複数から選べるし、「ライブラリ」として利用できるのか。

PDF2Audioやpdf-to-podcastとの違いをまとめるとこう

入力ソース 利用可能なTTS 利用形態
PDF2Audio / pdf-to-podcast PDFのみ(多分) OpenAI アプリ
Podcastfy 画像 / ウェブサイト / YouTube / PDF OpenAI / ElevenLabs / Edge ライブラリ / CLI

個人的には、ライブラリになってるってのが良いなと思う。これならアプリケーション部分は自分で自由に作ることができるので。まあだいぶ尖った用途のライブラリだと思うけども。

READMEには多数デモがあるので見てみると良い。

kun432kun432

Quick Startに従って進める。

https://github.com/souzatharsis/podcastfy/tree/main/podcastfy.ipynb

最初Colaboratoryでやろうと思ったのだが、Podcastfyの要件にPython-3.11以上というのがあって、現時点のColaboratoryではPython-3.10。パッケージインストールに失敗する。

ということで今回はローカルで。自分はmiseで仮想環境を構築したが、ここは適宜。

$ mkdir podcastfy-work && cd podcastfy-work
$ mise use python@3.11
$ cat << 'EOS' >> .mise.toml

[env]
_.python.venv = { path = ".venv", create = true }
EOS
$ mise trust

JupyterLabで作業を進めるので、インストール+起動。

$ pip install jupyterlab ipywidgets
$ jupyter-lab --ip="0.0.0.0" --NotebookApp.token=""

以後の作業はJupyterLab上で。

パッケージインストール。ffmpegのpythonパッケージとかあるんだ、知らなかった。

!pip install ffmpeg podcastfy
!pip freeze | egrep -i "podcastfy|ffmpeg"
ffmpeg==1.4
podcastfy==0.2.6

notebookで再生するためのヘルパー関数を用意

from IPython.display import Audio, display

def embed_audio(audio_file):
	"""
    ノートブックにオーディオファイルを埋め込み、再生可能にする。
	
    引数:
        audio_file (str): オーディオファイルへのパス
	"""
	try:
		display(Audio(audio_file))
		print(f"Audio player embedded for: {audio_file}")
	except Exception as e:
		print(f"Error embedding audio: {str(e)}")

APIキーをセットする。Podcastfyで設定できるLLM/TTSは以下。

https://github.com/souzatharsis/podcastfy/tree/f33a568f207fb1a657d9af38efc283185cfd32b4/usage/config.md

デフォルトだとLLMはGemini、TTSはOpenAIとなる。今回はデフォルトで進める。

import os

os.environ["GEMINI_API_KEY"] = "XXXXXXXXXX"
os.environ["OPENAI_API_KEY"] = "XXXXXXXXXX"

ではコンテンツからオーディオを生成する。コンテンツは画像・PDF・YouTube・Webサイトが指定できる。まずはWebサイトにしてみる。以下のWebサイトを使う。

https://ja.wikipedia.org/wiki/オグリキャップ

generate_podcast関数にURLを渡すとオーディオが生成され、そのパスが返される。

%%time
from podcastfy.client import generate_podcast

audio_file = generate_podcast(
    urls=["https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"]
)

処理が開始される

2024-10-19 00:04:40,775 - podcastfy.client - INFO - Processing 1 links

途中、LangSmith APIのWarningが出るがとりあえず無視して良さそう。

LangSmithMissingAPIKeyWarning: API key must be provided when using hosted LangSmith API

コンテンツから生成されたトランスクリプトも表示されている。

[("Welcome to PODCASTFY - Your Personal Generative AI Podcast. Today, we're diving deep into the captivating story of Oguri Cap, a legendary Japanese racehorse who captured the hearts of millions!", 'Oguri Cap! The "Grey Monster"! What a legend! I'm ready to hear all about him. Where do we even begin with a horse this famous?'), ("Well, his story starts in rural Japan, far from the bright lights of the central racing circuit. He was born on a small farm in Hokkaido, and his early life wasn't exactly glamorous. In fact, he was born with a deformed right foreleg and wasn't expected to amount to much.", "Wow, a deformed leg? That's a tough start for a racehorse. How did he overcome that?"), ('His breeder, Inaba Funanao, saw something special in the foal despite his leg. He named him "Hatsu ratsu," meaning "vigorous," and diligently worked to correct the deformity. Hatsu ratsu, later to be known as Oguri Cap, proved to be a fighter from the start. He had a voracious appetite and an unyielding spirit, quickly growing into a strong and healthy colt.', 'So, he started racing locally, right? Tell me about his early career.'), ('Exactly! He debuted at the笠松, or Kasamatsu, Racecourse in May 1987. He lost his first race, but it was clear he had potential. He went on an eight-race winning streak, dominating local races and earning the nickname "The Grey Monster" for his powerful, ground-covering strides.', "Eight wins in a row! That's incredible! But he wasn't racing against the top horses in Japan yet, was he?"), ("That's right. He was a local hero, but his owner, Oguri Koichi, initially had no intention of sending him to the central racing circuit. He believed Oguri Cap belonged in Kasamatsu. But a persistent horse owner named Sabashi Isuo saw Oguri Cap's true potential and convinced Oguri to sell him the horse.", "That was a turning point, wasn't it? Oguri Cap was finally going to face the best of the best!"), ('It was! In January 1988, Oguri Cap was transferred to the care of trainer Setoguchi Tsutomu at the Ritto Training Center. His central racing debut was in the Pegasus Stakes, and despite his local success, he was only the second favorite. But he silenced any doubters with a stunning come-from-behind victory!', 'I can only imagine the excitement! He was proving he belonged on the big stage. What happened next?'), ('He kept winning! He took the Mainichi Hai, the Kyoto Yonsai Tokubetsu, and the New Zealand Trophy 4-Year-Old Stakes, setting a new race record in the process. He was unstoppable, racking up win after win against top-class competition.', 'He was making history! But there's a "but" coming, isn't there? He couldn't race in the Classics, could he?'), ("You're right. Because he hadn't been registered for the Classics as a foal, he missed out on the Satsuki Sho (Japanese 2000 Guineas) and the Tokyo Yushun (Japanese Derby). It was a huge disappointment for his fans, but he kept proving his worth in other races.", 'He was the "phantom Derby horse," right? What a shame! But he did win his first GI, didn't he?'), ('He did! He faced the reigning Horse of the Year, Tamamo Cross, in the 1988 Arima Kinen. It was a thrilling race, and Oguri Cap, ridden by the legendary jockey Okabe Yukio, emerged victorious, becoming the first grey horse to win the prestigious Arima Kinen!', "What a story! He was a national hero by then, wasn't he? But his career wasn't all smooth sailing, was it?"), ("No, it wasn't. He faced setbacks, injuries, and a grueling race schedule in 1989. He was pushed hard, perhaps too hard, and some questioned whether he was being overused. But he kept fighting, winning the Mainichi Okan for the second year in a row and the Mile Championship in a breathtaking finish.", "He was a true warrior! But his 1990 season was even more dramatic, wasn't it?"), ('It was! He started the year with a brilliant win in the Yasuda Kinen, ridden by the young star jockey Take Yutaka. But injuries plagued him throughout the season, and he suffered disappointing losses in the Takarazuka Kinen, Tenno Sho (Autumn), and Japan Cup. Some even called for his retirement.', 'It must have been heartbreaking for his fans. But then came the 1990 Arima Kinen, right? His final race.'), ("Yes! Despite doubts about his condition, he was entered in the Arima Kinen, with Take Yutaka back in the saddle. He wasn't the favorite, but he ran a brilliant race, taking the lead in the final stretch and holding off challengers to win his second Arima Kinen in a truly emotional victory!", 'What a way to end his career! A true champion! What happened after he retired?'), ('He retired to stud at the <say-as interpret-as="spell-out">Yushun Stallion Station in Hokkaido. He remained a popular attraction, but sadly, he never produced a champion racehorse. In 2010, he suffered a fatal leg fracture and was euthanized at the age of 25.', "That's so sad. But his legacy lives on, doesn't it? He's still remembered as one of the greatest racehorses in Japanese history."), ("Absolutely! Oguri Cap's story is one of resilience, determination, and the power of the human-animal bond. He transcended the sport of horse racing, becoming a symbol of hope and inspiration for millions. He'll never be forgotten.", "What an incredible story! Thanks for sharing it with us. I'm sure our listeners will be captivated by Oguri Cap's journey."), ("Thanks for listening to PODCASTFY! We'll be back soon with another fascinating story. Until then, take care!", 'Bye Bye!')]

以下のように表示されれば完了

2024-10-19 00:07:19,272 - podcastfy.client - INFO - Podcast generated successfully using openai TTS model

最終的なオーディオファイルが生成されるまでにはそこそこに時間がかかったかな。

CPU times: user 800 ms, sys: 660 ms, total: 1.46 s
Wall time: 2min 38s

再生してみる。

embed_audio(audio_file)

生成されたものはこんな感じ

https://youtu.be/vbL58mbGtps

なお、生成されたデータは以下のように出力される。トランスクリプトもファイルとして出力されている。

$ tree data
data
├── audio
│   ├── podcast_69d02eb4b3dd42a5889c631e2dcb9501.mp3
│   └── tmp
└── transcripts
    └── transcript_a8050b059dec4e16b3b6f40d3900ebb4.txt

4 directories, 2 files

トランスクリプトはこんな感じ。

data/transcripts/transcript_a8050b059dec4e16b3b6f40d3900ebb4.txt
<Person1> <prosody rate="1.1">Welcome to PODCASTFY - Your Personal Generative AI Podcast. Today, we're diving deep into the captivating story of Oguri Cap, a legendary Japanese racehorse who captured the hearts of millions!</prosody></Person1>

<Person2> <prosody pitch="+2%">Oguri Cap! The "Grey Monster"! What a legend! I'm ready to hear all about him. Where do we even begin with a horse this famous?</prosody></Person2>

<Person1> <prosody rate="1.05">Well, his story starts in rural Japan, far from the bright lights of the central racing circuit. He was born on a small farm in Hokkaido, and his early life wasn't exactly glamorous. In fact, he was born with a deformed right foreleg and wasn't expected to amount to much.</prosody></Person1>

<Person2> <prosody rate="1.15">Wow, a deformed leg? That's a tough start for a racehorse. How did he overcome that?</prosody></Person2>

<Person1> <prosody rate="1.1">His breeder, Inaba Funanao, saw something special in the foal despite his leg. He named him "Hatsu ratsu," meaning "vigorous," and diligently worked to correct the deformity.  Hatsu ratsu, later to be known as Oguri Cap, proved to be a fighter from the start. He had a voracious appetite and an unyielding spirit, quickly growing into a strong and healthy colt.</prosody></Person1>

<Person2> <prosody pitch="+1%">So, he started racing locally, right? Tell me about his early career.</prosody></Person2>

<Person1> <prosody rate="1.1">Exactly! He debuted at the笠松, or Kasamatsu, Racecourse in May 1987.  He lost his first race, but it was clear he had potential.  He went on an eight-race winning streak, dominating local races and earning the nickname "The Grey Monster" for his powerful, ground-covering strides.</prosody></Person1>

<Person2> <prosody rate="1.15">Eight wins in a row! That's incredible! But he wasn't racing against the top horses in Japan yet, was he?</prosody></Person2>

<Person1> <prosody rate="1.1">That's right. He was a local hero, but his owner, Oguri Koichi, initially had no intention of sending him to the central racing circuit.  He believed Oguri Cap belonged in Kasamatsu.  But a persistent horse owner named Sabashi Isuo saw Oguri Cap's true potential and convinced Oguri to sell him the horse.</prosody></Person1>

<Person2> <prosody rate="1.1">That was a turning point, wasn't it?  Oguri Cap was finally going to face the best of the best!</prosody></Person2>

<Person1> <prosody rate="1.1">It was! In January 1988, Oguri Cap was transferred to the care of trainer Setoguchi Tsutomu at the Ritto Training Center.  His central racing debut was in the <emphasis>Pegasus Stakes</emphasis>, and despite his local success, he was only the second favorite.  But he silenced any doubters with a stunning come-from-behind victory!</prosody></Person1>

<Person2> <prosody rate="1.15">I can only imagine the excitement!  He was proving he belonged on the big stage.  What happened next?</prosody></Person2>

<Person1> <prosody rate="1.1">He kept winning! He took the <emphasis>Mainichi Hai</emphasis>, the <emphasis>Kyoto Yonsai Tokubetsu</emphasis>, and the <emphasis>New Zealand Trophy 4-Year-Old Stakes</emphasis>, setting a new race record in the process.  He was unstoppable, racking up win after win against top-class competition.</prosody></Person1>

<Person2> <prosody rate="1.15">He was making history! But there's a "but" coming, isn't there?  He couldn't race in the Classics, could he?</prosody></Person2>

<Person1> <prosody rate="1.1">You're right. Because he hadn't been registered for the Classics as a foal, he missed out on the <emphasis>Satsuki Sho</emphasis> (Japanese 2000 Guineas) and the <emphasis>Tokyo Yushun</emphasis> (Japanese Derby).  It was a huge disappointment for his fans, but he kept proving his worth in other races.</prosody></Person1>

<Person2> <prosody rate="1.15">He was the "phantom Derby horse," right?  What a shame!  But he did win his first GI, didn't he?</prosody></Person2>

<Person1> <prosody rate="1.1">He did! He faced the reigning Horse of the Year, <emphasis>Tamamo Cross</emphasis>, in the <emphasis>1988 Arima Kinen</emphasis>.  It was a thrilling race, and Oguri Cap, ridden by the legendary jockey Okabe Yukio, emerged victorious, becoming the first grey horse to win the prestigious Arima Kinen!</prosody></Person1>

<Person2> <prosody rate="1.15">What a story!  He was a national hero by then, wasn't he?  But his career wasn't all smooth sailing, was it?</prosody></Person2>

<Person1> <prosody rate="1.1">No, it wasn't.  He faced setbacks, injuries, and a grueling race schedule in 1989.  He was pushed hard, perhaps too hard, and some questioned whether he was being overused.  But he kept fighting, winning the <emphasis>Mainichi Okan</emphasis> for the second year in a row and the <emphasis>Mile Championship</emphasis> in a breathtaking finish.</prosody></Person1>

<Person2> <prosody rate="1.15">He was a true warrior!  But his 1990 season was even more dramatic, wasn't it?</prosody></Person2>

<Person1> <prosody rate="1.1">It was! He started the year with a brilliant win in the <emphasis>Yasuda Kinen</emphasis>, ridden by the young star jockey Take Yutaka.  But injuries plagued him throughout the season, and he suffered disappointing losses in the <emphasis>Takarazuka Kinen</emphasis>, <emphasis>Tenno Sho (Autumn)</emphasis>, and <emphasis>Japan Cup</emphasis>.  Some even called for his retirement.</prosody></Person2>

<Person2> <prosody rate="1.15">It must have been heartbreaking for his fans.  But then came the 1990 Arima Kinen, right?  His final race.</prosody></Person2>

<Person1> <prosody rate="1.1">Yes! Despite doubts about his condition, he was entered in the Arima Kinen, with Take Yutaka back in the saddle.  He wasn't the favorite, but he ran a brilliant race, taking the lead in the final stretch and holding off challengers to win his second Arima Kinen in a truly emotional victory!</prosody></Person1>

<Person2> <prosody rate="1.15">What a way to end his career!  A true champion!  What happened after he retired?</prosody></Person2>

<Person1> <prosody rate="1.1">He retired to stud at the <say-as interpret-as="spell-out">Yushun Stallion Station</say-as> in Hokkaido.  He remained a popular attraction, but sadly, he never produced a champion racehorse.  In 2010, he suffered a fatal leg fracture and was euthanized at the age of 25.</prosody></Person1>

<Person2> <prosody rate="1.15">That's so sad.  But his legacy lives on, doesn't it?  He's still remembered as one of the greatest racehorses in Japanese history.</prosody></Person2>

<Person1> <prosody rate="1.1">Absolutely! Oguri Cap's story is one of resilience, determination, and the power of the human-animal bond.  He transcended the sport of horse racing, becoming a symbol of hope and inspiration for millions.  He'll never be forgotten.</prosody></Person1>

<Person2> <prosody rate="1.15">What an incredible story!  Thanks for sharing it with us.  I'm sure our listeners will be captivated by Oguri Cap's journey.</prosody></Person2>

<Person1> <prosody rate="1.1">Thanks for listening to PODCASTFY!  We'll be back soon with another fascinating story.  Until then, take care!</prosody></Person1>

SSMLっぽい感があるけど、これってOpenAI TTSで認識できるのかな?単にトランスクリプトとしてしゅつ

音声もトランスクリプトも英語になっているので、少しカスタマイズして日本語で出力させてみる。おまけでTTSをElevenLabsに変更。ElevenLabsのAPIキーもセットしておく。

from podcastfy.client import generate_podcast

os.environ["ELEVENLABS_API_KEY"] = "XXXXXXXXXX"

audio_file_elevenlabs = generate_podcast(
    urls=["https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"],
    conversation_config={
        "output_language": "Japanese",
    },
    tts_model="elevenlabs",
)

embed_audio(audio_file_elevenlabs)

こんな感じになる。

https://youtu.be/VUd6ZCVq_Ds

OpenAI TTSとはまた雰囲気が変わるね。ちょいちょい発話ミスがあるけど、ElevenLabsもマルチリンガルには対応しているようなので、恐らく中で使用されているTTSのモデルがマルチリンガルのものではないのだろうと推測。READMEにも以下とあるし。

グローバルなコンテンツ作成のための多言語サポート(実験的!)

conversation_configはいろんな設定があるようなので、あとで細かく見ていくので、一旦はとりあえず日本語の設定だけ有効にして以降は進める。

kun432kun432

generate_podcastは複数のコンテンツを入力とすることができる。

from podcastfy.client import generate_podcast

audio_file_multiple_input = generate_podcast(
    urls = [
    	"https://github.com/souzatharsis/podcastfy/blob/main/README.md",
    	"https://www.youtube.com/watch?v=jx2imp33glc"
    ],
    conversation_config={
        "output_language": "Japanese",
    },
)

embed_audio(audio_file_multiple_input)

上記の例では、

  • podcastfyのREADME
  • GoogleのNotebookLMに関するCNBCのニュースのYouTube動画(これは果たしていいんだろうか?)

からオーディオを生成している。ちょっと著作権的にどうなのかな?という気もするので、実際に生成されたものは公開しないけど、結果としては、コンテンツの内容はYouTube動画の内容だけに限定されたものになっていた。この点についてはノートブックのコメントにも記載されている。

しかし、この特定のトランスクリプトは、YouTube動画のみに焦点を当てた私のPodcastifyのコンテンツをピックアップしませんでした。これは、AI-Podcastホストが、提供されたソースの1つから特定のコンセプトをピックアップし、そのコンセプトを中心に会話を展開することがあるためです。AI-Podcastホストが、提供された入力ソース間のコンテンツのカバー範囲のバランスをうまく取るように導くには、改善の余地があります。

ということでこれについてはそのうち改善されるかもしれない。

音声は不要でトランスクリプトだけを出力することもできる。transcript_only=Trueを付与する。

from podcastfy.client import generate_podcast

transcript_file = generate_podcast(
    urls=["https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"],
    transcript_only=True,
    conversation_config={
        "output_language": "Japanese",
    },   
)

ノートブックだとトランスクリプトファイルのパスが返されるように書いてあるのだけど、試してみた限り何も返ってこなかった。直接ディレクトリを見ると出力されているのでそちらを直接確認。

$ head  data/transcripts/transcript_d0e040bd6c484f209a4667c485ce4478.txt
<Person1> <prosody rate="1.1" pitch="+2st"> 皆さん、こんにちは!PODCASTFYへようこそ - あなただけの生成AIポッドキャストです!</prosody> <prosody rate="1.05">今日は、競馬界の伝説、オグリキャップについて語り合いたいと思います!</prosody></Person1>
<Person2> <prosody rate="1.1">オグリキャップ! 芦毛の怪物! 競馬ファンなら誰でも知っている名馬ですよね!</prosody></Person2>
<Person1> <prosody rate="1.05">まさに! 地方競馬から中央競馬へ移籍し、数々の伝説を残した、まさにシンデレラボーイ!</prosody> <prosody rate="1.1">今日は、彼の生い立ちから、輝かしい成績、そして引退後まで、じっくりと掘り下げていきましょう!</prosody></Person2>
<Person2> <prosody rate="1.1">ワクワクしますね! まずは、オグリキャップの誕生から教えてください!</prosody></Person2>
<Person1> <prosody rate="1.05">オグリキャップは1985年3月27日、北海道の稲葉牧場で生まれました。 実は、生まれた時は右前脚が外向していて、なかなか立ち上がれなかったんです。</prosody></Person1>
<Person2> <prosody rate="1.1">ええっ!? そうなんですか? そんなハンデを乗り越えて、名馬になったんですね!</prosody></Person2>
<Person1> <prosody rate="1.05">そうなんです! 牧場の方の懸命な世話と、オグリキャップ自身の生命力で、見事に克服したんです。 そして、笠松競馬場でデビュー!</prosody></Person1>
<Person2> <prosody rate="1.05">笠松競馬場! 地方競馬からのスタートだったんですね!</prosody></Person2>
<Person1> <prosody rate="1.1">そう! デビュー戦は惜しくも2着でしたが、その後は連戦連勝! 重賞も次々と制覇し、笠松競馬のスターダムにのし上がりました!</prosody></Person1>
<Person2> <prosody rate="1.1">まさに、地方競馬のヒーロー! そこから、中央競馬へ移籍したんですね!</prosody></Person2>

でこの生成されたトランスクリプトからオーディオを生成することもできる。conversation_configの設定は一応トランスクリプト化&オーディオ化の両方に関連するとコメントにはあるが、自分が試した限り、トランスクリプトからオーディオ生成する場合は付与してもしなくてもあまり変わらなかった。

from podcastfy.client import generate_podcast

audio_from_transcript = generate_podcast(
	transcript_file="data/transcripts/transcript_d0e040bd6c484f209a4667c485ce4478.txt"
)

embed_audio(audio_from_transcript)

https://youtu.be/WMhWZ7kPeG4

ローカルのPDFファイルを指定することもできる。今回は神戸市が公開している観光に関する統計・調査資料のうち、「令和5年度 神戸市観光動向調査結果について」のPDFを元にポッドキャスト音声を生成してみる。

(出典)
神戸市Webサイトの「観光に関する統計・調査」のページ
https://www.city.kobe.lg.jp/a64051/shise/toke/sightseeing.html

上記にある「令和5年度 神戸市観光動向調査結果について」のPDF
https://www.city.kobe.lg.jp/documents/15123/r5_doukou.pdf

from podcastfy.client import generate_podcast

audio_from_local_pdf = generate_podcast(
    urls=["./r5_doukou.pdf"],
    conversation_config={
        "output_language": "Japanese",
    },   
)

embed_audio(audio_from_local_pdf)

こんな感じで生成された。

<Person1>
<prosody rate="110%" pitch="high">やあ、PODCASTFYへようこそ! みんなの大好きな、神戸市の観光動向調査の結果が出たぞ!</prosody>
</Person1>

<Person2>
<prosody rate="105%">おお、あれか!毎年結構詳しく出てるやつですよね。 今年はどんな感じだったんですか?</prosody>
</Person2>

<Person1>
<prosody rate="110%"> まずは全体的な傾向から! 令和5年度の調査では、神戸を訪れた人はなんと <emphasis>6,250人</emphasis> もいたんだって!</prosody>
</Person2>

<Person2>
<prosody rate="105%"><emphasis>6,250人</emphasis>!? すごい数ですね...! どこでそんなに調査したんですか?</prosody>
</Person2>

<Person1>
<prosody rate="110%"> <emphasis>北野</emphasis><emphasis>南京町</emphasis> みたいな定番スポットはもちろん、<emphasis>IKEA神戸</emphasis> とか <emphasis>神戸三田プレミアム・アウトレット</emphasis> といったところまで、30箇所以上も調査地点があったみたいだよ!</prosody>
</Person2>

<Person2>
<prosody rate="105%">へえ〜。 そんなに色々な場所で調査してたんですね! どんな人が神戸に訪れてるか、気になります!</prosody>
</Person2>

<Person1>
<prosody rate="110%"> 年齢層でいうと、<emphasis>60歳以上</emphasis> の方が一番多かったみたい。 でも、<emphasis>須磨・舞子</emphasis>だと特にその傾向が強くて、<emphasis>60歳以上</emphasis>が3割強もいたんだって!</prosody>
</Person2>

<Person2>
<prosody rate="105%">なるほど〜。 <emphasis>須磨・舞子</emphasis>は、落ち着いた雰囲気が年配の方に人気なのかな?</prosody>
</Person2>

<Person1>
<prosody rate="110%"> そうかもね! あと、居住地だけど、やっぱり<emphasis>近畿</emphasis> からの人が多かったみたい。だけど、<emphasis>北野</emphasis>だけは別格で、なんと<emphasis>半数</emphasis>近くが<emphasis>近畿以外</emphasis>からの観光客だったんだ!</prosody>
</Person2>

<Person2>
<prosody rate="105%">えー! <emphasis>北野</emphasis>ってそんなに人気なんですね! 異国情緒あふれる街並みは、県外の人にとっても魅力的ってことかな?</prosody>
</Person2>

<Person1>
<prosody rate="110%">間違いないね!</prosody>
</Person1>

次に画像から生成することもできる。この場合はurlsではなく、image_pathsでローカルの画像パスを指定する。

今回は、国立国会図書館の蔵書から著作権が切れたものを公開している「NDLイメージバンク」の画像を使わせてもらう。(NDLイメージバンクの利用規約はこちら

https://ndlsearch.ndl.go.jp/imagebank

以下の2つの画像を使う。


出典:国立国会図書館「NDLイメージバンク」
出典: 広重,豊国『江戸自慢三十六興 海案寺紅葉』,平のや. 国立国会図書館デジタルコレクション https://dl.ndl.go.jp/pid/1305746 (参照 2024-10-20)


出典:国立国会図書館「NDLイメージバンク」
出典: 広重『瀬戸秋月』. 国立国会図書館デジタルコレクション https://dl.ndl.go.jp/pid/1305451 (参照 2024-10-20)

from podcastfy.client import generate_podcast

image_paths = [
    "kaianji_momiji.jpg",
    "seto_no_shugetsu.jpg",
]

audio_file_from_images = generate_podcast(
    image_paths=image_paths,
    conversation_config={
        "output_language": "Japanese",
    }
)

embed_audio(audio_file_from_images)

音声はちょっと割愛で、こんな感じのトランスクリプトになる。

<Person1> <prosody rate="105%" pitch="medium"> 皆さん、こんにちは!PODCASTFYへようこそ - あなただけの生成AIポッドキャストです! </prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high"> わあ、今日のテーマは何ですか?わくわくしますね! </prosody> </Person2>
<Person1> <prosody rate="105%" pitch="medium">今日は、日本の伝統的な芸術、浮世絵について話しましょう。特に、風景画と人物画の魅力に迫ります!</prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high">いいですね!浮世絵って、鮮やかな色使いと独特な構図が印象的ですよね。風景画と人物画、どんな違いがあるんでしょう?</prosody> </Person2>
<Person1> <prosody rate="105%" pitch="medium"> ええ、まず風景画ですが、自然の美しさ、それから当時の日本の風景や生活の様子を生き生きと描いていますね。例えば、有名な葛飾北斎の富嶽三十六景!雄大な富士山と、その周りで暮らす人々の日常が、見事に融合されているでしょう? </prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high"> ああ、わかります!あの波の絵は、迫力満点ですよね!でも、風景画って、なんだか静かで落ち着いた雰囲気のものが多い気がしますけど…? </prosody> </Person2>
<Person1> <prosody rate="105%" pitch="medium"> ああ、確かに。でも、例えば歌川広重の東海道五十三次なんかは、旅の情景を通して、当時の賑わいとか、人々の活気が伝わってきませんか? </prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high"> なるほど…言われてみれば、旅人が行き交う様子とか、宿場町の活気とか、見ていて飽きないですよね。 </prosody> </Person1>
<Person1> <prosody rate="105%" pitch="medium"> そうでしょう?一方、人物画は、当時の粋な人々、特に遊女や歌舞伎役 actors 俳優などを生き生きと描いています。喜怒哀楽、人間の様々な感情が、表情や仕草で表現されていて、見ている私たちも引き込まれますよね。 </prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high"> ああ、美人画とか、役者絵は、本当に美しいですよね!着物の柄とか、髪型とか、細かいところまで描かれていて、当時の文化が垣間見えるのも面白いですね。 </prosody> </Person2>
<Person1> <prosody rate="105%" pitch="medium"> ええ、まさに!人物画を通して、当時のファッションや流行、そして美意識まで感じ取ることができますね。 </prosody> </Person1>
<Person2> <prosody rate="100%" pitch="high"> 風景画と人物画、どちらも奥が深いですね!もっと色々な作品を見てみたくなりました! </prosody> </Person2>
<Person1> <prosody rate="105%" pitch="medium"> そうですね!美術館や浮世絵の展覧会もたくさん開催されているので、ぜひ足を運んでみてください!  さて、今日はこの辺で。PODCASTFYを聞いてくれてありがとう!また次回! </prosody> </Person1>

流石に画像の詳細な内容までは解釈できてないように思える。

kun432kun432

でカスタマイズについて。conversation_configでコンテンツからどういうトランスクリプトおよび音声データを生成するか?について設定ができる。以下にまとまっている。

https://github.com/souzatharsis/podcastfy/tree/f33a568f207fb1a657d9af38efc283185cfd32b4//usage/conversation_custom.md

パラメータ デフォルト値 説明
word_count 2000 int 生成されたコンテンツのターゲットとなる単語数
conversation_style ["engaging","fast-paced","enthusiastic"] list[str] 会話に適用するスタイル
roles_person1 "main summarizer" str 最初のスピーカーの役割
roles_person2 "questioner/clarifier" str 2番目のスピーカーの役割
dialogue_structure ["Introduction", "Main Content Summary", "Conclusion"] list[str] 会話の構成
podcast_name "PODCASTFY" str ポッドキャストの名称
podcast_tagline "YOUR PERSONAL GenAI PODCAST" str ポッドキャストのキャッチフレーズ
output_language "English" str 出力の言語
engagement_techniques ["rhetorical questions", "anecdotes", "analogies", "humor"] list[str] リスナーを引き付けるテクニック
creativity 0 int 創造性のレベル/温度 (0-1)

例えばこんな風に設定する。

from podcastfy.client import generate_podcast

custom_config = {
    # 大きくするとより深い議論になる
    "word_count": 4000,
    # 会話のスタイル。今回は「熱狂的」・「カジュアル」・「分析的」。
    "conversation_style": ["enthusiastic", "casual", "analytical"],
    # スピーカー1の役割。今回は競馬ロマンチスト
    "roles_person1": "horse racing romanticist",
    # スピーカー2の役割。今回は競馬アナリスト
    "roles_person2": "horse racing analyst",
    # ポッドキャストの構成。今回は「導入」「紹介する馬の概要」「紹介する馬の強み」「紹介する馬の弱み」「聴衆からの質問」「締め」
    "dialogue_structure": [
        "Introduction",
        "Overview of the horse",
        "Strong point of the horse",
        "Weak point of the horse",
        "Audience Questions",
        "Closing Remarks"
    ],
    # ポッドキャスト名
    "podcast_name": "日本の名馬ポッドキャスト",
    # ポッドキャストのキャッチフレーズ
    "podcast_tagline": "日本の素晴らしい名馬を1頭ピックアップして深堀りしていきます。",
    # トランスクリプト・音声の出力言語
    "output_language": "Japanese",
    # リスナーへのテクニック。今回は「ドラマティック」「統計的」・「リスナーへの問いかけ」
    "engagement_techniques": ["dramatic", "statistical", "audience prompts"],
    # 小さくするとより事実性に基づいたコンテンツになる
    "creativity": 0.3  
}

race_horse_podcast = generate_podcast(
    urls=["https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"],
    conversation_config=custom_config,
    tts_model="openai"
)

embed_audio(race_horse_podcast)

作成されたトランスクリプト

<Person1> <prosody rate="90%" pitch="medium"> いらっしゃいませ! 日本の名馬ポッドキャスト  - 日本の素晴らしい名馬を1頭ピックアップして深堀りしていきます。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> 今回の主役は、競馬ファンなら誰もが知るあの名馬ですよ! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> そうですね!競馬ブームを牽引した、芦毛の怪物、オグリキャップ! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> オグリキャップは、地方競馬から中央競馬へ移籍し、GI4勝を含む輝かしい成績を残した、まさに伝説の馬です。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> 地方競馬出身という異色の経歴でありながら、中央競馬のエリート馬たちを相手に数々の激闘を繰り広げ、多くのファンを魅了しました。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> 今日は、オグリキャップの生涯を辿りながら、その強さの秘密、そして彼が巻き起こした競馬ブームについて、じっくり語っていきましょう! </prosody> </Person2>
<Person1> <prosody rate="90%" pitch="medium"> まずは、オグリキャップの生い立ちから見ていきましょうか。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> オグリキャップは1985年3月27日、北海道の稲葉牧場で生まれました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> 生まれた時は右前脚が外向していて、なかなか立ち上がれなかったそうですね。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> ええ、競走馬としては大きなハンデキャップでした。牧場の人は、無事に育ってほしいという願いを込めて、「ハツラツ」という幼名をつけて愛情深く育てたそうです。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> ハツラツは、母馬の乳の出が悪く、最初は痩せこけていたそうですが、食欲旺盛で、やがて立派な馬体に成長したんですね。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> そうなんです。そして、1987年5月、岐阜県の笠松競馬場でデビューしました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> デビュー戦は2着に敗れましたが、その後は連戦連勝! 地方競馬では12戦10勝という素晴らしい成績を残しました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> 特に、重賞5連勝を達成したあたりから、「笠松にすごい馬がいる!」と、中央競馬の関係者の間でも話題になったそうですね。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> ええ、そして1988年1月、ついに中央競馬へ移籍することになりました。 </prosody> </Person2>
<Person1> <prosody rate="90%" pitch="medium"> 中央競馬での活躍は、本当にすごかったですね! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> まずは移籍初戦のペガサスステークスを快勝! 続く毎日杯も制し、クラシック戦線への期待が高まりました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> ところが、オグリキャップは地方競馬時代にクラシック登録をしていなかったため、皐月賞やダービーに出走することができなかったんです。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> ああ、なんとも惜しい! しかし、オグリキャップは、いわゆる「幻のダービー馬」として、ファンの間でさらに注目を集めることになりました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> そして、ダービーの代わりに、ニュージーランドトロフィー4歳ステークスに出走し、レコードタイムで圧勝! 続く高松宮杯も制し、中央競馬移籍後、重賞5連勝を達成しました。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> 地方競馬出身馬による重賞5連勝は、当時の新記録でしたね! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> オグリキャップは、まさに破竹の勢いでした! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> しかし、その快進撃も、天皇賞(秋)でついにストップ。当時、無敵を誇っていたタマモクロスに敗れてしまいました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> ああ、あのレースは本当に惜しかった! オグリキャップは、上がり3ハロン33秒8の末脚で追い込んだんですが、タマモクロスを捕らえることはできませんでした。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> それでも、4歳馬が天皇賞で連対したのは、オグリキャップが初めてだったんですよ。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> なるほど、そうだったんですね。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> 続くジャパンカップでも、オグリキャップはタマモクロスに敗れ、3着に終わりました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> しかし、オグリキャップは、年末の有馬記念で、ついにGI初制覇を達成するんです! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> そう! しかも、相手は、あのタマモクロス! オグリキャップは、最後の直線でタマモクロスを差し切り、見事リベンジを果たしました! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> あのレースは、本当に感動的でした! オグリキャップは、まさに「芦毛の怪物」の名にふさわしい、強さを見せてくれました! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> そして、オグリキャップは、1988年度のJRA賞最優秀4歳牡馬に選出されました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> 地方競馬出身馬が最優秀4歳牡馬に選ばれるのは、史上初の快挙でしたね! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> オグリキャップは、まさにシンデレラボーイ! 彼の活躍は、多くのファンに夢と希望を与えてくれました! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> さて、オグリキャップの中央競馬での活躍はまだまだ続きます。1989年は、怪我で春シーズンを棒に振ってしまいましたが、秋に復帰し、オールカマーを快勝! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> そこから、毎日王冠、天皇賞(秋)、マイルチャンピオンシップ、ジャパンカップ、有馬記念と、怒涛の6連戦! </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> 毎日王冠では、イナリワンとの激闘をハナ差で制し、史上初の連覇を達成! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> あのレースは、「オグリキャップのベストバトル」とも呼ばれる名勝負でしたね! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> 続く天皇賞(秋)では、スーパークリークに敗れましたが、マイルチャンピオンシップでは、驚異的な末脚でバンブーメモリーを差し切り、GI2勝目を挙げました! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> そして、なんと、翌週のジャパンカップにも出走! 世界レコードで走破したものの、ホーリックスに惜敗。2着に終わりました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> あの連闘は、本当にすごかった! オグリキャップのタフネスぶりには、ただただ驚かされるばかりです。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> しかし、さすがに疲れが出たのか、年末の有馬記念では5着に敗れてしまいました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> それでも、オグリキャップは、1989年も、多くのファンを熱狂させる走りを見せてくれました! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> そして、1990年、オグリキャップは、6歳にして現役続行! 春は、武豊騎手を鞍上に迎え、安田記念に出走しました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> オグリキャップと武豊騎手のコンビ! 当時、大きな話題になりましたね! </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> ええ、そして、その安田記念を、オグリキャップは見事レコード勝ち! 武豊騎手とのコンビで、最高のスタートを切りました! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> しかし、続く宝塚記念では2着に敗れ、その後、脚部不安のため、長期休養を余儀なくされました。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> オグリキャップは、秋に復帰しましたが、天皇賞(秋)、ジャパンカップと、精彩を欠くレースが続きました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> ああ、あの頃は、「オグリキャップも、もう終わりか…」と、多くのファンが心配していましたね。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> しかし、オグリキャップは、そんなファンの心配をよそに、引退レースとして出走した有馬記念で、奇跡の復活劇を演じるんです! </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> そう! オグリキャップは、最後の直線で、メジロライアン、ホワイトストーンとの壮絶な叩き合いを制し、見事優勝! 2年前の有馬記念に続く、2度目の栄冠を手にしました! </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> あのレースは、まさに「奇跡のラストラン」! オグリキャップは、最後まで、ファンの期待に応える、素晴らしい走りを見せてくれました! </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> オグリキャップは、この有馬記念を最後に、競走馬を引退しました。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> そして、1991年、京都競馬場、笠松競馬場、東京競馬場で、盛大な引退式が行われました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> どの競馬場も、オグリキャップを一目見ようと、たくさんのファンが詰めかけましたね。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> オグリキャップは、多くのファンに愛され、惜しまれながら、ターフを去っていきました。 </prosody> </Person2>
<Person1> <prosody rate="95%" pitch="medium"> オグリキャップは、その後、種牡馬となりましたが、残念ながら、中央競馬の重賞優勝馬を出すことはできませんでした。 </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> それでも、オグリキャップは、多くのファンに夢と感動を与えてくれた、日本競馬史に残る名馬です。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> オグリキャップの活躍は、これからも、語り継がれていくことでしょう。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> ええ、オグリキャップは、永遠のヒーローです! </prosody> </Person2>
<Person1> <prosody rate="90%" pitch="medium"> 今回は、オグリキャップについて、じっくりと語ってきましたが、いかがでしたでしょうか? </prosody> </Person1>
<Person2> <prosody rate="105%" pitch="high"> オグリキャップの強さ、そして彼が巻き起こした競馬ブームについて、改めて実感することができました。 </prosody> </Person2>
<Person1> <prosody rate="100%" pitch="medium"> また、次の機会に、別の名馬を取り上げて、その魅力に迫りたいと思います。 </prosody> </Person1>
<Person2> <prosody rate="110%" pitch="high"> それでは、次回の放送もお楽しみに! </prosody> </Person2>
<Person1> <prosody rate="90%" pitch="medium"> 日本の名馬ポッドキャスト、ご清聴ありがとうございました! さようなら! </prosody> </Person1>

https://youtu.be/51DZG266nlg

トランスクリプトはいい感じになってるように思えるが、これまでにもちょいちょいあったけど、生成されたオーディオファイルは発話がおかしいものがちらほらある。

例えば、わかりやすいところでいうと、「競馬」を「きょうば」と発音している。

今回の主役は、競馬ファンなら誰もが知るあの名馬ですよ!

これOpenAIのPlaygroundで試したところ、tts-1-hdだとダメでtts-1だと問題なく発話される

オグリキャップは、地方競馬から中央競馬へ移籍し、GI4勝を含む輝かしい成績を残した、まさに伝説の馬です。

についても「まさに伝説の馬です。」より前の部分の発話が完全に破綻しているのだが、この部分は残念ながらPlaygroundでは再現できなかった。

実際に送信している箇所を追いかけてみると生成されたトランスクリプトからSSMLタグ部分を取り除いて送信しているようで、そのデータ部分がおかしくなっているのかなと思って、トランスクリプトから音声を生成し直してみたら改善されたりしたけど、別の箇所で今度はおかしくなったり。このあたりはTTSモデルの制約なのかもしれない。

podcastfyのデフォルトだとtts-1-hdなので設定を変更するとよいのかもしれない、と思って色々見てみた感じだと、以下のように設定する感じになるっぽい・・・のだが、設定しても変わらなかった。このあたりはちょっとよくわからない。

from podcastfy.client import generate_podcast

audio_file = generate_podcast(
    urls=["https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%B0%E3%83%AA%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97"],
    tts_model="openai",
    conversation_config={
        "output_language": "Japanese",
        "text_to_speech": {
            "default_tts_model": "openai",
            "openai": {
                "default_voices": {
                    "question": "alloy",
                    "answer": "nova"
                },
                "model": "tts-1"
            },
        },
    },   
)

なお、カスタムな設定については以下の注意書きがある。

https://github.com/souzatharsis/podcastfy/blob/f33a568f207fb1a657d9af38efc283185cfd32b4//usage/conversation_custom.md#notes-of-caution

  • word_countは目標であり、AIは指定された単語数よりも多くまたは少なく生成する場合があります。単語数が少ないと高度な議論が生成されやすく、単語数が多いと詳細な議論が生成されやすくなります。
  • output_language は、文字起こしの言語と音声の言語の両方を定義します。関連情報として、以下のものがあります。
    • 結論から言うと、英語以外の文字起こしは十分可能ですが、英語以外の音声は現在開発中です。
    • 文字起こしは、デフォルトで100以上の言語をサポートするGoogleのGemini 1.5 Proを使用して生成されます。
    • 音声は、openai(デフォルト)、elevenlabsedgeの TTSモデルを使用して生成されます。
      • openai TTS モデルは複数の言語を自動的にサポートしていますが、私の経験では英語以外の音声はまだ品質が十分ではありません。
      • elevenlabs TTS モデルはデフォルトで英語の音声が用意されています。英語以外の音声を使用するには、elevenlabs アカウントの設定で対象言語のカスタム音声をダウンロードし、config.yaml ファイルtext_to_speech.elevenlabs.default_voices パラメータを使用する音声に設定する必要があります(この設定ファイルはプロジェクトのソースコードでのみ利用可能で、pip パッケージには含まれていません。そのため、pip パッケージを使用している場合は、この設定はできません)。 config.yamlファイルで使用したい音声にパラメータを設定します(このconfigファイルはプロジェクトのソースコードでのみ利用可能で、pipパッケージには含まれていません。そのため、pipパッケージを使用している場合は、ElevenLabsの音声を変更することはできません)。ElevenLabsの音声に関する詳細は、ElevenLabs Voice Libraryをご覧ください。
kun432kun432

まとめ

冒頭にも書いたけど、「ライブラリ」として使えるというのがpodcastfyの一番のウリになると思う。設定についても、プロンプトを直接いじるのはできないにしても(というかそこはやりたい人とやりたくない人にわかれそう)、かなり細かくいろいろ設定できるようになっているので、PDF2Audioやpdf-2-podcastを修正・もしくはそれらから流用するよりも、自分でアプリケーションを作って組み込みたいというケースには良いのではないかと思う。

自分はライブラリとして使うことに興味があるのでコードを追いかけてみようと思う。

kun432kun432

Issueのコメントが返ってきた。どうやらリグレッションバグらしい。バグは後ほど修正されるようだけど、v0.2.0以前のバージョンを使ってみてほしいとのこと。

https://github.com/souzatharsis/podcastfy/issues/87

v0.2.0で試したけどダメだったので、リグレッションではなくて、そもそもバグってそう。

このスクラップは2ヶ月前にクローズされました