Python > 投稿内容が言及された場合に取得する

Pythonで遊んでいます。具体的には以下の通りです。\n\nClient Challenge / https://docs.discourse.org/#tag/Notifications/operation/getNotifications\n\nPythonは初心者(学習中)で、@UserAがどこかで言及された場合に投稿を受け取るだけでいいと思っています。通知からpost_numberを取得し、その投稿をクエリして投稿コンテンツを取得・保存する必要があると考えていました。\n\nそこから、その投稿コンテンツをデータ変数として保存し、そこから何かを実験したいと考えています。\n\n私のコードの一部は次のとおりです。\n```\n# メンションを検索\nmention = client.notifications.json.get()\n\n# 投稿を出力\nfor post_number in mention:\n print(post_number)\n\n\nこのコードの現在の出力は次のとおりです。\n\n\nnotifications\ntotal_rows_notifications\nseen_notification_id\nload_more_notifications\n```\n\nこれは愚かな質問かもしれませんが、APIもPythonも比較的初心者です。一日中成功せずにこれに取り組んできましたが、誰かが正しい方向を示してくれるなら、非常に感謝します。

「いいね!」 3

fluent-discourseへのリンクを投稿してくれてありがとう!

現在、Pythonを習得しようとしているところなので、ここで概説していることよりも良いアプローチがある可能性があります。

mention = client.notifications.json.get()

これは、clientを作成したときに設定したusernameのメンションの辞書を返します。clientを作成したときにusernameUserAに設定したと仮定します。

辞書が返されていることを確認するには、次を実行できます。

print(type(mention))

これは<class 'dict'>を返すはずです。

実行することで辞書のキーを確認できます。

print(list(mention))

これは['notifications', 'total_rows_notifications', 'seen_notification_id', 'load_more_notifications']を返します。

あなたのケースでは、notificationsキーの下にある値が必要になります。

notifications = mention['notifications']

次にtype(notifications)を実行すると、リストであることがわかります。UserAへのメンションによってトリガーされた通知を取得するには、リストを反復処理して、notification_type1に設定されているエントリを見つける必要があります。DiscourseサイトのrailsコンソールからNotification.typesを実行すると、Discourse通知タイプの値を確認する最も簡単な方法です。

 pry(main)
=> {:mentioned=>1,
 :replied=>2,
 :quoted=>3,
 :edited=>4,
 :liked=>5,
 ...

したがって、clientに設定したユーザー名の「メンション」通知を取得するには、次のようなことを試してください(入力しながらPythonインタープリターでテストしています)。

data = client.notifications.json.get()
notifications = data['notifications']
# 「メンション」通知を格納するため、空のリストオブジェクトを作成します
mentions = []
# `notifications`リストを反復処理して、`notification_type`が`1`に設定されているすべてのエントリを見つけます
for notification in notifications:
    if notification['notification_type'] == 1:
        mentions.append(notification)

これにより、メンションによってトリガーされた通知のリストが作成されます。リストの各項目は辞書になります。次のようなもので確認できます。

for mention in mentions:
    print(mention['topic_id'], mention['post_number'])
「いいね!」 3

これは素晴らしいですね。情報ありがとうございます。Python x Discourseに関する情報はあまり多くないので、学べて嬉しいです。これは他の人にも役立つかもしれません。コードを試してみましたが、期待どおりに動作するようです。もちろん、プレイを止めたわけではないので、ステップ5まで進むための回避策と、投稿の生のコンテンツまで必要な値を取得するための別の方法を見つけました。

基本的にはこれがやりたいことです。

  1. 通知を取得する
  2. 投稿番号を取得する
  3. 投稿コンテンツを取得する
  4. OpenAIで返信を生成する
  5. 返信する
  6. 同じ通知を既読にする?
# ボットを無期限に実行するためのループを設定する
while True:
    # ユーザーアクションを取得し、投稿IDを取得する
    data = {
    'username': 'theuser',
    # メンションと返信の場合、フィルター6 + 7を取得する必要がありますが、なぜか1つのJSON応答しか返されません。
    'filter': 6 | 7,
    'limit': 10,
    }

    unread_mentions = client.user_actions.json.get(data)
    print(unread_mentions)

    user_actions = unread_mentions['user_actions']

    # 未読のメンションごとにループする
    for user_action in unread_mentions['user_actions']:
        topic_id = user_action['topic_id']
        post_number = user_action['post_number']
        post_id = user_action['post_id']
        username = user_action['username']

        print(f'Topic ID: {topic_id}, Post Number: {post_number}, Post ID: {post_id}, Reply to: {username}')

        # 投稿コンテンツを取得する
        post = client.posts[post_id].json.get()

        # 投稿コンテンツを出力する
        post_content = post['raw']

        # 投稿への返信を生成する
        response = generate_response(post_content)

        # フォーラムに返信する
        content = {
            'topic_id': topic_id,
            'raw': response + ' @' + str(username)
        }
        make_post = client.posts.json.post(content)

現在、2つの問題があります。

  • メンションが1つしか取得されません。何か忘れていると思いますが、まだ理由はわかりません。
  • もちろん、投稿に一度だけ返信したいので、ループしているため、これを防ぐための何かが必要です。
    • post_idを.txtファイルに保存できます(どれくらいのデータを保存できるかわかりませんが、かなりの数のメンションを処理できると思います)。
    • 私の理想的な解決策は、通知を既読にすることでした。しかし、私たちのコードのどれも未読のメンションを取得していないことに気づきました(まあ、最初は未読通知を取得しようとしましたが、必要なpost_id変数を抽出/保存して、/posts/get.jsonを使用して「raw」コンテンツを取得することができませんでした)。

私の最終的な目標は、OpenAI APIで応答を供給することです。しかし、まず上記の問題を解決する方法を見つける必要があります。

指定されたユーザー名(例:UserA)が投稿で言及されたときに、OpenAIからの応答を生成したいのだと仮定します。それが正しい場合、DiscourseにAPIリクエストを行って通知を取得する代わりに、Discourseの通知イベントWebhookをPythonアプリケーションのサーバーに向けることができます。PythonアプリケーションはWebhookのペイロードを確認する必要があります。ペイロードのnotification_type1に設定されており、そのuser_idが通知を取得したいユーザーのIDと一致する場合、ペイロードのoriginal_post_idフィールドに設定されている投稿を取得するためにDiscourseにAPIリクエストを行います。次に、そのリクエストから返された投稿コンテンツをOpenAIに送信します。

以下は、メンション通知のペイロードの例です。

{
  "notification": {
    "id": 55267,
    "user_id": 2,
    "notification_type": 1,
    "read": false,
    "high_priority": false,
    "created_at": "2022-12-08T23:23:36.379Z",
    "post_number": 5,
    "topic_id": 277,
    "fancy_title": "I should be able to call this topic anything",
    "slug": "i-should-be-able-to-call-this-topic-anything",
    "data": {
      "topic_title": "I should be able to call this topic anything",
      "original_post_id": 10999,
      "original_post_type": 1,
      "original_username": "scossar",
      "revision_number": null,
      "display_username": "scossar"
    }
  }
}

このアプローチの利点は、Discourseサイトへの大量のAPIリクエストを行うことなく、リアルタイムで通知を取得できることです。

Webhookアプローチを採用する場合、DiscourseでWebhookの「シークレット」フィールドを設定し、Pythonアプリケーションでリクエストを検証してシークレットキーが正しく設定されていることを確認することをお勧めします。まだPythonアプリケーションにWebhookのシークレットを設定するルートを作成したことはありません。WordPressでWebhookのシークレットを検証する方法の詳細はこちらをご覧ください:wp-discourse-custom-webhook-request/wp-discourse-custom-webhook-request.php at master · scossar/wp-discourse-custom-webhook-request · GitHub

「いいね!」 1

ご返信ありがとうございます。大変感謝しております。

DiscourseのWebhookについては調べたことがありませんでした。調べてみます。

「いいね!」 1

編集:私の間違いのようです。タイプ1と2を探しているようです。タイプ2はユーザーへの返信があった場合にトリガーされます。これにより、この投稿は基本的に無関係になります。これをいじっているうちに、次の質問が思い浮かびました。

mentioned は明確で、明確な @Mention があればタイプ == 1 です。

しかし、replied については少し混乱しています。

一般的なボタンのいずれかを使用してトピックに返信すると、返信として入ってきます。理にかなっています。

しかし、ユーザーの特定の投稿への返信ボタンをクリックすると、メンションだと思われるかもしれませんが、通知タイプは依然としてタイプ2です。

This should be a mention type notification

「ユーザーへの返信」通知は、投稿に @Mention がなくても、基本的にメンションとまったく同じなので、タイプ1になるべきではないでしょうか?

参考までに、メタの他の場所には nowhere なので、通知タイプをここに投稿します。おそらく、これらのタイプの通知には新しいタイプ、または単にタイプ1を付けることができるでしょうか?

[1] pry(main)> Notification.types
=> {:mentioned =>1,
 :replied =>2,
 :quoted =>3,
 :edited =>4,
 :liked =>5,
 :private_message =>6,
 :invited_to_private_message =>7,
 :invitee_accepted =>8,
 :posted =>9,
 :moved_post =>10,
 :linked =>11,
 :granted_badge =>12,
 :invited_to_topic =>13,
 :custom =>14,
 :group_mentioned =>15,
 :group_message_summary =>16,
 :watching_first_post =>17,
 :topic_reminder =>18,
 :liked_consolidated =>19,
 :post_approved =>20,
 :code_review_commit_approved =>21,
 :membership_request_accepted =>22,
 :membership_request_consolidated =>23,
 :bookmark_reminder =>24,
 :reaction =>25,
 :votes_released =>26,
 :event_reminder =>27,
 :event_invitation =>28,
 :chat_mention =>29,
 :chat_message =>30,
 :chat_invitation =>31,
 :chat_group_mention =>32,
 :chat_quoted =>33,
 :assigned =>34,
 :question_answer_user_commented =>35,
 :watching_category_or_tag =>36}
「いいね!」 1

そうは思いません。「メンション通知」("notification_type": 1)は、投稿に@ユーザー名が追加された特定のケースを想定しています。直接の返信に同じ通知タイプを使用すると混乱が生じます。

注意すべきエッジケースがあります。ユーザーへの返信にユーザー名が追加された場合、ユーザーに送信される通知は"notification_type": 2ではなく"notification_type": 1になります。たとえば、ここであなたのユーザー名をメンションすると、この投稿はあなたに返信したことを示す通知ではなく、私があなたをメンションしたことを伝える通知をトリガーするはずです:@MarcP

あなた以外のユーザーがこのトピックをウォッチしていた場合、そのユーザーはタイプ9(投稿あり)に設定された通知を受け取ることになります。

「いいね!」 2

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.