プログラミングの芽

面白そうな技術を使って、楽しいことやりたい

ChatGPT APIとVOICEPEAKを連携してAIとお話する

VOICEPEAKがPythonから使えるようになっていたので、最近話題のChatGPTに声を与えてみました。
VOICEPEAKをPythonで使う方法については、以下記事を参照してください。 atarms.hatenablog.com 今回は上記記事のスクリプトを、text2voicePeak.pyとして保存したものを使います。

あと、ChatGPT APIはそのまま使うとユーザーとのやり取りを一切記憶しないので、今回は記憶する実装にしました。 詳細は調べてね。

下に置いてあるコードを使うと動画みたいな感じになります。

以下が今回のコード

import openai
from text2voicePeak import playVoicePeak

openai.api_key = "OpenAIのサイトから発行したものをペースト"

# ChatGPTクラス
class ChatGPTClass:
    def __init__(self):
        self.messages = []
        self.ai_response = ""
        # role:systemで初期設定をしたければ、以下で読み込む。なくてもいい
        # self.loadConfig("chatGPTSetting.txt")

    def chatProcess(self, userMessage):
        # ユーザの回答を保存
        self.messages.append({"role": "user", "content": userMessage})

        # APIを使ってChatGPTの回答を生成
        response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=self.messages)
        self.ai_response = response['choices'][0]['message']['content']

        # AIの回答を保存
        self.messages.append({"role": "assistant", "content": self.ai_response})

        return self.ai_response

    def loadConfig(self,fileName):
        with open(fileName, "r", encoding="utf-8") as f:
            self.messages.append({"role": "system", "content": f.read()})

使用例

# chatBotクラスのインスタンスを生成
chatbot = chatBot()
# 会話を始める
while True:
    # ユーザの入力を待機
    userMessage = input("あなた:")
    if(userMessage == "_log"):
        # このセッションのChatGPTとのログを表示
        for message in chatbot.messages:
            print(message["role"],":",message["content"])
        continue

    # ユーザの入力をchatProcessに渡す
    chatbot.chatProcess(userMessage)
    # AIの回答を表示
    print("AI:",chatbot.ai_response)

    # VoicePeakでAIの回答を音声で再生
    playVoicePeak(chatbot.ai_response)

VOICEPEAKナレータの種類も増えてきてますし、今回の方法使ってギャルゲ作ってくれる人を切に望んでいます。

VOICEPEAKをPythonから呼び出す

VOICEPEAKがコマンドラインから使えるようになっていたので、Pythonから呼び出してみました。
今回、チャットボットの回答を音読させるようにしたので、生成された音声ファイルは使い捨てています。

PythonからVOICEPEAKを使うには、subprocessモジュールを使ってvoicepeak.exeを実行します。
voicepeak.exeのパスや出力先、ナレーター名や感情パラメータなどを引数として渡します。
出力されたwavファイルをwinsoundモジュールで再生しています。
再生後、wavファイルを削除しています。

以下が今回のコードです。

import os
import subprocess
import winsound

def playVoicePeak(script , narrator = "Japanese Female 1", happy=50, sad=50, angry=50, fun=50):
    """
    任意のテキストをVOICEPEAKのナレーターに読み上げさせる関数
    script: 読み上げるテキスト(文字列)
    narrator: ナレーターの名前(文字列)
    happy: 嬉しさの度合い
    sad: 悲しさの度合い
    angry: 怒りの度合い
    fun: 楽しさの度合い
    """
    # voicepeak.exeのパス
    exepath = "C:/Program Files/VOICEPEAK/voicepeak.exe"
    # wav出力先
    outpath = "output.wav"
    # 引数を作成
    args = [
        exepath,
        "-s", script,
        "-n", narrator,
        "-o", outpath,
        "-e", f"happy={happy},sad={sad},angry={angry},fun={fun}"
    ]
    # プロセスを実行
    process = subprocess.Popen(args)

    # プロセスが終了するまで待機
    process.communicate()

    # 音声を再生
    winsound.PlaySound(outpath, winsound.SND_FILENAME)

    # wavファイルを削除
    os.remove(outpath)

使用例(最小)

playVoicePeak("こんにちは")

VOICEPEAKのコマンド引数については、以下を参考にしました。
voicepeak v1.2.1のコマンド - takashiskiのブログ

公式マニュアルにも書いてあるみたいなんですけど、記述を見つけられませんでした・・・

VOICEPEAKとChatGPTを連携した記事を書きました。

atarms.hatenablog.com

Gitでよく使うコマンドメモ

最近をGithub使う機会が増えたので、よく使うコマンドをメモしておきたいと思います。

基本

リモートリポジトリをローカルに作成する

git clone "リポジトリのURL"

リポジトリ編集完了後の差分追加方法

git add [ファイル名 or "."で差分全て]
git commit -m "最高にわかりやすいコメント"
git push origin [ブランチ名]

ちなみにコメントについては、1行目にタイトル、3行目4行目以降に詳細を記入したtxtファイルを作成後

git commit -F commit.txt

でも可能。

ローカルリポジトリがリモートリポジトリより古いときに最新版を取得する

複数の環境で一つのリモートリポジトリを弄っているとズレてくるので、そんなときは古い環境の方でpull

git pull origin [ブランチ名]

ブランチ関係

ブランチを切る

ブランチを切りたいローカルリポジトリディレクトリで

git branch [新しいブランチ名]
git checkout [新しいブランチ名]
git push origin [新しいブランチ名]

ブランチをmasterにマージする

git checkout master
git merge [mergeしたいブランチ名]
git push origin master

あとはローカルのコミット取り消したりだとかありますが、まだあまり使う機会がないので今回は書いてません。
リモートリポジトリをローカルに持ってきて、ブランチ切って編集してプッシュして...、キリがいいところでmasterにマージといった感じでしょうか。

youtube-dlをpythonで使うときのオプションメモ

こんにちは
youtube-dlをpythonで使う時に、私がよく使うオプションをメモしておく記事になります。

今回の内容

今回示す設定内容は
- mp3で保存
- 最高音質
- 限定公開やメンバーシップ限定動画に対応(クッキー使用)
- ダウンロードしたファイルのメタ情報に動画のタイトル等を追加
- ダウンロードしたファイルに動画サムネイルを設定
- 実行ファイル/result/以下に保存
という内容になっています。

コード

ydl_opts = {
        'writethumbnail': True,
        'cookiefile': cookieFilePath,
        'postprocessors': [
            {
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            },
            {'key': 'FFmpegMetadata'},
            {'key': 'EmbedThumbnail'},
        ],
        'outtmpl': os.path.dirname(__file__) + '/result/' + channelName + '/' + fileName + '.%(ext)s',  // channelNameとfileNameは適宜
        'format': 'bestaudio/best',
}

おわりに

postprocessorsを使用するのがポイントです。
クッキーファイルはYoutubeにログインした状態でクッキーファイルを書き出すなどして用意してください。
恐らくtxtファイルになるかと思います。

GoogleのGeocodingAPIで住所の正規化をする

こんにちは。
何の処理もされていない各々が入力した、揺らぎまくりの住所録データを使ったシステムを作ることになってどうしたもんか試していたところ
Google Maps PlatformのGeocoding APIを使えばいい感じにフォーマットしてくれたので、メモとして残しておきます。

今回の目的としては以下になります。 - 住所の単純な正規化(半角全角など) - 建物名以降は除外

Geocoding APIとは

住所→座標および座標→住所(逆Geocoding)の変換を行うAPIです。
使い方などの詳しいことは、以下の公式のドキュメントを読んでください。

developers.google.com

応答などのドキュメント

developers.google.com

実装(Python

シンプルにAPIを使う場合

import pandas as pd
# 住所録ファイル読み込み
df = pd.read_excel('./sample.xlsx')

import googlemaps

# GoogleMapsAPI用に取得したAPIキー
Key = "取得したAPIキー"

# GoogleMapsAPI用にAPIキーを返す
gmaps = googlemaps.Client(key=Key)

# 結果格納用
result = []

for i in range(len(df)):
    # 各行のデータを取得
    row = df.iloc[i]
    # ジオコーディング
    geocode_result = gmaps.geocode(row[0], language='ja')
    result.append(geocode_result)

返ってきた結果から、フォーマットされた住所を抽出する

formatResult = []

# 以下でフォーマットされた住所を抽出
for r in result:
    # 元データが不正だったのか、たまに空のケースあるので条件分岐
    if r != []:
        data = r[0]
        #"formatted_address"に入ってる。" "でsplitすると、[1]に丁目番地まで、[2]以降に建物名などが入ってくる
        formatResult.append(data["formatted_address"].split(" ")[1])
    else:
        formatResult.append(['None'])
# dfに変換
dfsavedata = pd.DataFrame(formatResult)
# xlsxファイルに保存
dfsavedata.to_excel('./output.xlsx')

以上で、ばらばらだった住所録のデータを丁目番地以降削除した状態でフォーマットできます。

問題

建物名が含まれた住所で、時々丁目番地も一緒に消された結果が返ってくることがあります。
前処理でどうにかなるのかもしれませんが、今回は面倒くさかったので生データをそのまま入れた結果です。
まぁ少数なので、その部分は手で直せばよいかなという感じです。

finalのCOTSUBU for ASMRを買った話(1カ月使用しての感想を追記)

※約1か月使用しての気になる部分を追記しました

こんにちは。
私は以下のサイトを作ってしまうぐらいにはASMRが大好きです。

www.vtasmr.com

そこで、今回は当然のように購入したfinalのCOTSUBU for ASMRについて、実際にASMRを聴いてみて感じたことを、ものすごく簡単に書きたいと思います。
普段はAirPods ProでASMRを聴いています。(定番のSE215やE500、HSE-A2000PNは所持していますが、それでもAirPods Proの音が私は好きでした)

私がCOTSUBU for ASMRに期待していたこと

  • 装着感
  • 寝ホンとして使用できるか

以上2点です。
というのも、ASMRはやはり寝る時に聴くことが多いです。 そんな中で、耳から簡単に外れてしまったり、耳を枕に押し付けたときに痛くなったり等が要因となって姿勢が制限されてしまうとストレスになってしまいます。 そのため、私は音がどうだ、というよりもいかに快適に寝れるかが重要だと思っています。 音は正直二の次です。

装着感

まず装着感についてですが、問題は全くないです。
特筆すべき点としては、イヤホンが本当に耳奥まで入ってくるという点です。
私の場合は、イヤホンを耳から外すのが少し大変なぐらいに耳奥まで入ってきます。
耳奥まで入ってるのは単純にイヤーピースのサイズが小さいから?とつけた瞬間は思ったのですが、いざ耳からイヤホンを外そうとするとしっかり密閉されていることがわかったので、そういう設計なのでしょう。

寝ホンとしてはどうか?

結論としては、最高ではないけど問題は無いラインです。
耳を完全に枕に押し付けると、設計上より耳奥まで入ってしまい、痛い、というかこれ以上深く差していいものか不安になります。
ただ、ボディに突起等はなく、耳から飛び出ているわけでもないので耳を枕に押し付けたときの違和感というのはありません。

実際にASMRを聴いてみて

聴いたASMRは、上記サイトに登録されている適当な動画です。

違和感?新感覚?

まず真っ先に思ったのが、なんか音に違和感を感じたんですよね。
悪いというよりかは、今まで自分が聴いたことがない音の出し方というか、VRを初めて体験した時の感覚に近かったです。

音の定位がものすごく良い

これってなんなんだろう、と少し考えた結果、音の定位がものすごく良いという結論に至りました。
ASMR専用と謳ってはいましたが、嘘偽りはありませんでした。
本当に音の定位が新感覚レベルで良いんです。
普通のイヤホンだったら、音が出ている位置とか距離って、バイノーラル録音していたとしてもなんとなくボヤっとしてるんですよね。
以下がイメージ図なんですが(左が従来、右がCOTSUBU for ASMR) f:id:atarms:20211112135657p:plain COTSUBU for ASMRだと音の定位がはっきりしているというか、輪郭がぼやけていないというか、なんというか・・・
私は音にうるさい人間ではないので感覚の話なんですが、とにかく従来のものと全然感覚が違います。 音が広がっていないといえばいいんでしょうか、従来は広がっていたものがギュッと凝縮されて点になって聴こえます。
これが定位が良いということなんでしょうね。
正直、音に関してはワイヤレスということもあって舐めてたんですけど感動しました。

おわりに

私はレビューを書くような人間ではないのですが、今回はCOTSUBU for ASMRがあまりにも新感覚な音を提供してくれたので衝動で記事にしました。
ASMRイヤホンとしては間違いなく素晴らしいイヤホンです。
普段ASMRを聴かない人も、お店で試聴でもなんでもいいので1回はこのイヤホンでASMRを聴いてみてほしいです。
イヤホンというか、もうVR機器です。

以下、商品リンクです

COTSUBU for ASMRfinal-inc.com

ちなみに、同サイト内にある以下ページも興味深い内容ですので、おすすめです。

final-inc.com

1カ月使用して感じたこと(2021/12/05追記)

ほぼ毎日、寝るときにASMRを聴くために使用していました。
その中でいくつか気になる部分が出てきたので追記しておきます。 良い部分に関しては上に書いているので、基本的には良くない部分になります。 以下順番に書きます。

1. タッチ操作はいらない

装着しながら寝ていると、徐々にズレて耳から外れそうになることがあります。
これ自体は別に構わないんですが、位置を直そうと触ると8割ぐらいの確率で再生が停止したりなんだりしてしまいます。
これ以外にも、自分の腕を枕にして寝てる時でもセンサが反応して再生が止まったりします。
良くも悪くもタッチのセンサがものすごく敏感で、本当にちょっと触れただけでも反応してしまうのは結構ストレスですね。

2. 寝ホンとしては、Airpods Proの方が優秀

しばらく使ってて、やはり耳への負担的なものはAirdpod Proの方が無いです。
というのも、恐らくAirpods Proはそもそも設計的に耳奥まで入ることが無い為でしょう。
COTSUBU for ASMRを寝ホンとしてちゃんと使いたい場合、以下の様な枕を使うと快適に使えます。(私も1年前に購入して今も使っています。)

(広告ブロックしてると表示されないかもしれません)

3. 充電ケースに入れても充電されていない時がある

原因がよくわからないのですが、いざ使おうとケースから出すと、1分程度で片方のバッテリーが0になったりすることがちょくちょくありました。
ケースにしっかり入っていなかったのかもしれませんが、パチっと磁力か何かで接点にくっついて、ケースが正常にしまっているのにもかかわらず充電できていないのはよくわかりません。
寝るときに使おうとしてるので、これが起きるとかなりテンション下がっちゃいますね。
まぁその時はAirpods Proを使っています。

4. 両方だしても片方だけしかペアリングされない場合がある

これは前述したバッテリーが0の状態とかではなく、バッテリーがあるのにペアリングされない場合ですね。
ペアリングされていないほうを再度ケースに入れて、もう一度出すとペアリングされます。

結局のところ

後者2つは不具合的なものなので、初期ロットを買ったということもあって仕様がない部分もあるのかなとは思います。
ただ、タッチ操作に関してはもう少しどうにかならなかったのかなと思います。
反応しないように気を付けて触っても、反応してしまうのは中々ストレスです。
寝るときにASMRを聴くためのイヤホンとしては、音だけ見れば最高の物なので今後も変わらず使用し続ける予定です。
今後新タイプが出るのかはわかりませんが、もし新しいタイプが出たらそれもぜひ買ってみたいなと思う製品でした。

Youtubeチャンネルのメンバーシップ限定動画の再生リストを表示する

追記 Chrome拡張機能を公開

本記事の内容でもメンバーシップ限定動画の再生リストを閲覧することは可能なのですが、一々URLをコピーして連結というのが面倒くさいです。
ということで、ワンクリックでメンバー限定の動画プレイリストを開けるChrome拡張機能を作成・公開しました。
以下のURLから追加が可能です。

chrome.google.com

追加したら、任意のチャンネルページで本拡張機能をクリックすることでメンバー限定動画のプレイリストを表示できます。

拡張機能 ver1.1.0アップデート(2022/1/2)

YoutubeのチャンネルURL仕様変更に伴い、本拡張機能が実質的に機能しない状態になっていました。
これに関して対応が完了いたしました。

ただ、処理に抜本的な変更が必要になったことや、manifest v3への対応のために少し必要な権限が増えました。
インストールやアップデート時に、履歴の読み取りができる等不安なことが書いてありますが、権限的に読み取れますよというだけです。
実際に読み取りや、その結果を外部サーバーに送ったりはしていないのでご安心ください。

もし、不安がございましたら以下でソースコード全て公開しているので確認してみてください。
yt-member-playlist-view/src at master · atarm/yt-member-playlist-view · GitHub

初めに

Display a playlist of Youtube channel membership-only videos

こんにちは。
今回はYoutubeチャンネルに登録されているメンバーシップ限定の配信および動画の再生リスト一覧を表示する方法について書きます。
今回の内容は、メンバーシップ登録の有無関係なく適用可能です。 [:contents]

前提

Youtubeにおいて、動画の公開範囲を定めるものは以下の4つです(厳密には5つですが)

視聴範囲 検索結果
公開 全員 表示される
限定公開 URLを知っている人 表示されない
メンバー限定公開 メンバー登録している人 表示されない
非公開 投稿者 表示されない

今回は3つ目のメンバー限定のものが対象です。

限定公開や非公開の動画リストに関しては、私の知る限りではチャンネル側が作成する必要があります。

メンバー限定配信/動画を視聴する一般的な方法

私はいくつかのYoutubeチャンネルのメンバーシップを登録しています。

その中で限定配信や限定動画などのコンテンツがあります。これらを視聴する主な流れは以下となります。

  1. メンバーシップを登録しているチャンネルページを開く
  2. メンバーシップタブに切り替える
  3. 目的のコンテンツを探す

ただ、これには何点か致命的な問題があります。

問題点

以下の3点は、ものすごく不便ではありますが耐えられる範囲のものです。

  • 投稿のソート等はできないので、過去の古いコンテンツの発見が困難
  • 動画/配信以外の投稿と混ざるので単純に見にくい

しかし、以下の問題は致命的です。

  • 限定配信/動画のURLが分からなければ、そのコンテンツの発見が不可能

とはならないのが非常に厄介なんです。

限定配信/動画が発見できるケース

コミュニティにて(TwitterなどのSNSでもよいですが)

予めメンバー限定で配信/投稿することが決まっている場合、多くの方はどこかしらかで発信してくれます。

限定配信/動画が発見できないケース

多くは分からない、というより分からなくなるケースですね。

はい、チャンネルの事情で一般公開されていたものがメンバー限定に切り替えられるパターンです。

気が付いたらメンバー限定になっていたりすることもあり、こうなると見つけるのが困難になります。

コミュニティタブなどでURL付きで通知してくれればマシなのですが、実施しているチャンネルはあまり見たことがありません。

既に公開したものだから、みんな当然知っているだろうという感じでしょう。

(一応)見つける方法

  • 自分の再生履歴をから探す
  • たまたまその動画を高評価していれば、「高評価した動画」リストから探す
  • もしチャンネルがTwitterなどで配信/投稿を呟いていれば、そのツイートを探す
  • たまたま覚えてたURLを打ち込む

いずれにしても古い動画を急にメンバー限定にされたら非常に困難ですね。

メンバーシップ限定動画の再生リストを表示する

本題です。といっても以下の1行ですが。

https://www.youtube.com/playlist?list=UUMO + UC以降のチャンネルID

上記のURLにアクセスすると、「メンバー限定の動画」という再生リストにアクセスできます。

https://www.tech.vtasmr.com/wp-content/uploads/2021/11/image-4.png

この再生リストは、画像にも書いてある通りYoutubeが自動で作成しているものなので、メンバー限定になっているものは全て登録されています。

チャンネルID・・・?(2023/1/10追記)

気が付いたらチャンネルIDはほぼ使われなくなっていますね。 Youtube君は何がしたいのか、カスタムURLすら差し置いてユーザーIDを使い始めています。

事実上、本記事で紹介している方法は使えないかもしれません。 冒頭の拡張機能は、これらに対応済みなので特に何も考えず使用できます。

それっていいの?

なぜかわかりませんが、チャンネルの意図しない(?)ところでメンバー限定動画のURLを知ることを気に掛ける方を時々見かけます。

上の画像に共有ボタンがあったり、Youtubeの仕様で自動的に再生リストが作られていることからもわかるように

別にYoutubeはメンバー限定動画のURLを該当チャンネル以外が公開することを禁止していません。

そもそも、メンバー登録していなければ以下のように動画は視聴できません。

https://www.tech.vtasmr.com/wp-content/uploads/2021/11/image-5.png

終わりに

今回はYoutubeチャンネルのメンバー限定動画の一覧(再生リスト)を表示する方法について書きました。

メンバーの登録の有無に関わらず再生リストの表示はできるので、どんなコンテンツがあるか確認してからメンバー登録を検討したい、といった場合に使ってみてください。