Python: Obtener contenido de post si se menciona

Estoy jugando con Python. Para ser específico:

Estoy consultando la documentación de la API:

Discourse API Docs / Discourse API Docs

Soy nuevo (estoy aprendiendo) en Python y estoy intentando simplemente recibir las publicaciones si @UsuarioA es mencionado en algún lugar. Estaba pensando que necesito obtener el post_number de las notificaciones y luego consultar esa publicación, para recuperar y almacenar el contenido de la publicación.

A partir de ahí, quiero almacenar ese contenido de publicación como una variable de datos y, a partir de ahí, experimentar con algunas cosas.

Una parte de mi código es esta:

# buscar menciones
mencion = client.notifications.json.get()

# imprimir las publicaciones
for post_number in mencion:
    print(post_number)

La salida actual de este código:

notifications
total_rows_notifications
seen_notification_id
load_more_notifications

Disculpen si esta es una pregunta estúpida, soy relativamente nuevo con las API y aún más nuevo con Python. He estado trabajando en esto todo el día sin éxito, si alguien puede señalarme la dirección correcta, se lo agradecería mucho.

3 Me gusta

Gracias por publicar el enlace a fluent-discourse.

Actualmente estoy intentando ponerme al día con Python, por lo que es posible que haya mejores maneras de abordar esto que las que describo aquí.

mention = client.notifications.json.get()

Esto devuelve un diccionario de menciones para el username que estableciste al crear el client. Asumo que estableciste el username en UserA al crear el client.

Para confirmar que se está devolviendo un diccionario, puedes ejecutar:

print(type(mention))

Eso debería devolver <class 'dict'>

Puedes ver las claves del diccionario ejecutando:

print(list(mention))

Eso devolverá ['notifications', 'total_rows_notifications', 'seen_notification_id', 'load_more_notifications']

Para tu caso, quieres los valores que se encuentran bajo la clave notifications:

notifications = mention['notifications']

Si luego ejecutas type(notifications), verás que es una lista. Para obtener las notificaciones que fueron activadas por menciones de UserA, necesitas iterar a través de la lista para encontrar entradas donde notification_type esté establecido en 1. La forma más fácil de ver los valores de los tipos de notificación de Discourse es ejecutar Notification.types desde la consola de rails de tu sitio de Discourse:

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

Así que para obtener notificaciones de “mención” para el usuario cuyo nombre de usuario has establecido para el client, intenta algo como esto (estoy probando esto en el intérprete de Python mientras lo escribo):

data = client.notifications.json.get()
notifications = data['notifications']
# Crea un objeto de lista vacío para almacenar las notificaciones de "mención"
mentions = []
# Itera a través de la lista `notifications` para encontrar todas las entradas donde `notification_type` esté establecido en `1`
for notification in notifications:
    if notification['notification_type'] == 1:
        mentions.append(notification)

Eso creará una lista de notificaciones que fueron activadas por menciones. Cada elemento de la lista será un diccionario. Puedes comprobarlo con algo como:

for mention in mentions:
    print(mention['topic_id'], mention['post_number'])
3 Me gusta

Esto es genial. Gracias por la información. No hay mucha información disponible sobre Python x Discourse, así que me alegra aprender, y tal vez esto ayude a otros. Acabo de probar tu código y parece funcionar como se esperaba. Por supuesto, no dejé de jugar, así que encontré una solución para llegar hasta el paso 5, y una forma diferente de obtener los valores que necesitaba hasta una copia en bruto del contenido de la publicación.

Lo que quiero es básicamente esto.

  1. Recibir notificaciones
  2. Obtener números de publicación
  3. Obtener contenido de la publicación
  4. Generar respuesta con OpenAI
  5. Publicar respuesta
  6. Marcar esa misma notificación como leída.
# Configurar un bucle para ejecutar el bot indefinidamente
while True:
    # Obtener acciones del usuario y buscar el ID de la publicación
    data = {
        'username': 'theuser',
        # Para menciones y respuestas, necesito obtener los filtros 6 + 7, pero por alguna razón solo se da 1 respuesta JSON.
        'filter': 6 | 7,
        'limit': 10,
    }

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

    user_actions = unread_mentions['user_actions']

    # Bucle sobre cada mención no leída
    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}')

        # Obtener el contenido de la publicación
        post = client.posts[post_id].json.get()

        # Imprimir el contenido de la publicación
        post_content = post['raw']

        # Generar una respuesta a la publicación
        response = generate_response(post_content)

        # Publicar una respuesta en el foro
        content = {
            'topic_id': topic_id,
            'raw': response + ' @' + str(username)
        }
        make_post = client.posts.json.post(content)

Actualmente tengo dos problemas:

  • Solo se recupera 1 mención. Debo haber olvidado algo, pero aún no he descubierto por qué.
  • Por supuesto, queremos responder a una publicación solo una vez, y como estamos en un bucle, necesitamos algo aquí para evitar esto.
    • Podemos almacenar el post_id en un archivo .txt (no estoy seguro de cuántos datos puede almacenar, creo que puedes manejar bastantes menciones aquí).
    • Mi solución ideal era marcar la notificación como leída. Pero me di cuenta de que en ninguno de nuestros códigos recuperamos menciones no leídas (bueno, lo intenté al principio, recuperando notificaciones no leídas, pero no pude extraer/almacenar la variable post_id que necesitaba usar /posts/get.json y recuperar el contenido “raw”).

Mi objetivo final es alimentar la respuesta con la API de OpenAI. Pero primero necesito encontrar una manera de solucionar los problemas anteriores.

Supongo que lo que quieres hacer es generar una respuesta de OpenAI cuando se menciona a un nombre de usuario determinado (por ejemplo, UserA) en una publicación. Si es así, en lugar de realizar solicitudes a la API de Discourse para obtener las notificaciones, podrías apuntar un webhook de Evento de Notificación de Discourse a tu servidor de aplicación Python. La aplicación Python necesitaría examinar la carga útil del webhook. Si el notification_type de la carga útil estuviera configurado como 1, y su user_id coincidiera con el ID del usuario para el que deseas recibir notificaciones, realizarías una solicitud a la API de Discourse para obtener la publicación que se establece en el campo original_post_id de la carga útil. Luego, enviarías el contenido de la publicación devuelto por esa solicitud a OpenAI.

Aquí tienes un ejemplo de cómo se ve la carga útil para una notificación de mención:

{
  "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"
    }
  }
}

El beneficio de este enfoque es que te permitiría recibir notificaciones en tiempo real, sin tener que realizar un gran número de solicitudes a la API de tu sitio de Discourse.

Si optas por el enfoque del webhook, sería una buena idea configurar el “Secreto” del webhook en Discourse y luego validar la solicitud en tu aplicación Python para asegurarte de que la clave secreta esté correctamente configurada. Aún no he intentado configurar una ruta en una aplicación Python para hacer esto. Los detalles sobre cómo validar un secreto de webhook en WordPress se encuentran aquí: wp-discourse-custom-webhook-request/wp-discourse-custom-webhook-request.php at master · scossar/wp-discourse-custom-webhook-request · GitHub.

1 me gusta

Gracias por tu respuesta, lo aprecio mucho.

Nunca he investigado los webhooks de Discourse. Lo haré.

1 me gusta

EDITAR: Creo que me equivoqué. Parece que estoy buscando los tipos 1 y 2. El tipo 2 se activará si hay una respuesta al usuario. Esto hace que esta publicación sea básicamente irrelevante. Mientras jugaba con esto, surgió la siguiente pregunta:

mentioned es claro como el agua, tipo == 1 si hay una @Mención clara.

Pero para replied estoy un poco confundido.

Cuando respondo al tema, a través de uno de los botones generales, aparece como una respuesta. Tiene sentido.

Pero si haces clic en el botón de respuesta a una publicación específica de un usuario, uno pensaría que es una mención, pero sigue siendo una notificación de tipo 2.

Esta debería ser una notificación de tipo mención

¿No debería una notificación de “respuesta al usuario” obtener el tipo 1? Porque es básicamente lo mismo que una mención, solo que sin la @Mención en la publicación.

Como referencia, ya que no está en ningún otro lugar en meta, publico los tipos de notificación aquí. ¿Quizás estos tipos de notificaciones puedan obtener un nuevo tipo, o simplemente el tipo 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 me gusta

No lo creo. Las notificaciones de mención ("notification_type": 1) están pensadas para el caso específico de cuando se agrega un @nombredeusuario a una publicación. Usar el mismo tipo de notificación para respuestas directas causaría confusión.

Hay un caso extremo a tener en cuenta. Si se agrega un nombre de usuario a una respuesta al tema de un usuario, la notificación que se envía al usuario será "notification_type": 1, no "notification_type": 2. Por ejemplo, al mencionar tu nombre de usuario aquí, esta publicación debería activar una notificación que te diga que te he mencionado, y no una notificación que diga que te he respondido: @MarcP.

Ten en cuenta que si un usuario que no eres tú estuviera siguiendo este tema, recibiría una notificación con su tipo establecido en 9 (publicado).

2 Me gusta

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