現代の生活では、バスを待つ時間、地下鉄に乗る時間、核酸を取り出す時間、朝食を買う時間など、必然的に多くの断片的な時間に遭遇します。これらの時間の蓄積は間違いなく大きな個人的リソースであり、この部分の時間を使いたい場合は、明らかに聞くことが最善の方法です。
国内のクラウドコンピューティング音声合成サービスはすでに非常に成熟しており、オープンソースツールをベースにしたTTS PaaSサービスを統合することで、個人的にカスタマイズしたオーディオブック制作ツールを作成するのに非常に便利です。
需要はあります。実現可能性は問題ありません。始めましょう。手を汚しましょう!
1. 分析・調査
オーディオブックの需要を一言で言えば、電子書籍を音声にしてダウンロードリンクを提供することです。
まず要件を絞り込み、さまざまなプロセスに分割し、それらをサポートするためにどのような機能が必要かを確認しましょう。
- 私たちは個人的な好みに基づいて優れた電子書籍をダウンロードします (商用利用の場合は、承認されていることを確認してください)。以前 Kindle を使っていたので、mobi の電子書籍をたくさん持っています。
- 制作ツールを開き、指定した mobi 電子書籍をアップロードします。(Webインタラクションライブラリの研究)
- 制作ツールは、最初に mobi を解析してテキスト コンテンツを取得する必要があります。(mobi 解析ライブラリの研究)
- テキスト コンテンツに基づいて音声合成サービスを呼び出し、オーディオ ブックのオーディオ コンテンツを取得します。(クラウドコンピューティング音声合成PaaSサービスの研究)
- オーディオブックの音声をダウンロードできます。
調べた結果、使用するために用意されたツールスタックは次のとおりです。
2. コード開発
ツールスタックを配置したら、コーディングを開始します。
ステップ 1: 電子書籍ファイルの分析
解析モジュールはまず外部ライブラリ mobi を導入し、mobi.extract 関数を通じて電子書籍ファイルを読み取り、それを HTML 形式ファイル tmp_html に解析します。
mobi ライブラリの使用方法については、ドキュメント mobi - mobi ファイルを解凍するためのライブラリを参照してください。
import mobi
def load_file(self, file_name):
logging.info('begin to parse file')
start_t = time.time()
tmp_dir, tmp_html = mobi.extract(file_name) # 解析 mobi 文件
end_t = time.time()
logging.info('extract {} to {}. cost {}ms'.format(file_name, tmp_html, int((end_t-start_t)*1000)))
with open(tmp_html, 'r') as fp:
lines = fp.readlines()
self.html_content = ''.join(lines) # 读取 html
logging.info('load file total {} chars'.format(len(self.html_content)))
shutil.rmtree(tmp_dir)
logging.info('clean temp dir {}'.format(tmp_dir))
HTML ファイルを取得したら、lxml.etree を通じてそれを DOM ツリーに解析し、大きなキラーである xpath を使用して、必要なコンテンツを取得します。
たとえば、特定の属性を持つ要素、段落、特定の位置のタイトルなどです。理解できない学生は、XPath チュートリアルを読むことができます。
from lxml import etree
def parse_html(self):
logging.info('parse html')
# pre process
self.html_content = self.pre_process(self.html_content)
# parse dom
dom = etree.fromstring(self.html_content)
plist = dom.xpath('//p/text()')
audio_texts = []
# 示例,比如从 1010 段开始,获取后面 10 个段落
idx_start = 1010
for p in plist[idx_start:idx_start+10]:
#logging.info('{}'.format(p))
audio_texts.append(p)
self.text = ''.join(audio_texts)
logging.info('content length {}'.format(len(self.text)))
上記は、AudioBookGenerator クラスにカプセル化された電子書籍解析モジュールです。詳細については、src/audio_book_generator.pyを参照してください。
ステップ 2: 音声音声合成
有声音声合成には、サードパーティの音声合成 TTS サービスが必要です。市場にある一般的なクラウド コンピューティング ベンダーの PaaS サービスを調査した結果、Tencent Cloud TTS サービスを使用することにしました。
良い点は3つあると思います。
- 開発ドキュメントは開発者の視点に基づいており、非常にスムーズに見えます。
- 長いテキスト合成インターフェイスは最大 100,000 ワードをサポートし、章を完全に合成できるため、頻繁にテキストを分割する必要のないオーディオ ブック合成シナリオに適しています。
- Zhixiaoyao サウンドとナレーションをサポートする機能は、小説のシーンに適しており、特にキャラクターの会話が含まれる場合、ナレーションと会話が明確に分離されます。
サービスの登録とアクティベーションについては、公式ドキュメントが非常に詳しいので割愛しますが、Tencent Cloud TTSを参照してください。
サービスがアクティブ化されたら、コンソールでAPI キー管理ページを開き、次のアクセス キーをコピーし、構成ファイルに設定します。
設定ファイルsrc/config.py
class Config(object): SECRET_ID = 'XXXX' # 上記の SecretId に対応 SECRET_KEY = 'XXXX' # 上記の SecretKey に対応 |
公式サイトから提供されているSDKを使って音声合成サービスを呼び出す方法を見てみましょう。
長いテキスト合成の公式開発ドキュメントを開き、下にスクロールして対応する SDK を見つけます。ここでは Python SDK を使用します。
SDK をプロジェクトに統合します。
ロング テキスト合成は、サービス呼び出し用の 2 つのインターフェイスを提供する非同期サービスです。
- 合成タスクインターフェイスの作成: CreateTtsTask
- タスクのステータスと結果のインターフェイスのクエリ: DescribeTtsTaskStatus
以下の create_task 関数と query_task 関数は、これら 2 つの関数に対してそれぞれカプセル化されています。
タスクのステータスをクエリする場合、タスクが完了していない可能性があるため、タスクが完了する (成功または失敗) まで一定の時間が経過した後にクエリをループする必要があることに注意してください。
タスクの作成: CreateTtsTask
電話をかけるときは 2 つのパラメータに注意してください
- VoiceType: 話者を選択するための音声 ID、ここでは先行研究で決定された Zhixiaoyao (100510000) を使用します。武侠小説やファンタジー小説のシーンに非常に適しています。
- VoiceoverDialogueSplit: ボイスオーバー ダイアログ サポート オプション。True に設定する必要があります。テキスト内のダイアログとナレーションを分割し、対応する音色で合成できます。
リクエストが成功すると、タスクの一意の ID が返されます: TaskId
def create_task(self) -> str:
task_id = ''
req = models.CreateTtsTaskRequest()
req.Text = self.text # 合成文本
req.VoiceType = self.voice_type # 设置音色id,此处选用 智逍遥100510000
req.VoiceoverDialogueSplit = self.voiceover_dialogue_split # 打开旁对白支持
req.Codec = self.codec
req.SampleRate = self.sample_rate
req.ModelType = self.model_type
try:
resp = self.client.CreateTtsTask(req)
task_id = resp.Data.TaskId
req_id = resp.RequestId
print('call CreateTtsTask succeed, task_id: {} request_id: {}'.format(task_id, req_id))
except TencentCloudSDKException as err:
print('call CreateTtsTask failed, err: {}'.format(str(err)))
return task_id
タスクのステータスと結果のクエリ: DescribeTtsTaskStatus
呼び出し時に、上記で取得した TaskId をパラメータとして渡すと、リクエストは主に次のようなタスク関連の情報をリアルタイムで返します。
- ステータス: タスクのステータス
- ErrorMsg: タスクのエラーメッセージ (タスクが失敗した場合)
- ResultUrl: 合成されたオーディオのアドレス
def query_task(self, task_id):
req = models.DescribeTtsTaskStatusRequest()
req.TaskId = task_id
try:
resp = self.client.DescribeTtsTaskStatus(req)
data = resp.Data
req_id = resp.RequestId
print('call DescribeTtsTaskStatus succeed, data: {} request_id: {}'.format(str(data), req_id))
except TencentCloudSDKException as err:
print('call DescribeTtsTaskStatus failed, err: {}'.format(str(err)))
if data:
return data.Status, data.ErrorMsg, data.ResultUrl # 任务状态、错误信息、音频文件地址
else:
return 3, 'internal error', ''
上記は、TencentSDK クラスにカプセル化されたオーディオブック音声合成モジュールです。詳細については、src/tencent_sdk.pyを参照してください。
ステップ 3: オーディオブック制作スクリプトを完成させる
メイン スクリプトを通じて、前の 2 つのステップの電子書籍解析モジュールと音声合成モジュールが統合され、ファイル ダウンロード機能が追加されてオーディオブック制作スクリプトが完成します。
Tencent Cloud TTS サービスによって返される合成オーディオ URL の場合、オーディオ バイナリ ファイルをローカルにダウンロードするために HttpAgent クラスが追加されます。
from audio_book_generator import AudioBookGenerator
from http_agent import HttpAgent
def main():
file_name = sys.argv[1]
logging.info('upload file: {}'.format(file_name))
# gen audio
generator = AudioBookGenerator()
generator.process(file_name)
audio_url = generator.get_audio_url()
logging.info('get audo url: {}'.format(audio_url))
# download audio
session_path = os.environ.get('SESSION_PATH', './')
audio_name = os.path.join(session_path, 'result.mp3')
agent = HttpAgent()
agent.download(audio_url, audio_name)
logging.info('download audio to: {}'.format(audio_name))
HttpAgent の詳細については、ファイルsrc/http_agent.pyを参照してください。
ローカル ツールが完成したので、次のコマンドで呼び出して効果を確認できます。
(venv) justin@VM_centos:[~/audio_book/src]: python main.py ../dou.mobi
2022-06-21 10:36:44,959 - main.py[line:13] - INFO: upload file: ../dou.mobi
2022-06-21 10:36:44,959 - /home/justin/audio_book/src/audio_book_generator.py[line:26] - INFO: begin to parse file
2022-06-21 10:36:47,253 - /home/justin/audio_book/src/audio_book_generator.py[line:30] - INFO: extract ../dou.mobi to /tmp/mobiexk287bwzw/mobi7/book.html. cost 2294ms
2022-06-21 10:36:47,293 - /home/justin/audio_book/src/audio_book_generator.py[line:35] - INFO: load file total 4988080 chars
2022-06-21 10:36:47,295 - /home/justin/audio_book/src/audio_book_generator.py[line:38] - INFO: clean temp dir /tmp/mobiexk287bwzw
2022-06-21 10:36:47,295 - /home/justin/audio_book/src/audio_book_generator.py[line:45] - INFO: parse html
2022-06-21 10:36:47,506 - /home/justin/audio_book/src/audio_book_generator.py[line:60] - INFO: content length 625
2022-06-21 10:36:47,549 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/urllib3/connectionpool.py[line:1005] - DEBUG: Starting new HTTPS connection (1): tts.tencentcloudapi.com:443
2022-06-21 10:36:47,699 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/urllib3/connectionpool.py[line:465] - DEBUG: https://tts.tencentcloudapi.com:443 "POST / HTTP/1.1" 200 125
2022-06-21 10:36:47,701 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/tencentcloud/common/http/request.py[line:112] - DEBUG: GetResponse Status: 200
Header: Server: nginx
Date: Tue, 21 Jun 2022 02:36:41 GMT
Content-Type: application/json
Content-Length: 125
Connection: keep-alive
Data: {"Response":{"RequestId":"ffb6f632-bd56-427d-ae21-xxxx","Data":{"TaskId":"gz-27ac44ab-c21e-4e58-b0b3-xxxx"}}}
call CreateTtsTask succeed, task_id: gz-27ac44ab-c21e-4e58-b0b3-xxxx request_id: ffb6f632-bd56-427d-ae21-xxxx
2022-06-21 10:37:27,964 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/urllib3/connectionpool.py[line:1005] - DEBUG: Starting new HTTPS connection (1): tts.tencentcloudapi.com:443
2022-06-21 10:37:28,016 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/urllib3/connectionpool.py[line:465] - DEBUG: https://tts.tencentcloudapi.com:443 "POST / HTTP/1.1" 200 576
2022-06-21 10:37:28,017 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/tencentcloud/common/http/request.py[line:112] - DEBUG: GetResponse Status: 200
Header: Server: nginx
Date: Tue, 21 Jun 2022 02:37:21 GMT
Content-Type: application/json
Content-Length: 576
Connection: keep-alive
Data: {"Response":{"RequestId":"7c4c20d3-ad79-47ea-86a8-xxxx","Data":{"TaskId":"gz-27ac44ab-c21e-4e58-b0b3-xxxx","Status":2,"StatusStr":"success","ResultUrl":"https://xxxx","ErrorMsg":""}}}
call DescribeTtsTaskStatus succeed, data: {"TaskId": "gz-27ac44ab-c21e-4e58-b0b3-xxxx", "Status": 2, "StatusStr": "success", "ResultUrl": "https://xxxx", "ErrorMsg": ""} request_id: 7c4c20d3-ad79-47ea-86a8-xxxx
2022-06-21 10:37:28,580 - /home/justin/audio_book/venv/lib64/python3.6/site-packages/urllib3/connectionpool.py[line:465] - DEBUG: https://xxxx:443 "GET /xxxx HTTP/1.1" 200 535248
http download succ: https://xxxx -> ./result.mp3
2022-06-21 10:37:29,001 - main.py[line:26] - INFO: download audio to: ./result.mp3
音声ファイル result.mp3 は正常に生成できます。付録にデモ音声があり、それを聞くことができますが、効果は非常に優れています。
ステップ 4: スクリプトの視覚化
オーディオブック制作スクリプトは完成しましたが、スクリプトはまだ使いにくいため、他の人が使用することはできません。
ここでは、スクリプトを視覚化し、Web ツールとしてデプロイする必要があります。
ここでは Wooey オープン ソース ライブラリが使用されており、次の利点があります。
- アダプテーション クラスをコンパイルすることにより、スクリプト ツールを Web インタラクティブ ページに簡単に変換できます。
- フロントエンドの知識がなくても、コード構成を通じてページに表示できるドロップダウン ボックス、ファイル アップロードなどの一般的な UI インタラクティブ コンポーネントをサポートします。
- タスクの起動、エコー実行処理、結果ファイルのダウンロードなどの機能をサポートします。
アダプテーション クラスは次のとおりで、パーサーを介してファイル アップロード コンポーネントを追加します。
import os
import sys
import argparse
parser = argparse.ArgumentParser(description="convert mobi file to audio")
parser.add_argument('--audio', help='the mobi file to make audio', type=argparse.FileType('r'), required=True) # 文件上传组件
def audio_book(mobi_file):
_format = mobi_file.split('.')[-1].lower()
if _format != 'mobi':
print('only mobi is supported')
return
# TODO: 此处填写业务逻辑
if __name__ == '__main__':
args = parser.parse_args()
audio_book(args.audio.name)
電子書籍制作スクリプト ツールを呼び出し、Python venv を使用して wooey の環境変数とツール スクリプトを分離すると、wooey プラットフォームが他のスクリプトを統合しやすくなります。
SCRIPT_PATH = '/root/audio_book'
def audio_book(mobi_file):
# ...
# TODO: 此处填写业务逻辑
cmd = []
cmd.append('export SESSION_PATH={}'.format(os.getcwd())) # 传输本次执行 session 路径到脚本
cmd.append('cd {}'.format(SCRIPT_PATH))
cmd.append('source {}/venv/bin/activate'.format(SCRIPT_PATH))
cmd.append('cd src')
cmd.append('python main.py {}'.format(mobi_file))
cmd.append('cd ')
cmd = '&&'.join(cmd)
print(cmd)
os.system(cmd)
視覚化プラットフォームにスクリプトを追加する
[root@VM-centos ~/TOOLS]# python manage.py addscript ../audio_book/audio_book_adaptor.py --group 小工具 Converting ../audio_book/audio_book_adaptor.py 変換されたスクリプト数は 0 です |
すべての作業が完了しました。効果を楽しみましょう。
3. 製品体験
初めてのオーディオブックを合成する
ツールプラットフォームを開き、オーディオブック作成ツールを選択します
[ファイルを選択]ボタンをクリックして、変換したい電子書籍ファイルをアップロードします。
タスクを開始すると、ページからスクリプトの実行ログを確認できます。
タスクの実行が完了するとステータスに成功が表示され、ページ下部のファイルリストから「result.mp3」をクリックしてダウンロードできます。
この時点で、オーディオブック制作ツール全体が完成しており、オーディション用のオーディオとエンジニアリング コードが付録に含まれています。
オーディオブックの効果については、興味のある学生は付録からダウンロードして聞くことができ、個人的にはかなり良いと思います。
エンジニアリングコード部分は基本的にそのままで利用できるので、興味があればダウンロードして実行し、これをベースに必要な機能を追加することもできます。
さて、ここでやめましょう~~
付録
- オーディオブックのサウンド効果プレビュー: result.mp3
- オーディオブック制作プロジェクトコード: GitHub - jizhouli/audio_book_generator
Tencent Cloud AI 音声合成製品情報の詳細については、音声合成_音声カスタマイズ_音声合成サービス-Tencent Cloud をご覧ください。