ChatGPTとVOICEVOXでNHKニュースを聞く
ChatGPTとVOICEVOXでNHKのニュース記事をラジオみたいな感覚で聞けるプログラムを作ってみました。環境構築はよくわからないので説明全然してません。頑張ってください。WSLでやってます。予期しない動作でお金がいっぱいとられても自己責任でお願いします。
環境
まずはVOICEVOXのAPIをなんとかして使えるようにします。以下の記事を参考にしました。
この記事通りエンジンを起動するところまでやってください。GPUは使わなくていいと思います。
ChatGPTの方は無限に紹介記事あるのでなんでもいいでしょう。SeleniumのためのChrome driverとかも必要です。
コード
いんぽーと
from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import chromedriver_binary
import time
import json
import wave
from playsound import playsound
import openai
まずはChatGPTの問い合わせコードです。ほぼこの記事からのコピペですが、使用トークン数が分かるようにしています。あと使ってないけどてんぷらちゃあも。
openai.api_key = "あぴきー"
def completion(new_message_text:str, settings_text:str = '', past_messages:list = [], temperature=1):
if len(past_messages) == 0 and len(settings_text) != 0:
system = {"role": "system", "content": settings_text}
past_messages.append(system)
new_message = {"role": "user", "content": new_message_text}
past_messages.append(new_message)
result = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=past_messages,
temperature=temperature
)
response_message = {"role": "assistant", "content": result.choices[0].message.content}
past_messages.append(response_message)
response_message_text = result.choices[0].message.content
return response_message_text, past_messages, result["usage"]["total_tokens"]
最新ニュース記事を取得します。Seleniumを使うのはブラウザで読み込まないと記事いっぱいとってこれないからです。
driver = webdriver.Chrome()
driver.get("https://www3.nhk.or.jp/news/catnew.html#!/10/")
time.sleep(1)
html = driver.page_source
driver.close()
soup = BeautifulSoup(html, 'html.parser')
links = [url.get('href') for url in soup.find_all('a')]
links = ["https://www3.nhk.or.jp" + news for news in links if "/html/" in news]
links = list(set(links))
ChatGPTへのプロンプト。プロンプトはよくわからないので適当です。
system_settings = """記事の内容を入力します。
あなたは入力された記事を要約して少女風のかわいらしい話し言葉に変えてください。
例:
あのね、
すごいでしょ?
できたんだって!
びっくりだよね~
"""
メインのコード
start_time = False
for link in links:
res = requests.get(link)
res.encoding = res.apparent_encoding
soup = BeautifulSoup(res.text, 'html.parser')
try:
#タイトル、本文
question = soup.find(class_="content--detail-body").get_text()
title = soup.find(class_="content--title").get_text().replace("\n","")
new_message, _, tokens = completion(question, system_settings, [], temperature=1)
except:
continue
print(title, f":{tokens}トークン")
print("(" + link + ")")
print(new_message)
print()
#音声合成
res1 = requests.post('http://127.0.0.1:50021/audio_query',params = {'text': title + " " + new_message, 'speaker':8})
res2 = requests.post('http://127.0.0.1:50021/synthesis',params = {'speaker': 8},data=json.dumps(res1.json()))
data = res2.content
#前の音声が終わるまで待つ
end_time = time.perf_counter()
if start_time and end_time - start_time < play_time:
time.sleep(start_time - end_time + play_time)
time.sleep(1)
with open('output.wav', mode='wb') as f:
f.write(data)
with wave.open('output.wav', mode='r') as f:
play_time = f.getnframes() / f.getframerate()
#再生
start_time = time.perf_counter()
playsound("output.wav", False)
playsoundで非同期に再生して、記事間で隙間ができないようにしています。音声処理に関しては知識がないのでこんな感じでいいのかよく分かりません。記事の一部で形式が違ってうまく本文が取り込めないものや、ChatGPTのトークン数制限に引っかかるものがあるので、適当に例外処理しています。
生成例:
こんな感じです。ヌートバーまじか;;
うまくいってないもの。
「わたしたちの大好きな」、とか「あきらめることになってしまった」、とかちょっとおかしいですね。
おわりに
英語圏のニュースサイトでやった方が有意義じゃね?