Python > Obter conteúdo do post se mencionado

Estou brincando com Python. Para ser específico:

Estou olhando a documentação da API:

Discourse API Docs / Discourse API Docs

Sou novo (estou aprendendo) em Python e estou tentando simplesmente receber as postagens se o @UserA for mencionado em algum lugar. Pensei que precisaria obter o post_number das notificações e, em seguida, consultar essa postagem para recuperar e armazenar o conteúdo da postagem.

A partir daí, quero armazenar esse conteúdo de postagem como uma variável de dados e, a partir daí, experimentar algumas coisas.

Uma parte do meu código é esta:

# procurar menções
mention = client.notifications.json.get()

# imprimir as postagens
for post_number in mention:
    print(post_number)

A saída atual deste código:

notifications
total_rows_notifications
seen_notification_id
load_more_notifications

Desculpe se esta for uma pergunta estúpida, sou relativamente novo em APIs e ainda mais novo em Python. Tenho trabalhado nisso o dia todo sem sucesso, se alguém puder me apontar na direção certa, isso seria muito apreciado.

3 curtidas

Obrigado por postar o link para o fluent-discourse!

Estou atualmente tentando me atualizar em Python, então é possível que existam maneiras melhores de abordar isso do que o que estou descrevendo aqui.

mention = client.notifications.json.get()

Isso está retornando um dicionário de menções para o username que você definiu ao criar o client. Estou assumindo que você definiu o username como UserA ao criar o client.

Para confirmar que um dicionário está sendo retornado, você pode executar:

print(type(mention))

Isso deve retornar <class 'dict'>

Você pode ver as chaves do dicionário executando:

print(list(mention))

Isso retornará ['notifications', 'total_rows_notifications', 'seen_notification_id', 'load_more_notifications']

Para o seu caso, você quer os valores que são encontrados sob a chave notifications:

notifications = mention['notifications']

Se você então executar type(notifications), verá que é uma lista. Para obter notificações que foram acionadas por menções de UserA, você precisa iterar pela lista para encontrar entradas onde o notification_type está definido como 1. A maneira mais fácil de ver os valores para os tipos de notificação do Discourse é executar Notification.types do console rails do seu site Discourse:

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

Portanto, para obter notificações de "menção" para o usuário cujo nome de usuário você definiu para o client, tente algo como isto (estou testando isso no interpretador Python enquanto digito):

data = client.notifications.json.get()
notifications = data['notifications']
# Cria um objeto de lista vazio para armazenar notificações de "menção"
mentions = []
# Itera pela lista `notifications` para encontrar todas as entradas onde `notification_type` é definido como `1`
for notification in notifications:
    if notification['notification_type'] == 1:
        mentions.append(notification)

Isso criará uma lista de notificações que foram acionadas por menções. Cada item na lista será um dicionário. Você pode verificá-lo com algo como:

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

Isto é ótimo. Obrigado pelas informações. Não há muitas informações sobre Python x Discourse disponíveis por aqui, então fico feliz em aprender, e talvez isso ajude outras pessoas. Acabei de testar seu código e ele parece funcionar como esperado. Claro, não parei de jogar, então encontrei uma solução alternativa para chegar até a etapa 5 e uma maneira diferente de obter os valores que precisava até uma cópia bruta do conteúdo da postagem.

O que eu quero é basicamente isto.

  1. Receber notificações
  2. Obter números de postagem
  3. Obter conteúdo da postagem
  4. Gerar resposta com OpenAI
  5. Postar resposta
  6. Marcar essa mesma notificação como lida?
# Configurar um loop para executar o bot indefinidamente
while True:
    # Obter ações do usuário e buscar ID da postagem    
    data = {
    'username': 'theuser',
    # Para menções e respostas, preciso obter os filtros 6 + 7, mas por algum motivo apenas 1 resposta JSON é dada.
    'filter': 6 | 7,
    'limit': 10,
    }
    
    unread_mentions = client.user_actions.json.get(data)
    print(unread_mentions)

    user_actions = unread_mentions['user_actions']

    # Loop sobre cada menção não lida
    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}')
    
        # Obter o conteúdo da postagem   
        post = client.posts[post_id].json.get()

        # Imprimir o conteúdo da postagem
        post_content = post['raw']

        # Gerar uma resposta para a postagem
        response = generate_response(post_content)
    
        # Postar uma resposta no fórum
        content = {
            'topic_id': topic_id,
            'raw': response + ' @' + str(username)
        }
        make_post = client.posts.json.post(content)

Atualmente estou tendo dois problemas:

  • Apenas 1 menção é buscada. Devo ter esquecido algo, mas ainda não descobri o porquê.
  • Claro, queremos responder a uma postagem apenas uma vez, e como estamos em loop, precisamos de algo aqui para evitar isso.
    • Podemos armazenar o post_id em um arquivo .txt (não tenho certeza de quantos dados isso pode armazenar, acho que você pode lidar com muitas menções aqui.
    • Minha solução ideal era marcar a notificação como lida. Mas percebi que em nenhum dos nossos códigos estamos buscando menções não lidas (bem, tentei no início, buscando notificações não lidas, mas não consegui extrair/armazenar a variável post_id que eu precisava usar /posts/get.json e buscar o conteúdo “raw”).

Meu objetivo final é alimentar a resposta com a API OpenAI. Mas primeiro preciso encontrar uma maneira de resolver os problemas acima.

Presumo que o que você deseja fazer é gerar uma resposta da OpenAI quando um determinado nome de usuário (por exemplo, UserA) for mencionado em uma postagem. Se isso estiver correto, em vez de fazer solicitações de API para o Discourse para obter as notificações, você pode apontar um webhook de Evento de Notificação do Discourse para o servidor do seu aplicativo Python. O aplicativo Python precisaria analisar a carga útil do webhook. Se o notification_type da carga útil estivesse definido como 1 e seu user_id correspondesse ao ID do usuário para o qual você deseja receber notificações, você faria uma solicitação de API para o Discourse para obter a postagem que está definida no campo original_post_id da carga útil. Em seguida, envie o conteúdo da postagem retornado dessa solicitação para a OpenAI.

Aqui está um exemplo de como se parece a carga útil para uma notificação de menção:

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

O benefício dessa abordagem é que ela permitiria que você recebesse notificações em tempo real - sem ter que fazer um grande número de solicitações de API para o seu site Discourse.

Se você optar pela abordagem de webhook, seria uma boa ideia definir o campo “Secret” do webhook no Discourse e, em seguida, validar a solicitação em seu aplicativo Python para garantir que a chave secreta esteja corretamente definida. Eu ainda não tentei configurar uma rota em um aplicativo Python para fazer isso. Detalhes sobre como validar o Secret de um webhook no WordPress estão aqui: wp-discourse-custom-webhook-request/wp-discourse-custom-webhook-request.php at master · scossar/wp-discourse-custom-webhook-request · GitHub.

1 curtida

Obrigado pela sua resposta, eu aprecio muito.

Eu nunca olhei para os webhooks do Discourse. Vou verificar isso.

1 curtida

EDIT: Acho que estou enganado. Parece que estou procurando os tipos 1 e 2. O tipo 2 será acionado se houver uma resposta ao usuário. Isso torna esta postagem basicamente irrelevante. Ao brincar com isso, a seguinte pergunta surgiu:

mentioned é autoexplicativo, tipo == 1 se houver uma @Menção clara

Mas para replied estou meio confuso.

Quando respondo ao tópico, através de um dos botões gerais, ele entra como uma resposta. Faz sentido.

Mas se você clicar no botão de resposta para uma postagem específica de um usuário, alguém pensaria que é uma menção, mas ainda é uma notificação do tipo 2.

Esta deveria ser uma notificação do tipo menção

Uma notificação de “resposta ao usuário” não deveria ser do tipo 1? Porque é basicamente a mesma coisa que uma menção, apenas sem a @Menção na postagem.

Como referência, já que não está em nenhum outro lugar no meta, estou postando os tipos de notificação aqui. Talvez esses tipos de notificações possam receber um novo tipo, ou apenas o 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 curtida

Eu não acho. Notificações de menção ("notification_type": 1) são para o caso específico de quando um @username é adicionado a uma postagem. Usar o mesmo tipo de notificação para respostas diretas causaria confusão.

Há um caso extremo a ser observado. Se um nome de usuário for adicionado a uma resposta ao tópico de um usuário, a notificação enviada ao usuário será "notification_type": 1, e não "notification_type": 2. Por exemplo, ao mencionar seu nome de usuário aqui, esta postagem deve acionar uma notificação dizendo que eu o mencionei, e não uma notificação dizendo que respondi a você: @MarcP.

Note que se um usuário diferente de você estivesse acompanhando este tópico, ele receberia uma notificação com seu tipo definido como 9 (postado).

2 curtidas

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