feat: persist AI chat history, add search across it

Both chat panels (per-recipe and the general cooking assistant) previously
kept messages in component state only — closing the sheet or reloading
the page lost everything. Both POST routes now persist question+answer
pairs to a new chat_messages table (recipeId null for the general
assistant), and both panels load their own history back on open.

New GET /api/v1/ai/chat-history (scoped by recipeId, or scope=general for
the homepage assistant, or neither to search across everything) backs a
new search control in both panels' header — debounced, shows matched
messages with date and (when searching across everything) which recipe
they belonged to.

Verified locally: asked a real question, closed and reopened the panel
and confirmed the conversation reloaded, then searched a keyword from
that conversation and confirmed both the question and answer surfaced
in the results dropdown.
This commit is contained in:
Arnaud
2026-07-12 22:37:39 +02:00
parent 0062220d8e
commit 96ef5b8379
8 changed files with 237 additions and 9 deletions
+10
View File
@@ -388,6 +388,13 @@
"inputPlaceholder": "Ask a question…",
"send": "Send message"
},
"chatHistory": {
"searchAriaLabel": "Search chat history",
"searchPlaceholder": "Search past questions…",
"searching": "Searching…",
"noResults": "No matching messages",
"close": "Close"
},
"cookingChat": {
"sorry": "Sorry, I couldn't answer that.",
"error": "Something went wrong. Please try again.",
@@ -1147,6 +1154,9 @@
"lastUsedOn": "Last used {date}",
"neverUsed": "Never used",
"revoke": "Revoke",
"apiKeyScopeFull": "Full access",
"apiKeyScopeRead": "Read-only",
"apiKeyScopeHelp": "Read-only keys can only make GET requests — they can't create, edit, or delete anything.",
"webhookUrlPlaceholder": "https://example.com/webhook",
"webhookAdding": "Adding…",
"webhookAddButton": "Add webhook",
+10
View File
@@ -388,6 +388,13 @@
"inputPlaceholder": "Posez une question…",
"send": "Envoyer le message"
},
"chatHistory": {
"searchAriaLabel": "Rechercher dans l'historique",
"searchPlaceholder": "Rechercher une question passée…",
"searching": "Recherche…",
"noResults": "Aucun message correspondant",
"close": "Fermer"
},
"cookingChat": {
"sorry": "Désolé, je n'ai pas pu répondre à cela.",
"error": "Une erreur s'est produite. Veuillez réessayer.",
@@ -1153,6 +1160,9 @@
"lastUsedOn": "Utilisée le {date}",
"neverUsed": "Jamais utilisée",
"revoke": "Révoquer",
"apiKeyScopeFull": "Accès complet",
"apiKeyScopeRead": "Lecture seule",
"apiKeyScopeHelp": "Les clés en lecture seule ne peuvent faire que des requêtes GET — elles ne peuvent rien créer, modifier ou supprimer.",
"copyFailed": "Échec de la copie dans le presse-papiers",
"byokSaved": "Clé {provider} enregistrée",
"byokSaveFailed": "Échec de l'enregistrement de la clé",