Linebot の24時間経過したメッセージの削除

24時間経過したメッセージの削除

import warnings
from google.cloud import firestore
import datetime
import absl.logging

# 警告を無視する設定
warnings.filterwarnings("ignore", category=UserWarning, module="google.cloud.firestore_v1.base_collection")

# Firestore クライアントの初期化
db = firestore.Client.from_service_account_json("serviceAccountKey.json")

# gRPCの警告を抑制
absl.logging.set_verbosity("info")

def get_user_messages(user_id):
    messages_ref = db.collection("messages")
    
    # 複数条件のクエリを設定
    query = messages_ref.where("user_id", "==", user_id).where("timestamp", ">=", datetime.datetime.now() - datetime.timedelta(days=1))
    
    # メッセージを取得してリストに格納
    user_messages = []
    for doc in query.stream():
        user_messages.append(doc.to_dict())

    return user_messages

# 特定のユーザーIDを指定してメッセージを取得
user_id = ""
messages = get_user_messages(user_id)

for message in messages:
    print(f"メッセージ: {message['text']}, タイムスタンプ: {message['timestamp']}")

では24時間以内のメッセージのみ取得して表示している

ストレージの確保のため
24時間経過したメッセージは削除する

import warnings
from google.cloud import firestore
import datetime
import absl.logging

# 警告を無視する設定
warnings.filterwarnings("ignore", category=UserWarning, module="google.cloud.firestore_v1.base_collection")

# Firestore クライアントの初期化
db = firestore.Client.from_service_account_json("serviceAccountKey.json")

# gRPCの警告を抑制
absl.logging.set_verbosity("info")

def get_user_messages(user_id):
    messages_ref = db.collection("messages")
    now = datetime.datetime.now()
    
    # 24時間以内のメッセージを取得するクエリ
    query = messages_ref.where("user_id", "==", user_id).where("timestamp", ">=", now - datetime.timedelta(days=1))
    # 24時間以上前のメッセージを削除するクエリ
    old_messages_query = messages_ref.where("user_id", "==", user_id).where("timestamp", "<", now - datetime.timedelta(days=1))

    # メッセージを取得してリストに格納
    user_messages = []
    for doc in query.stream():
        user_messages.append(doc.to_dict())
    
    # 古いメッセージを削除
    for doc in old_messages_query.stream():
        doc.reference.delete()

    return user_messages

# 特定のユーザーIDを指定してメッセージを取得
user_id = ""
messages = get_user_messages(user_id)

for message in messages:
    print(f"メッセージ: {message['text']}, タイムスタンプ: {message['timestamp']}")

として実行

/Users/snowpool/aw10s/linebot/get_message.py:20: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead.
  query = messages_ref.where("user_id", "==", user_id).where("timestamp", ">=", now - datetime.timedelta(days=1))
/Users/snowpool/aw10s/linebot/get_message.py:22: UserWarning: Detected filter using positional arguments. Prefer using the 'filter' keyword argument instead.
  old_messages_query = messages_ref.where("user_id", "==", user_id).where("timestamp", "<", now - datetime.timedelta(days=1))
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1732049170.984219 4556639 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
メッセージ: 本日は厳しい冷え込みだ, タイムスタンプ: 2024-11-19 20:43:21+00:00

となって24時間経過したメッセージは消えた

次にこのコードに既読フラグをつけたいが
その前になぜ前回のコードが機能しなかったのかまとめておく

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_API_URL = "http://192.168.1.69:50021"
VOICEVOX_SPEAKER_ID = 1

def read_unread_messages():
    # UTCの現在時刻を取得
    current_time = datetime.now(timezone.utc)
    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"]
        # FirestoreのタイムスタンプをUTCに変換
        message_time = message_data["timestamp"].replace(tzinfo=timezone.utc)

        print(f"Checking message: {message_text} at {message_time}, Time difference: {current_time - message_time}")
        if current_time - message_time > timedelta(hours=24):
            print(f"Deleting message: {message_text} at {message_time}")
            message.reference.delete()
        else:
            print(f"Not deleting message: {message_text} at {message_time}")

        read_message_aloud(message_text)
        message.reference.update({"read": True})

def read_message_aloud(text):
    query_response = requests.post(f"{VOICEVOX_API_URL}/audio_query", params={"text": text, "speaker": VOICEVOX_SPEAKER_ID})
    if query_response.status_code == 200:
        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(f"Message read aloud: {text}")
        else:
            print("Failed to read aloud:", synthesis_response.text)
    else:
        print("Failed to generate audio query:", query_response.text)

read_unread_messages()

の場合

from datetime import datetime, timedelta, timezone

def read_unread_messages():
    current_time = datetime.now(timezone.utc)
    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_time = message_data["timestamp"].replace(tzinfo=timezone.utc)

        if current_time - message_time > timedelta(hours=24):
            print(f"Deleting message: {message_text} at {message_time}")
            message.reference.delete()
        else:
            print(f"Not deleting message: {message_text} at {message_time}")

の場合
タイムスタンプをUTC時刻に変換してから、現在時刻との差を計算して24時間を超えていればメッセージを削除

ここでのタイムスタンプはtimestampフィールドから取得され、その値がすでにUTC時刻である必要がある

今回の場合は

import datetime

def get_user_messages(user_id):
    now = datetime.datetime.now()
    old_messages_query = messages_ref.where("user_id", "==", user_id).where("timestamp", "<", now - datetime.timedelta(days=1))

    for doc in old_messages_query.stream():
        doc.reference.delete()


現在時刻から1日前の時刻を計算し、それよりも前のタイムスタンプを持つメッセージをクエリで直接検索

この場合、Firestoreのtimestampは自動的にUTCで扱われるため、時差を考慮する必要がない

GPTによれば

違い
1. タイムゾーンの扱い:
* 最初のコードでは、メッセージのタイムスタンプをUTCに明示的に変換して比較しています。
* 二番目のコードでは、タイムスタンプがUTCであると仮定して、クエリで直接比較しています。
2. クエリの利用:
* 最初のコードでは、すべての未読メッセージをストリームで取得してから条件分岐を行い、必要に応じて削除しています。
* 二番目のコードでは、24時間以上古いメッセージに対して直接クエリを発行し、その結果に基づいて削除しています。

最初のコードが削除できなかった可能性として、タイムスタンプの変換や時差の取り扱いが適切でなかったか、Firestoreの設定やデータの整合性に問題がある可能性が考えられます。また、read属性がFalseに設定されたままのメッセージが削除の条件に含まれていなかったことも影響しているかもしれません

とあるが
最後の read属性についてはハズレで
これがFalseでも削除されている

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です