Discourse AI + Data Explorer ?

J’ai décidé que je voulais une requête particulière aujourd’hui. Ne voulant pas déranger mes ingénieurs (trop), j’ai décidé de demander à ChatGPT d’écrire une requête d’explorateur de données pour moi en fonction de ce que je savais, et de ce que je savais que je voulais. J’ai été assez époustouflé qu’il ait tout fait correctement (à part ajouter un point-virgule à la fin qu’il n’aurait pas dû).\n\nVoici la requête qu’il a construite pour moi lorsque je lui ai donné quelques paramètres et que je lui ai demandé de me construire une requête qui me donnait un total cumulé du nombre de tous les utilisateurs par mois :\n\nsql\nSELECT \n timeframe \"Mois, Année\",\n user_count as \"Utilisateurs inscrits ce mois-ci\",\n SUM(user_count) OVER (ORDER BY TO_DATE(timeframe, 'Month, YYYY'))::integer as \"Utilisateurs (Total cumulé)\"\nFROM (\n SELECT \n TO_CHAR(u.created_at, 'Month, YYYY') as \"timeframe\",\n count(u.id) as \"user_count\"\n FROM \n users u\n GROUP BY \n timeframe\n ORDER BY\n timeframe\n) subquery\nORDER BY \n TO_DATE(timeframe, 'Month, YYYY')\n\n\nLa possibilité d’intégrer l’IA dans la zone d’exploration de données a-t-elle été envisagée ? :slight_smile:

12 « J'aime »

Un message a été divisé en un nouveau sujet : Pourrions-nous rouvrir le sujet pour partager des requêtes Explorer ?

Voulez-vous partager l’invite, la version de ChatGPT et le modèle utilisé avec ChatGPT. :slightly_smiling_face:

Par exemple


ChatGPT Version d’août 3
Modèle : GPT-3.5
Invite

Qu’est-ce que Discourse Data Explorer ?

Complétion

D’après ma dernière mise à jour en septembre 2021, il n’existe aucun outil ou produit spécifique appelé « Discourse Data Explorer » dont j’aie connaissance. Cependant, je peux fournir une explication générale basée sur les informations disponibles jusqu’à cette date.

Discourse est un logiciel de forum moderne et open-source qui permet aux communautés en ligne d’avoir des discussions et des interactions. Il est largement utilisé pour héberger des discussions, des forums de questions-réponses et des communautés de support. Discourse offre un riche ensemble de fonctionnalités pour gérer les discussions, l’engagement des utilisateurs et la modération.

Un « Data Explorer » (explorateur de données) fait généralement référence à un outil ou une fonctionnalité qui permet aux utilisateurs d’interroger et d’explorer des données au sein d’un système ou d’une plateforme. Il est souvent utilisé dans le contexte des bases de données ou des plateformes d’analyse de données.

Compte tenu des deux composantes, « Discourse Data Explorer » pourrait potentiellement être un outil ou un plugin hypothétique qui permet aux utilisateurs d’explorer et d’interroger des données au sein d’un forum Discourse. Cela pourrait être utile pour les administrateurs de communauté ou les analystes de données qui souhaitent obtenir des informations sur le comportement des utilisateurs, les tendances de contenu ou d’autres métriques liées aux discussions qui ont lieu sur le forum.

Il est important de noter que mes informations peuvent être obsolètes et que de nouveaux développements ont pu survenir après ma dernière mise à jour. Si « Discourse Data Explorer » est effectivement un produit ou une fonctionnalité réelle, je vous recommande de rechercher les informations les plus récentes pour obtenir des détails précis sur ses capacités et son utilisation.


La raison de cette demande est que vous avez une excellente idée et qu’il était agréable de la voir partagée, mais à l’avenir, d’autres pourraient essayer de poser une autre invite, et le partage de l’invite, de la complétion et des détails de ChatGPT est nécessaire si une aide est nécessaire pour comprendre d’éventuels problèmes.

Remarque : Je suis modérateur de catégorie sur le forum OpenAI Discourse, j’ai donc beaucoup d’expérience avec ceux qui cherchent de l’aide pour les invites ChatGPT. (ref)


La version de ChatGPT se trouve en bas à droite, sous l’endroit où une invite est saisie

Le modèle se trouve près du haut de la page, au milieu

image

1 « J'aime »

Je…n’aime pas ce bot.

1 « J'aime »

Pour étendre cette idée, permettre aux utilisateurs d’interagir avec des applications en langage naturel est à peu près mon rêve en matière d’IA. Avec Discourse et le plugin Data Explorer, il serait possible d’obtenir des résultats à partir d’invites comme “renvoyer une liste d’utilisateurs qui ont exprimé leur intérêt pour la modération”. Ou encore mieux, “envoyer une invitation au groupe community_moderation à tous les utilisateurs qui ont exprimé leur intérêt pour la modération”.

Pour revenir à ce qui est possible maintenant :

En testant avec ChatGPT 3.0 et 3.5, j’ai obtenu de bons résultats en lui demandant de renvoyer une requête PostgreSQL et en copiant la structure des tables qui m’intéressent dans l’invite. Par exemple :

Résumé

Moi : Renvoyer une requête postgresql qui liste tous les noms d’utilisateur des utilisateurs qui font partie du groupe “community_moderators” pour la structure de base de données suivante :

# == Schema Information
#
# Table name: groups
#
#  id                                 :integer          not null, primary key
#  name                               :string           not null

# == Schema Information
#
# Table name: group_users
#
#  id                 :integer          not null, primary key
#  group_id           :integer          not null

# == Schema Information
#
# Table name: users
#
#  id                        :integer          not null, primary key
#  username                  :string(60)       not null

ChatGPT 3.5 : Bien sûr, voici une requête PostgreSQL qui liste tous les noms d’utilisateur des utilisateurs qui font partie du groupe “community_moderators” en fonction de la structure de base de données donnée :

SELECT u.username
FROM users u
JOIN group_users gu ON u.id = gu.user_id
JOIN groups g ON gu.group_id = g.id
WHERE g.name = 'community_moderators';

Cette requête récupère les noms d’utilisateur de la table users en la joignant avec la table group_users sur l’ID utilisateur, puis en la joignant avec la table groups sur l’ID de groupe. Elle filtre les résultats pour n’inclure que les noms d’utilisateur des utilisateurs qui font partie du groupe “community_moderators”.

Moi : Voici la structure des tables de sujets et de messages de l’application :

# == Schema Information
#
# Table name: topics
#
#  id                        :integer          not null, primary key
#  title                     :string           not null

# == Schema Information
#
# Table name: posts
#
#  id                      :integer          not null, primary key
#  user_id                 :integer
#  topic_id                :integer          not null
#  post_number             :integer          not null
#  raw                     :text             not null

Renvoyer une requête qui liste tous les ID de sujets, ID de messages et noms d’utilisateur pour tous les messages créés par des membres du groupe “community_moderators” qui indiquent un intérêt pour la manière de modérer des discussions polarisantes.

ChatGPT 3.5 : Pour y parvenir, vous devrez joindre les tables posts, topics, users et group_users en fonction du schéma fourni. Voici une requête PostgreSQL qui récupère les informations demandées :

SELECT t.id AS topic_id, p.id AS post_id, u.username
FROM posts p
JOIN topics t ON p.topic_id = t.id
JOIN users u ON p.user_id = u.id
JOIN group_users gu ON u.id = gu.user_id
JOIN groups g ON gu.group_id = g.id
WHERE g.name = 'community_moderators'
  AND (p.raw ILIKE '%moderate%' OR p.raw ILIKE '%polarizing%' OR p.raw ILIKE '%discussion%');

Cette requête récupère l’topic_id, le post_id et le username pour tous les messages créés par des membres du groupe “community_moderators” qui contiennent certains mots-clés indiquant un intérêt pour la modération de discussions polarisantes. L’opérateur ILIKE est utilisé pour la correspondance de motifs insensible à la casse dans la colonne raw de la table posts.

Veuillez noter que cette requête suppose que les mots-clés que vous avez fournis sont indicatifs des messages souhaités. Vous pourriez avoir besoin d’ajuster ou d’étendre les mots-clés en fonction de vos critères spécifiques.

Moi : Écrire une requête qui renvoie un décompte des messages créés dans chaque période hebdomadaire depuis septembre 2022, créés par des membres du groupe community_moderators qui indiquent un certain intérêt pour la manière de modérer des discussions polarisantes.

ChatGPT 3.5 : Pour y parvenir, vous pouvez utiliser la requête PostgreSQL suivante pour renvoyer un décompte des messages créés dans chaque période hebdomadaire depuis septembre 2022, créés par des membres du groupe “community_moderators” qui indiquent un intérêt pour la manière de modérer des discussions polarisantes :

SELECT
    DATE_TRUNC('week', p.created_at) AS week_start,
    COUNT(p.id) AS post_count
FROM
    posts p
JOIN
    users u ON p.user_id = u.id
JOIN
    group_users gu ON u.id = gu.user_id
JOIN
    groups g ON gu.group_id = g.id
WHERE
    g.name = 'community_moderators'
    AND (p.raw ILIKE '%moderate%'
         OR p.raw ILIKE '%polarizing%'
         OR p.raw ILIKE '%political%'
         OR p.raw ILIKE '%contentious%'
         OR p.raw ILIKE '%debate%'
         OR p.raw ILIKE '%controversial%'
         OR p.raw ILIKE '%discussion%')
    AND p.created_at >= '2022-09-01' -- Date de début : septembre 2022
GROUP BY
    week_start
ORDER BY
    week_start;

Cette requête calcule le nombre de messages créés par des membres du groupe “community_moderators” qui contiennent les mots-clés spécifiés dans chaque période hebdomadaire depuis septembre 2022. Elle regroupe les résultats par semaine et les trie chronologiquement. Veuillez vous assurer d’ajuster les noms de colonnes et les relations de table en fonction du schéma réel de votre base de données.


Les résultats me semblent bons et représentent le type de requêtes que j’ai mis beaucoup de temps à écrire par le passé. Je suppose qu’il serait possible d’entraîner un modèle sur la structure de la base de données Discourse afin que les détails sur la structure puissent être omis des invites.

4 « J'aime »

oh c’est génial, j’ai eu des résultats mitigés avec les requêtes SQL de l’explorateur de données de chatGPT, mais faire cela a tellement de sens. je n’avais même pas pensé à fournir la structure des tables et à demander des requêtes PostgreSQL. :woman_facepalming:t2: merci pour le tuyau @simon :slight_smile:

1 « J'aime »

Existe-t-il un endroit où je peux voir un schéma complet des bases de données de discourse ?

1 « J'aime »

Salut @so-jordan-violet, j’utilise juste l’outil de tableau déroulant (je ne sais pas comment il s’appelle ! lol) sur le côté droit dans l’interface d’édition de requête de l’explorateur de données :

2 « J'aime »

Si nous pouvons obtenir un document textuel (surtout s’il est au format sql create table), nous pourrions le fournir comme instructions et obtenir probablement des résultats assez fiables.

1 « J'aime »

Oui, nous avons cet élément dans le backlog de l’équipe IA depuis le début de l’année. L’idée est d’ingérer la totalité (ou la partie importante) du schéma Discourse dans l’invite pour lui permettre de créer n’importe quelle requête.

Nous avons construit GitHub - discourse/data-explorer-examples: Examples for Discourse Data Explorer pour aider à fournir des exemples au modèle, afin qu’il soit mieux ancré.

7 « J'aime »

J’aurais aimé avoir plus de temps pour examiner la base de code, mais avez-vous le SQL stocké quelque part (publiquement) pour les schémas de table crest ?

Je travaille actuellement sur des LLM avec mon propre produit/entreprise et j’aimerais jouer avec ça.

1 « J'aime »

Oh, c’est génial. Merci pour le lien Falco ! :slight_smile:

3 « J'aime »

Je génère cela directement à partir du schéma

Quelque chose comme ceci devrait vous aider à démarrer :


J’ai exploré toutes sortes d’approches pour y parvenir. Un problème cependant est que GPT 3.5 est tellement orientable qu’il se perd.

Lui donner un schéma aide certainement, mais je constate que je dois être ultra stratégique avec les exemples.

Le simple fait de lui raconter une histoire sur « comment compter les sujets archivés pour un utilisateur » conduit à orienter une requête telle que « combien de messages un utilisateur a-t-il eu » vers les sujets archivés.

Je pensais :

graph TD
A[Ajouter des informations génériques utiles] --> B[Générer des embeddings pour la question]
B --> C[Effectuer une recherche de similarité parmi les exemples]
C --> D[Ajouter 3 exemples à l'invite]
D --> E[Ajouter le schéma à l'invite]
E --> F[Poser la question]
F --> G[Obtenir le SQL]

Mais il s’avère que, à moins que les exemples ne soient spectaculaires et que vous n’incluiez aucun contre-exemple… les choses tournent mal.

Je commence à penser que le mieux que nous ayons pour l’instant est de lui donner le schéma et un préambule. Peut-être ajouter une autre étape à la fin pour la validation et la nouvelle tentative de requête.

5 « J'aime »

Auriez-vous un schéma complet qui montre les types de données ?

Je ne suis pas sûr que cela rentre dans le budget de jetons, j’essaierai

With ChatCPT 3.5 I’m getting unexpected results when I provide the full schema. For example, it keeps trying to find the topic author in the topic_users table.

I get successful results by limiting the information in the prompt to the tables and columns that are required to write the query. Also by adding some additional information about how the columns are used. For example:

# Table name: user_actions
#
#  id              :integer          not null, primary key
#  action_type     :integer          not null (:like=>1,:was_liked=>2,:new_topic=>4,:reply=>5,:response=>6,:mention=>7,:quote=>9,:edit=>11,:new_private_message=>12,:got_private_message=>13,:solved=>15,:assigned=>16)
#  user_id         :integer          not null (the user who is to be credited with the action)
#  target_topic_id :integer
#  acting_user_id  :integer (the user who performed the action, for example, a staff user can perform an action on behalf of a regular user)
#  created_at      :datetime         not null

Another way to look at getting this to work with the Data Explorer plugin would be to have users fill out a dynamically generate form that lists the data they are looking for, and what conditions they want to apply to the data. The prompt could be generated programmatically by Discourse, then sent to the LLM to have the query written.

Edit: @jordan-violet, this might be a useful starting point. Here’s an annotated partial schema that’s working for me. It works well as long as I limit my queries so that they can be answered by the provided schema. I’ve added additional details to the schema to clarify details that seem to confuse ChatGPT. The obvious downside of this approach is that a fully annotated schema will exceed ChatGPT 3.5’s token limit. I’ve included some information in the schema that could be omitted to reduce the number of tokens that are used.

Summary
# == Schema Information
#
# Table name: application_requests
#
#  id       :integer          not null, primary key
#  date     :date             not null
#  req_type :integer          not null ("http_total"=>0,"http_2xx"=>1,"http_background"=>2,"http_3xx"=>3,"http_4xx"=>4,"http_5xx"=>5,"page_view_crawler"=>6,"page_view_logged_in"=>7,"page_view_anon"=>8,"page_view_logged_in_mobile"=>9,"page_view_anon_mobile"=>10,"api"=>11,"user_api"=>12)
#  count    :integer          default(0), not null
#
# Table name: users
#
#  id                        :integer          not null, primary key
#  username                  :string(60)       not null
#  created_at                :datetime         not null
#  updated_at                :datetime         not null
#  name                      :string           (the user's real name)
#  last_posted_at            :datetime
#  active                    :boolean          default(FALSE), not null
#  username_lower            :string(60)       not null
#  last_seen_at              :datetime
#  admin                     :boolean          default(FALSE), not null
#  trust_level               :integer          not null
#  approved                  :boolean          default(FALSE), not null
#  approved_by_id            :integer
#  approved_at               :datetime
#  previous_visit_at         :datetime
#  suspended_at              :datetime
#  suspended_till            :datetime
#  date_of_birth             :date
#  ip_address                :inet
#  moderator                 :boolean          default(FALSE)
#  title                     :string
#  locale                    :string(10)
#  primary_group_id          :integer
#  registration_ip_address   :inet
#  staged                    :boolean          default(FALSE), not null
#  first_seen_at             :datetime
#  silenced_till             :datetime
#
# Table name: topics
#
#  id                        :integer          not null, primary key
#  title                     :string           not null
#  last_posted_at            :datetime
#  created_at                :datetime         not null
#  updated_at                :datetime         not null
#  views                     :integer          default(0), not null
#  posts_count               :integer          default(0), not null
#  user_id                   :integer          (the id of the user who created the topic)
#  last_post_user_id         :integer          not null (the id of the user who created the last post in the topic)
#  reply_count               :integer          default(0), not null
#  deleted_at                :datetime
#  highest_post_number       :integer          default(0), not null
#  like_count                :integer          default(0), not null
#  category_id               :integer
#  visible                   :boolean          default(TRUE), not null
#  moderator_posts_count     :integer          default(0), not null
#  closed                    :boolean          default(FALSE), not null
#  archived                  :boolean          default(FALSE), not null
#  bumped_at                 :datetime         not null
#  archetype                 :string           default("regular"), not null (can be set to either "regular" or "private_message")
#  slug                      :string
#  deleted_by_id             :integer          (the id of the user who deleted the topic)
#  participant_count         :integer          default(1)
#  word_count                :integer
#  excerpt                   :string
#  highest_staff_post_number :integer          default(0), not null
#
# Table name: posts
#
#  id                      :integer          not null, primary key
#  user_id                 :integer          (the id of the user who created the post)
#  topic_id                :integer          not null
#  post_number             :integer          not null (indicates the post's order in its topic)
#  raw                     :text             not null (the post's content)
#  created_at              :datetime         not null
#  updated_at              :datetime         not null
#  reply_to_post_number    :integer          (the post_number that the post is a reply to)
#  reply_count             :integer          default(0), not null
#  deleted_at              :datetime
#  like_count              :integer          default(0), not null
#  bookmark_count          :integer          default(0), not null
#  reads                   :integer          default(0), not null (the number of times the post has been read)
#  post_type               :integer          default(1), not null (:regular=>1, :moderator_action=>2, :small_action=>3, :whisper=>4)
#  last_editor_id          :integer          (the id of the user who last edited the post)
#  hidden                  :boolean          default(FALSE), not null
#  hidden_reason_id        :integer          (:flag_threshold_reached=>1,:flag_threshold_reached_again=>2,:new_user_spam_threshold_reached=>3,:flagged_by_tl3_user=>4,:email_spam_header_found=>5,:flagged_by_tl4_user=>6,:email_authentication_result_header=>7,:imported_as_unlisted=>8)
#  edit_reason             :string
#  word_count              :integer
#  wiki                    :boolean          default(FALSE), not null
#
# Table name: categories
#
#  id                                        :integer          not null, primary key
#  name                                      :string(50)       not null
#  topic_id                                  :integer          (the id of the topic that is used for the category's description)
#  topic_count                               :integer          default(0), not null
#  created_at                                :datetime         not null
#  updated_at                                :datetime         not null
#  user_id                                   :integer          not null (the id of the user who created the topic)
#  topics_year                               :integer          default(0)
#  topics_month                              :integer          default(0)
#  topics_week                               :integer          default(0)
#  slug                                      :string           not null
#  description                               :text
#  text_color                                :string(6)        default("FFFFFF"), not null
#  read_restricted                           :boolean          default(FALSE), not null
#  auto_close_hours                          :float
#  post_count                                :integer          default(0), not null
#  latest_post_id                            :integer
#  latest_topic_id                           :integer
#  position                                  :integer
#  parent_category_id                        :integer
#  posts_year                                :integer          default(0)
#  posts_month                               :integer          default(0)
#  posts_week                                :integer          default(0)
#  topics_day                                :integer          default(0)
#  posts_day                                 :integer          default(0)
#
# Table name: groups
#
#  id                                 :integer          not null, primary key
#  name                               :string           not null
#  created_at                         :datetime         not null
#  automatic                          :boolean          default(FALSE), not null
#  user_count                         :integer          default(0), not null
#  title                              :string
#  bio_raw                            :text             (the group's description)
#  allow_membership_requests          :boolean          default(FALSE), not null
#  full_name                          :string
#  visibility_level                   :integer          default(0), not null (who can see the group :public=>0, :logged_on_users=>1, :members=>2, :staff=>3, :owners=>4)
#  messageable_level                  :integer          default(0) (who can message the group :public=>0, :logged_on_users=>1, :members=>2, :staff=>3, :owners=>4)
#  mentionable_level                  :integer          default(0) (who can mention the group :public=>0, :logged_on_users=>1, :members=>2, :staff=>3, :owners=>4)
#  members_visibility_level           :integer          default(0), not null (who see the group's members :public=>0, :logged_on_users=>1, :members=>2, :staff=>3, :owners=>4)
#
# Table name: group_users
#
#  id                 :integer          not null, primary key
#  group_id           :integer          not null
#  user_id            :integer          not null
#  created_at         :datetime         not null
#
# Table name: user_actions
#
#  id              :integer          not null, primary key
#  action_type     :integer          not null (:like=>1,:was_liked=>2,:new_topic=>4,:reply=>5,:response=>6,:mention=>7,:quote=>9,:edit=>11,:new_private_message=>12,:got_private_message=>13,:solved=>15,:assigned=>16)
#  user_id         :integer          not null (the user who is to be credited with the action)
#  target_topic_id :integer
#  target_post_id  :integer
#  target_user_id  :integer          (for example, the id of the user whose post was liked)
#  acting_user_id  :integer          (the user who performed the action, for example, a staff user can perform an action on behalf of a regular user)
#  created_at      :datetime         not null
#  updated_at      :datetime         not null
#
# Table name: topic_views
#
#  topic_id   :integer          not null
#  viewed_at  :date             not null
#  user_id    :integer         (will be set if the topic was viewed by a logged in user)
#  ip_address :inet            (will be set if the topic was viewed by an anonymous user)
#
# Table name: user_visits
#
#  id         :integer          not null, primary key
#  user_id    :integer          not null
#  visited_at :date             not null
#  posts_read :integer          default(0)
#  mobile     :boolean          default(FALSE) (will be set to TRUE if the user visited on a mobile device)
#  time_read  :integer          default(0), not null (the value returned is the number of seconds of the visit)

Here’s a link to a chat session where I tried it out: https://chat.openai.com/share/d108c104-3aa3-45d9-9161-6da21d5b3a77

If you want to try expanding on this list, the easiest way to do it is to copy the schema from the bottom of the model you’re interested in, directly from the Discourse code: discourse/app/models at main · discourse/discourse · GitHub.

3 « J'aime »

Ce serait formidable d’obtenir exactement cela, mais une liste complète de chaque table. D’où tenez-vous cela ?

EDIT : Ah, je vois votre lien en bas, désolé. Je n’aurai probablement pas le temps de tout rassembler. J’espérais qu’il y ait un schéma SQL maître quelque part :confused:

Le problème est que le simple fait de fournir le schéma ne suffit pas pour ChatGPT. Vous devez lui fournir des détails sur des éléments tels que :

  • ce que représentent les codes entiers de req_type dans application_requests
  • à quoi sert la colonne user_id dans topics
  • ce que représentent les codes de action_type dans la table user_actions et quelle est la différence entre les colonnes user_id, target_user_id et acting_user_id de cette table

Avec ces types de détails, GPT 3.5 semble faire un bon travail sans formation supplémentaire. Le problème devient alors que la fourniture de ce niveau de détail sur l’ensemble de la base de données entraînera le dépassement de la limite de jetons de ChatGPT (4096 jetons, incluant le texte du prompt et la sortie générée). Si ce type d’approche était utilisé, il faudrait un moyen de limiter ce qui est inclus dans le prompt en fonction des informations que l’utilisateur souhaitait obtenir de la requête Data Explorer.

1 « J'aime »

Ce n’est pas du tout mon expérience. J’ai eu une expérience plutôt agréable avec ce soir. Je partagerai quelques résultats plus tard.

Cela me donne le sentiment d’un rôle compétent, mais très d’entrée de gamme/junior. Il fait les choses de près, je lui dis ce qu’il a mal fait et il le corrige. Répéter.

J’apprécie vraiment ce qu’il me donne, et le temps qu’il me fait gagner compte tenu de mon utilisation ce soir.

1 « J'aime »

GPT 3.5 gère très bien le 16k aujourd’hui

Les problèmes commencent à survenir lorsque les requêtes sont compliquées, prenant en compte les cas limites, etc.

1 « J'aime »