Google Cloud Firestore APIの料金
Google Cloud Firestore の料金は、以下の要素に基づいて計算されます。
1. **ドキュメントの読み取り、書き込み、削除の回数**: 各操作ごとに課金されます。
2. **インデックス エントリの読み取り数**: クエリを満たすために読み取られるインデックス エントリの数に応じて課金されます。
3. **データベースのストレージ使用量**: 保存されているデータの容量に基づいて課金されます。
4. **ネットワーク帯域幅の使用量**: データの送受信量に応じて課金されます。これらの料金は日単位で計算されます。
**無料の使用枠**も提供されており、以下の通りです。
– **保存データ**: 1 GiB
– **ドキュメントの読み取り**: 1 日あたり 50,000 回
– **ドキュメントの書き込み**: 1 日あたり 20,000 回
– **ドキュメントの削除**: 1 日あたり 20,000 回
– **送信データ転送**: 1 か月あたり 10 GiB無料枠を超える使用量については、課金が発生します。
詳細な料金情報や具体的な料金例については、公式ドキュメントをご参照ください。
とのこと
料金はserviceKeyでのアクセスと合算されるか調べる
Google Cloud Firestore の料金は、
アクセス方法や認証手段に関係なく、プロジェクト全体の使用量に基づいて計算されます。したがって、サービス アカウントのキー(serviceKey)を使用してアクセスした場合でも、
その操作による使用量は他のアクセス方法と合算され、プロジェクト全体の料金として請求されます。具体的には、Firestore の課金は以下の要素に基づいています。
– **ドキュメントの読み取り、書き込み、削除の回数**
– **インデックス エントリの読み取り数**
– **データベースのストレージ使用量**
– **ネットワーク帯域幅の使用量**これらの使用量は、アクセス方法や認証手段に関係なく、プロジェクト全体で集計されます。
したがって、サービス アカウントを使用して行われた操作も、
他のアクセス方法で行われた操作と同様に、プロジェクト全体の使用量として合算され、
料金が計算されます。APIアクセスもserviceKeyアクセスと同様に扱われます。
Google Cloud Firestoreの料金は、
アクセス手段(APIアクセス、serviceKey、その他)に関係なく、
プロジェクト全体の使用量に基づいて計算されます。したがって、APIを通じたアクセスも、serviceKeyでのアクセスも、
同一プロジェクト内での使用量として合算されて課金されます。プロジェクトごとの料金体系に基づくため、
どのアクセス手段を用いても料金計算においては一貫しています
とのこと
つまりAPIでも serviceKey でのアクセスも合算されるので
新しく課金される項目が増えることはない
無料の使用枠も提供されており、以下の通りです。
* 保存データ: 1 GiB
* ドキュメントの読み取り: 1 日あたり 50,000 回
* ドキュメントの書き込み: 1 日あたり 20,000 回
* ドキュメントの削除: 1 日あたり 20,000 回
* 送信データ転送: 1 か月あたり 10 GiB
のように無料枠さえ超えないければ問題ない
まずはAPIを有効化する
Google Cloud Consoleの「Firestore API」のページにアクセス
「APIを有効にする」ボタンをクリックしてFirestore APIを有効化
Cloud Filestore API
Google Cloud Firestore API
の違いは?
調べたら
FileStore と FireStoreの違いだった
あと原因が判明
GOOGLE_APPLICATION_CREDENTIALS
を使う前提のコードになっている
これは以前設定した時に Google Cloud Vision API でうまくいかなくなったため
GOOGLE_APPLICATION_CREDENTIALS
を使わず
Jsonファイルを指定する方法にしているため
なので今回もjsonファイルを指定する
認証情報の指定: f
irestore.Client.from_service_account_json(“serviceAccountKey.json”) を使用して、
serviceAccountKey.json ファイルで認証情報を指定しました。
警告の抑制:
warnings.filterwarnings() を使って、
Firestoreに関するUserWarningを無視する設定を追加しています。
コードを
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | from google.cloud import firestore from datetime import datetime, timedelta import requests import warnings # JSONファイルで認証情報を指定 db = firestore.Client.from_service_account_json( "serviceAccountKey.json" ) # 特定のユーザーID target_user_id = "" # VoiceVox APIの設定 VOICEVOX_SPEAKER_ID = 1 # 読み上げに使用する話者のID # 警告を無視する設定 warnings.filterwarnings( "ignore" , category=UserWarning, module= "google.cloud.firestore_v1.base_collection" ) def read_unread_messages(): # 現在の時刻 current_time = datetime.now() # Firestoreのコレクションから未読メッセージを取得 messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) unread_messages = messages_ref.stream() for message in unread_messages: message_data = message.to_dict() message_text = message_data[ "text" ] message_time = message_data[ "timestamp" ].to_datetime() # VoiceVoxでメッセージを読み上げ read_message_aloud(message_text) # メッセージを既読に更新 message.reference.update({ "read" : True}) # 24時間経過したメッセージの削除 if current_time - message_time > timedelta(hours=24): message.reference.delete() def read_message_aloud(text): # VoiceVoxのAPIにリクエストを送信 response = requests.post( VOICEVOX_API_URL, json={ "text" : text, "speaker" : VOICEVOX_SPEAKER_ID} ) if response.status_code == 200: print( "メッセージを読み上げました:" , text) else : print( "読み上げに失敗しました:" , response.text) # コードを実行して未読メッセージを取得して読み上げ read_unread_messages() |
にする
しかし
1 2 3 4 5 6 7 8 9 10 11 | python get_firestore_message.py /Users/snowpool/aw10s/linebot/get_firestore_message .py:23: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead. messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1731443353.181065 4135517 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache Traceback (most recent call last): File "/Users/snowpool/aw10s/linebot/get_firestore_message.py" , line 53, in <module> read_unread_messages() File "/Users/snowpool/aw10s/linebot/get_firestore_message.py" , line 29, in read_unread_messages message_time = message_data[ "timestamp" ].to_datetime() AttributeError: 'DatetimeWithNanoseconds' object has no attribute 'to_datetime' |
となる
DatetimeWithNanoseconds オブジェクトに to_datetime() メソッドがないため、
エラーが発生しています。
このオブジェクトはそのまま datetime として利用できるので、 to_datetime() メソッドは不要です。
コードを修正して、to_datetime() の呼び出しを削除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | from google.cloud import firestore from datetime import datetime, timedelta import requests import warnings # JSONファイルで認証情報を指定 db = firestore.Client.from_service_account_json( "serviceAccountKey.json" ) # 特定のユーザーID target_user_id = "" # VoiceVox APIの設定 VOICEVOX_SPEAKER_ID = 1 # 読み上げに使用する話者のID # 警告を無視する設定 warnings.filterwarnings( "ignore" , category=UserWarning, module= "google.cloud.firestore_v1.base_collection" ) def read_unread_messages(): # 現在の時刻 current_time = datetime.now() # Firestoreのコレクションから未読メッセージを取得 messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) unread_messages = messages_ref.stream() for message in unread_messages: message_data = message.to_dict() message_text = message_data[ "text" ] message_time = message_data[ "timestamp" ] # to_datetime()を削除 # VoiceVoxでメッセージを読み上げ read_message_aloud(message_text) # メッセージを既読に更新 message.reference.update({ "read" : True}) # 24時間経過したメッセージの削除 if current_time - message_time > timedelta(hours=24): message.reference.delete() def read_message_aloud(text): # VoiceVoxのAPIにリクエストを送信 response = requests.post( VOICEVOX_API_URL, json={ "text" : text, "speaker" : VOICEVOX_SPEAKER_ID} ) if response.status_code == 200: print( "メッセージを読み上げました:" , text) else : print( "読み上げに失敗しました:" , response.text) # コードを実行して未読メッセージを取得して読み上げ read_unread_messages() |
今度は
1 2 3 4 5 6 7 8 9 10 11 | /Users/snowpool/aw10s/linebot/get_firestore_message .py:23: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead. messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1731443604.856422 4139038 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache 読み上げに失敗しました: { "detail" : "Not Found" } Traceback (most recent call last): File "/Users/snowpool/aw10s/linebot/get_firestore_message.py" , line 53, in <module> read_unread_messages() File "/Users/snowpool/aw10s/linebot/get_firestore_message.py" , line 38, in read_unread_messages if current_time - message_time > timedelta(hours=24): TypeError: can't subtract offset-naive and offset-aware datetimes |
となる
このエラーは、current_timeが「オフセットのない(ナイーブな)datetimeオブジェクト」で、
message_timeが「オフセットのある(タイムゾーン付きの)datetimeオブジェクト」であるため、
直接引き算できないことが原因です。
この問題を解決するために、両方を同じ形式のdatetimeオブジェクトに統一します。
コードを修正して、current_timeをUTCタイムゾーン付きに変換
しかし
1 2 3 4 5 6 7 | /Users/snowpool/aw10s/linebot/get_firestore_message .py:23: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead. messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1731443712.845077 4140502 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache 読み上げに失敗しました: { "detail" : "Not Found" } 読み上げに失敗しました: { "detail" : "Not Found" } 読み上げに失敗しました: { "detail" : "Not Found" } |
となる
“読み上げに失敗しました:
{“detail”:”Not Found”}” エラーは、VoiceVox APIに送信したリクエストが見つからない
(404 Not Found)ためです。
これは、VoiceVox APIのエンドポイントや
リクエストの構造が間違っている可能性があることを示しています。
VoiceVox APIの仕様に沿ってエンドポイントとリクエストのフォーマットを確認し、
修正を加えてみましょう。
例えば、VoiceVoxでのリクエストには、
/audio_query エンドポイントを使用して音声生成クエリを作成し、
その後 /synthesis エンドポイントで音声ファイルを生成する必要がある場合があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | from google.cloud import firestore from datetime import datetime, timedelta, timezone import requests import warnings # JSONファイルで認証情報を指定 db = firestore.Client.from_service_account_json( "serviceAccountKey.json" ) # 特定のユーザーID target_user_id = "" # VoiceVox APIの設定 VOICEVOX_SPEAKER_ID = 1 # 読み上げに使用する話者のID # 警告を無視する設定 warnings.filterwarnings( "ignore" , category=UserWarning, module= "google.cloud.firestore_v1.base_collection" ) def read_unread_messages(): # 現在の時刻をUTCのオフセット付きで取得 current_time = datetime.now(timezone.utc) # Firestoreのコレクションから未読メッセージを取得 messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) unread_messages = messages_ref.stream() for message in unread_messages: message_data = message.to_dict() message_text = message_data[ "text" ] message_time = message_data[ "timestamp" ] # VoiceVoxでメッセージを読み上げ read_message_aloud(message_text) # メッセージを既読に更新 message.reference.update({ "read" : True}) # 24時間経過したメッセージの削除 if current_time - message_time > timedelta(hours=24): message.reference.delete() def read_message_aloud(text): # audio_queryを生成 query_response = requests.post( f "{VOICEVOX_API_URL}/audio_query" , params={ "text" : text, "speaker" : VOICEVOX_SPEAKER_ID} ) if query_response.status_code != 200: print( "audio_queryの生成に失敗しました:" , query_response.text) return # 音声合成リクエストを送信 synthesis_response = requests.post( f "{VOICEVOX_API_URL}/synthesis" , params={ "speaker" : VOICEVOX_SPEAKER_ID}, json=query_response.json() ) if synthesis_response.status_code == 200: print( "メッセージを読み上げました:" , text) else : print( "読み上げに失敗しました:" , synthesis_response.text) # コードを実行して未読メッセージを取得して読み上げ read_unread_messages() |
これを実行すると
1 | /Users/snowpool/aw10s/linebot/get_firestore_message .py:23: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead. messages_ref = db.collection( "messages" ).where( "user_id" , "==" , target_user_id).where( "read" , "==" , False) WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1731444164.973858 4145605 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache メッセージを読み上げました: ゴルゴ13だ。 |
となる
コードが正常に動作し、メッセージが読み上げられたようで良かったです!
“メッセージを読み上げました: ゴルゴ13だ。” と表示されたので、
VoiceVoxを使った音声合成が成功しています
となるが
ちょっと意味が違う
Firestoreに保存されたメッセージの取得はできているが
これをvoicevox で音声を作成し
それを再生する
が本来の目的
以前作成したモジュールから使うことにする
音声作成と作成した音声を使用後削除するモジュール
音声を作成するためのモジュールがあるので
それを使うことにする
これらのモジュールはカレンダー読み上げのプロジェクトにあるので
それを使う