Quellcode durchsuchen

Démarrage : message « En ligne » plus soigné, passage en 5.12

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet vor 2 Tagen
Ursprung
Commit
20cccc0ca3
4 geänderte Dateien mit 36 neuen und 7 gelöschten Zeilen
  1. 9 1
      CHANGELOG.md
  2. 1 1
      bot/__init__.py
  3. 13 5
      bot/discord_bot.py
  4. 13 0
      bot/models.py

+ 9 - 1
CHANGELOG.md

@@ -2,7 +2,15 @@
 
 
 Les versions les plus récentes sont en haut. Chaque entrée commence par un résumé en gras, suivi du détail.
 Les versions les plus récentes sont en haut. Chaque entrée commence par un résumé en gras, suivi du détail.
 
 
-**Versions :** [5.11](#version-511) · [5.10](#version-510) · [5.9](#version-59) · [5.8](#version-58) · [5.7](#version-57) · [5.6](#version-56) · [5.5](#version-55) · [5.4.0](#version-540) · [5.3.0](#version-530) · [5.2.0](#version-520) · [5.1.0](#version-510-1) · [5.0.0](#version-500)
+**Versions :** [5.12](#version-512) · [5.11](#version-511) · [5.10](#version-510) · [5.9](#version-59) · [5.8](#version-58) · [5.7](#version-57) · [5.6](#version-56) · [5.5](#version-55) · [5.4.0](#version-540) · [5.3.0](#version-530) · [5.2.0](#version-520) · [5.1.0](#version-510-1) · [5.0.0](#version-500)
+
+---
+
+## Version 5.12
+
+### Changements
+
+- **Un message de démarrage plus soigné.** Le bloc « Bot en ligne » affiche maintenant l'avatar du bot, sa version, le modèle Claude utilisé (« Sonnet 5.5 ») et l'heure du démarrage, sur le vert du statut « en ligne » de Discord.
 
 
 ---
 ---
 
 

+ 1 - 1
bot/__init__.py

@@ -1,3 +1,3 @@
 """Chatbot Discord propulsé par Claude."""
 """Chatbot Discord propulsé par Claude."""
 
 
-VERSION = "5.11"
+VERSION = "5.12"

+ 13 - 5
bot/discord_bot.py

@@ -25,7 +25,7 @@ from .images import ImageError, prepare_image
 from .members import MemberRegistry, with_username
 from .members import MemberRegistry, with_username
 from .memory import DATE_FORMAT, MemoryStore
 from .memory import DATE_FORMAT, MemoryStore
 from .memory_views import MemoryCard, member_target, reply_error, see_user, server_target
 from .memory_views import MemoryCard, member_target, reply_error, see_user, server_target
-from .models import is_known
+from .models import display_name, is_known
 from .pdf_files import PDF_EXTENSIONS, PDF_MAX_BYTES, PdfError, prepare_pdf
 from .pdf_files import PDF_EXTENSIONS, PDF_MAX_BYTES, PdfError, prepare_pdf
 from .presence import PresenceManager, Status
 from .presence import PresenceManager, Status
 from .text_files import TEXT_EXTENSIONS, TEXT_FILE_MAX_BYTES, TextFileError, decode_text_file
 from .text_files import TEXT_EXTENSIONS, TEXT_FILE_MAX_BYTES, TextFileError, decode_text_file
@@ -36,6 +36,8 @@ logger = logging.getLogger("chatbot.discord")
 CUSTOM_EMOJI_ONLY = re.compile(r"^<a?:\w+:\d+>$")
 CUSTOM_EMOJI_ONLY = re.compile(r"^<a?:\w+:\d+>$")
 USER_MENTION = re.compile(r"<@!?(\d+)>")
 USER_MENTION = re.compile(r"<@!?(\d+)>")
 IMAGE_EXTENSIONS = (".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".tif", ".tiff")
 IMAGE_EXTENSIONS = (".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".tif", ".tiff")
+# Couleur du message de démarrage : le vert du statut « en ligne » de Discord.
+ONLINE_COLOR = discord.Color(0x23A55A)
 # Longueur maximale du texte d'un message cité ou transféré transmis à Claude.
 # Longueur maximale du texte d'un message cité ou transféré transmis à Claude.
 QUOTE_MAX_LENGTH = 500
 QUOTE_MAX_LENGTH = 500
 # Messages écrits par quelqu'un ; les autres types sont des messages système
 # Messages écrits par quelqu'un ; les autres types sont des messages système
@@ -243,14 +245,20 @@ class ChatBot(commands.Bot):
             logger.warning("Le bot est aussi sur %d autre(s) serveur(s), où il ne répond pas : %s. Retire-le de ces "
             logger.warning("Le bot est aussi sur %d autre(s) serveur(s), où il ne répond pas : %s. Retire-le de ces "
                            "serveurs, et décoche Public Bot dans le portail Discord (voir le README).", len(others),
                            "serveurs, et décoche Public Bot dans le portail Discord (voir le README).", len(others),
                            ", ".join(f"{guild.name} ({guild.id})" for guild in others))
                            ", ".join(f"{guild.name} ({guild.id})" for guild in others))
-        name = channel.guild.me.display_name if getattr(channel, "guild", None) else self.user.name
+        me = channel.guild.me if getattr(channel, "guild", None) else self.user
         logger.info("%d emoji(s) du serveur utilisable(s) dans les réponses.",
         logger.info("%d emoji(s) du serveur utilisable(s) dans les réponses.",
                     len(usable_emojis(getattr(channel, "guild", None))))
                     len(usable_emojis(getattr(channel, "guild", None))))
+        started = discord.utils.utcnow()
         embed = discord.Embed(
         embed = discord.Embed(
-            title="Bot en ligne",
-            description=f"{name} est désormais en ligne. Version {VERSION}.",
-            color=discord.Color.green(),
+            title="En ligne",
+            description=f"**{me.display_name}** vient de démarrer et répond de nouveau aux messages.",
+            color=ONLINE_COLOR,
+            timestamp=started,
         )
         )
+        embed.set_thumbnail(url=me.display_avatar.url)
+        embed.add_field(name="Version", value=f"`{VERSION}`")
+        embed.add_field(name="Modèle", value=display_name(self.settings.model))
+        embed.add_field(name="Démarrage", value=discord.utils.format_dt(started, "R"))
         try:
         try:
             await channel.send(embed=embed)
             await channel.send(embed=embed)
         except discord.HTTPException as exc:
         except discord.HTTPException as exc:

+ 13 - 0
bot/models.py

@@ -2,6 +2,11 @@
 
 
 from __future__ import annotations
 from __future__ import annotations
 
 
+import re
+
+# « claude-sonnet-5-5 » ou « claude-sonnet-4-5-20250929 » : famille, version, date éventuelle.
+_MODEL_ID = re.compile(r"^claude-([a-z]+)-(\d+)(?:-(\d{1,2}))?(?:-\d{8})?$")
+
 # Façon de couper la réflexion préalable (THINKING=off), qui dépend du modèle.
 # Façon de couper la réflexion préalable (THINKING=off), qui dépend du modèle.
 # None : impossible sur ce modèle, seul EFFORT permet alors de la réduire.
 # None : impossible sur ce modèle, seul EFFORT permet alors de la réduire.
 _THINKING_OFF: dict[str, dict | None] = {
 _THINKING_OFF: dict[str, dict | None] = {
@@ -25,6 +30,14 @@ def is_known(model: str) -> bool:
     return model in PRICES
     return model in PRICES
 
 
 
 
+def display_name(model: str) -> str:
+    """Nom lisible du modèle (« Sonnet 5.5 ») ; l'identifiant tel quel s'il n'a pas la forme habituelle."""
+    if not (match := _MODEL_ID.match(model)):
+        return model
+    family, major, minor = match.groups()
+    return f"{family.capitalize()} {major}{f'.{minor}' if minor else ''}"
+
+
 def thinking_off(model: str) -> dict | None:
 def thinking_off(model: str) -> dict | None:
     """Paramètre « thinking » à envoyer quand THINKING=off (None : ne rien envoyer)."""
     """Paramètre « thinking » à envoyer quand THINKING=off (None : ne rien envoyer)."""
     return _THINKING_OFF.get(model, _DEFAULT_THINKING_OFF)
     return _THINKING_OFF.get(model, _DEFAULT_THINKING_OFF)