From 88da476249f9460cdd08c891e739b4f3b2e8ddd8 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Fri, 20 Mar 2026 11:26:26 +0100 Subject: [PATCH] Update notification service --- AppImage/components/notification-settings.tsx | 2 +- AppImage/lib/api-config.ts | 26 ++++++++++++++----- AppImage/scripts/notification_manager.py | 14 +++++++--- AppImage/scripts/notification_templates.py | 11 ++++++-- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/AppImage/components/notification-settings.tsx b/AppImage/components/notification-settings.tsx index 07560ca7..1fe645aa 100644 --- a/AppImage/components/notification-settings.tsx +++ b/AppImage/components/notification-settings.tsx @@ -1746,7 +1746,7 @@ export function NotificationSettings() {

After creating the bot, BotFather will give you a token like:

- {":"} + xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Copy this token and paste it in the Bot Token field.

diff --git a/AppImage/lib/api-config.ts b/AppImage/lib/api-config.ts index 3bb0a36b..c07f26c0 100644 --- a/AppImage/lib/api-config.ts +++ b/AppImage/lib/api-config.ts @@ -89,12 +89,26 @@ export async function fetchApi(endpoint: string, options?: RequestInit): Prom cache: "no-store", }) - if (!response.ok) { - if (response.status === 401) { - throw new Error(`Unauthorized: ${endpoint}`) + if (!response.ok) { + if (response.status === 401) { + console.error("[v0] fetchApi: 401 UNAUTHORIZED -", endpoint, "- Token present:", !!token) + throw new Error(`Unauthorized: ${endpoint}`) + } + throw new Error(`API request failed: ${response.status} ${response.statusText}`) } - throw new Error(`API request failed: ${response.status} ${response.statusText}`) - } - return response.json() + // Check content type to ensure we're getting JSON + const contentType = response.headers.get("content-type") + if (!contentType || !contentType.includes("application/json")) { + const text = await response.text() + console.error("[v0] fetchApi: Expected JSON but got:", contentType, "- Body preview:", text.substring(0, 200)) + throw new Error(`Expected JSON response but got ${contentType || "unknown content type"}`) + } + + try { + return await response.json() + } catch (jsonError) { + console.error("[v0] fetchApi: JSON parse error for", endpoint, "-", jsonError) + throw new Error(`Invalid JSON response from ${endpoint}`) + } } diff --git a/AppImage/scripts/notification_manager.py b/AppImage/scripts/notification_manager.py index 691c2d8b..7e4fe69b 100644 --- a/AppImage/scripts/notification_manager.py +++ b/AppImage/scripts/notification_manager.py @@ -756,8 +756,10 @@ class NotificationManager: # ── Per-channel AI enhancement ── # Apply AI with channel-specific detail level and emoji setting # If AI is enabled AND rich_format is on, AI will include emojis directly + # Pass channel_type so AI knows whether to append original (email only) + channel_ai_config = {**ai_config, 'channel_type': ch_name} ai_result = format_with_ai_full( - ch_title, ch_body, severity, ai_config, + ch_title, ch_body, severity, channel_ai_config, detail_level=detail_level, journal_context=journal_context, use_emojis=use_rich_format @@ -1070,8 +1072,10 @@ class NotificationManager: rich_key = f'{ch_name}.rich_format' use_rich_format = self._config.get(rich_key, 'false') == 'true' + # Pass channel_type so AI knows whether to append original (email only) + channel_ai_config = {**ai_config, 'channel_type': ch_name} ai_result = format_with_ai_full( - title, message, severity, ai_config, + title, message, severity, channel_ai_config, detail_level=detail_level, use_emojis=use_rich_format ) @@ -1188,8 +1192,10 @@ class NotificationManager: ) # Apply AI enhancement (translates to configured language) + # Pass channel_type so AI knows whether to append original (email only) + channel_ai_config = {**ai_config, 'channel_type': ch_name} ai_result = format_with_ai_full( - base_title, base_message, 'INFO', ai_config, + base_title, base_message, 'INFO', channel_ai_config, detail_level=detail_level, use_emojis=use_rich_format ) @@ -1206,7 +1212,7 @@ class NotificationManager: # Translate caption if AI is active if ai_enabled: caption_result = format_with_ai_full( - '', logo_caption, 'INFO', ai_config, + '', logo_caption, 'INFO', channel_ai_config, detail_level='brief', use_emojis=use_rich_format ) caption = caption_result.get('body', logo_caption) diff --git a/AppImage/scripts/notification_templates.py b/AppImage/scripts/notification_templates.py index d6ed69fc..83c077d4 100644 --- a/AppImage/scripts/notification_templates.py +++ b/AppImage/scripts/notification_templates.py @@ -1675,6 +1675,9 @@ class AIEnhancer: try: result = self._provider.generate(system_prompt, user_msg, max_tokens) + if result is None: + print(f"[AIEnhancer] Provider returned None - possible timeout or connection issue") + return None return self._parse_ai_response(result, title, body) except Exception as e: print(f"[AIEnhancer] Enhancement failed: {e}") @@ -1811,9 +1814,13 @@ def format_with_ai_full(title: str, body: str, severity: str, result_title = enhanced.get('title', title) result_body = enhanced.get('body', body) - # For detailed level (email), append original message for reference + # For email channel with detailed level, append original message for reference # This ensures full technical data is available even after AI processing - if detail_level == 'detailed' and body and len(body) > 50: + # Only for email - other channels (Telegram, Discord, Gotify) should not get duplicates + channel_type = ai_config.get('channel_type', '').lower() + is_email = channel_type == 'email' + + if is_email and detail_level == 'detailed' and body and len(body) > 50: # Only append if original has substantial content result_body += "\n\n" + "-" * 40 + "\n" result_body += "Original message:\n"