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"