diff --git a/automations/ai-newsletter-digest/README.md b/automations/ai-newsletter-digest/README.md new file mode 100644 index 0000000..f4d0f7a --- /dev/null +++ b/automations/ai-newsletter-digest/README.md @@ -0,0 +1,58 @@ +# AI Newsletter Digest Automation + +Automatically consolidates AI-related newsletters into a single, deduplicated daily digest. + +## Schedule +- **When:** Daily at 7:30 AM (Australia/Perth timezone) +- **Delivery:** Via Telegram + +## What It Does +1. Scans unread emails from the last 24 hours +2. Identifies AI-related newsletters +3. **Excludes:** Notion, Platformer, WSJ, WIRED Daily (per Anthony's request) +4. Fetches full content from remaining newsletters +5. Uses LLM to analyze and create consolidated digest: + - Top AI News (deduplicated across sources) + - Product Launches + - Research Highlights + - Industry Trends + - Notable Quotes + +## Files +- `daily-digest.sh` - Main script that fetches newsletters +- `digest.py` - Python analysis tool (alternative approach) +- `list-newsletters.py` - Quick check of what newsletters are in inbox + +## Manual Run +```bash +cd /home/openclaw/.openclaw/workspace/automations/ai-newsletter-digest +./daily-digest.sh +``` + +This outputs a file path. You can then ask me to analyze it. + +## Cron Job +- **Job ID:** `faaed154-8320-468f-a597-21b6a92eed39` +- **Check status:** `openclaw cron list` +- **Disable:** `openclaw cron remove ` + +## Newsletter Sources Included +- AI Valley +- The Information (Applied AI) +- Wall Street Journal (AI coverage) +- The Deep View +- WIRED Daily +- And other AI-related emails + +## How to Modify + +**Change the schedule:** +```bash +openclaw cron update --schedule "0 8 * * *" # 8am instead +``` + +**Add more exclusions:** +Edit `daily-digest.sh` and add more `grep -v "pattern"` lines + +**Change lookback period:** +Edit the `--recent 24h` parameter in `daily-digest.sh` diff --git a/automations/ai-newsletter-digest/analyze.sh b/automations/ai-newsletter-digest/analyze.sh new file mode 100755 index 0000000..bd9b790 --- /dev/null +++ b/automations/ai-newsletter-digest/analyze.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# AI Newsletter Digest - Fetch and analyze +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EMAIL_SKILL="$SCRIPT_DIR/../../skills/imap-smtp-email" + +echo "šŸ¤– AI Newsletter Digest Generator" >&2 +echo "============================================================" >&2 + +# Fetch AI-related emails from last 7 days +echo "šŸ“§ Fetching AI newsletters from last 7 days..." >&2 + +python3 "$EMAIL_SKILL/scripts/imap-py.py" search \ + --subject "AI" \ + --recent 7d \ + --limit 20 > /tmp/ai_emails_list.txt + +# Count how many we found +EMAIL_COUNT=$(grep -c "^ā—" /tmp/ai_emails_list.txt || echo "0") +echo "šŸŽÆ Found $EMAIL_COUNT AI-related emails" >&2 + +if [ "$EMAIL_COUNT" = "0" ]; then + echo "No AI newsletters found in the last 7 days." + exit 0 +fi + +# Extract UIDs +UIDS=$(grep "UID:" /tmp/ai_emails_list.txt | awk '{print $3}' | head -10) + +echo "šŸ“– Fetching content from top 10 newsletters..." >&2 +echo "" > /tmp/ai_newsletters_content.txt + +for uid in $UIDS; do + echo " • Fetching email $uid..." >&2 + python3 "$EMAIL_SKILL/scripts/imap-py.py" fetch "$uid" >> /tmp/ai_newsletters_content.txt 2>/dev/null || true + echo -e "\n\n========================================\n\n" >> /tmp/ai_newsletters_content.txt +done + +echo "āœ… Content fetched!" >&2 +echo "" >&2 +echo "šŸ“‹ Newsletter sources:" >&2 +grep "^From:" /tmp/ai_newsletters_content.txt | sort -u | head -10 >&2 +echo "" >&2 + +# Output the file path for the agent to analyze +echo "/tmp/ai_newsletters_content.txt" diff --git a/automations/ai-newsletter-digest/daily-digest.sh b/automations/ai-newsletter-digest/daily-digest.sh new file mode 100755 index 0000000..4f4e870 --- /dev/null +++ b/automations/ai-newsletter-digest/daily-digest.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Daily AI Newsletter Digest - Fast Reliable Version +set -e + +EMAIL_SKILL="/home/openclaw/.openclaw/workspace/skills/imap-smtp-email" +OUTPUT_FILE="/tmp/ai-newsletter-emails.json" + +echo "šŸ¤– Daily AI Newsletter Digest" >&2 +echo "============================================================" >&2 +echo "$(date)" >&2 +echo "" >&2 + +echo "šŸ” Searching for AI newsletters from last 48 hours..." >&2 + +# Single search for all recent emails, then filter locally +cd "$EMAIL_SKILL" + +# Get recent emails and filter for AI newsletters (expanded to 48h and more sources) +ALL_EMAILS=$(node scripts/imap.js search --recent 48h --limit 100 2>/dev/null | jq '[.[] | select(.from | test("AI Valley|AI Secret|DeepView|Deep View|The Rundown|TLDR|Benedict|aivalley|aisecret|deepview|therundown|tldr|benedict"; "i"))]' 2>/dev/null || echo "[]") + +# Save results +echo "$ALL_EMAILS" > "$OUTPUT_FILE" + +EMAIL_COUNT=$(echo "$ALL_EMAILS" | jq '. | length') +echo "" >&2 +echo "šŸŽÆ Found $EMAIL_COUNT AI-related emails" >&2 + +if [ "$EMAIL_COUNT" -eq 0 ]; then + echo "No new AI newsletters in the last 24 hours." >&2 + echo "[]" + exit 0 +fi + +echo "" >&2 +echo "šŸ“§ Ready to process $EMAIL_COUNT newsletters" >&2 + +# Output the emails +cat "$OUTPUT_FILE" diff --git a/automations/ai-newsletter-digest/digest.py b/automations/ai-newsletter-digest/digest.py new file mode 100644 index 0000000..52b6cdf --- /dev/null +++ b/automations/ai-newsletter-digest/digest.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +""" +AI Newsletter Digest +Consolidates AI-related newsletters into a single, deduplicated summary +""" +import sys +import os +import json +import subprocess +from pathlib import Path +from datetime import datetime +import re + +# Add skills to path +WORKSPACE = Path(__file__).parent.parent.parent +EMAIL_SKILL = WORKSPACE / "skills" / "imap-smtp-email" + +# Newsletter keywords to look for in sender/subject +AI_KEYWORDS = [ + 'ai', 'artificial intelligence', 'machine learning', 'ml', 'llm', + 'gpt', 'claude', 'openai', 'anthropic', 'deepmind', 'neural', + 'chatgpt', 'transformer', 'diffusion', 'generative', 'newsletter' +] + +def log(msg): + """Log to stderr""" + print(msg, file=sys.stderr) + +def is_ai_newsletter(from_addr, subject): + """Check if email is likely an AI newsletter""" + text = f"{from_addr} {subject}".lower() + return any(keyword in text for keyword in AI_KEYWORDS) + +def fetch_unread_emails(limit=50): + """Fetch unread emails using the IMAP skill""" + log("šŸ“§ Fetching unread emails...") + + cmd = [ + "python3", + str(EMAIL_SKILL / "scripts" / "imap-py.py"), + "search", + "--unseen", + "--limit", str(limit) + ] + + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0: + log(f"Error fetching emails: {result.stderr}") + return [] + + # Parse the output + emails = [] + lines = result.stdout.strip().split('\n') + + current_email = {} + for line in lines: + line = line.strip() + + if line.startswith('ā—') or line.startswith(' '): + # Start of new email + if 'UID:' in line: + if current_email: + emails.append(current_email) + uid = line.split('UID:')[1].strip().split()[0] + current_email = {'uid': uid} + elif line.startswith('From:'): + current_email['from'] = line.replace('From:', '').strip() + elif line.startswith('Subject:'): + current_email['subject'] = line.replace('Subject:', '').strip() + elif line.startswith('Date:'): + current_email['date'] = line.replace('Date:', '').strip() + + if current_email: + emails.append(current_email) + + return emails + +def fetch_email_body(uid): + """Fetch full email body""" + log(f" Fetching email {uid}...") + + cmd = [ + "python3", + str(EMAIL_SKILL / "scripts" / "imap-py.py"), + "fetch", + uid + ] + + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0: + return None + + # Extract body (everything after the separator line) + parts = result.stdout.split('-' * 80) + if len(parts) > 1: + return parts[1].strip() + + return result.stdout.strip() + +def extract_key_points(newsletters): + """Use LLM to extract and deduplicate key points""" + log("🧠 Analyzing newsletters and extracting key points...") + + # Prepare newsletter content for analysis + newsletter_texts = [] + for i, newsletter in enumerate(newsletters, 1): + text = f"NEWSLETTER {i} - {newsletter['from']}\nSubject: {newsletter['subject']}\n\n{newsletter['body'][:3000]}" + newsletter_texts.append(text) + + combined = "\n\n" + "="*80 + "\n\n".join(newsletter_texts) + + # Prompt for LLM + prompt = f"""You are analyzing {len(newsletters)} AI-related newsletters. Extract the key information and insights, removing duplicates and synthesizing similar news across sources. + +{combined} + +Please provide: +1. **Top AI News** - The most important developments mentioned (deduplicated) +2. **Product Launches** - New tools, models, or features announced +3. **Research Highlights** - Notable papers or breakthroughs +4. **Industry Trends** - Patterns or themes across multiple newsletters +5. **Notable Quotes** - Interesting perspectives from thought leaders + +Format as markdown with clear sections. Be concise but informative. If the same news appears in multiple newsletters, mention it once and note it's widely covered.""" + + # Call LLM via openclaw (assuming this is running within openclaw context) + # For now, create a temporary prompt file + prompt_file = Path("/tmp/digest_prompt.txt") + prompt_file.write_text(prompt) + + log(" Generating digest with LLM...") + log(" (This may take a moment...)") + + # Return a placeholder for now - in production this would call the LLM + # The agent running this will provide LLM access + return { + 'prompt': prompt, + 'needs_llm': True + } + +def create_digest(newsletters): + """Create the final digest""" + if not newsletters: + return "No AI newsletters found in unread emails." + + # For now, return structured data that the agent can analyze + digest = { + 'count': len(newsletters), + 'sources': [n['from'] for n in newsletters], + 'newsletters': newsletters + } + + return digest + +def main(): + log("šŸ¤– AI Newsletter Digest Generator") + log("=" * 60) + + # Fetch unread emails + emails = fetch_unread_emails(limit=50) + + # Filter for AI newsletters + log(f"šŸ“Š Found {len(emails)} unread emails") + ai_newsletters = [] + + for email in emails: + if is_ai_newsletter(email.get('from', ''), email.get('subject', '')): + ai_newsletters.append(email) + + log(f"šŸŽÆ Found {len(ai_newsletters)} AI-related newsletters") + + if not ai_newsletters: + print(json.dumps({'status': 'no_newsletters', 'message': 'No AI newsletters found'})) + return + + # Fetch full content for each + log("šŸ“– Fetching full newsletter content...") + for newsletter in ai_newsletters[:10]: # Limit to 10 to avoid overwhelming + body = fetch_email_body(newsletter['uid']) + if body: + newsletter['body'] = body + + # Filter out ones without body + ai_newsletters = [n for n in ai_newsletters if 'body' in n] + + log(f"āœ… Successfully fetched {len(ai_newsletters)} newsletters") + + # Output structured data for the agent to analyze + result = { + 'status': 'success', + 'count': len(ai_newsletters), + 'sources': list(set([n['from'] for n in ai_newsletters])), + 'newsletters': ai_newsletters[:10] # Limit to 10 + } + + print(json.dumps(result, indent=2)) + + # Log summary to stderr + log("\nšŸ“‹ Newsletter Sources:") + for source in result['sources']: + log(f" • {source}") + +if __name__ == '__main__': + main() diff --git a/automations/ai-newsletter-digest/list-newsletters.py b/automations/ai-newsletter-digest/list-newsletters.py new file mode 100644 index 0000000..1f00141 --- /dev/null +++ b/automations/ai-newsletter-digest/list-newsletters.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +""" +Quick list of AI newsletters in inbox +""" +import sys +import subprocess +from pathlib import Path + +WORKSPACE = Path(__file__).parent.parent.parent +EMAIL_SKILL = WORKSPACE / "skills" / "imap-smtp-email" + +AI_KEYWORDS = [ + 'ai', 'artificial intelligence', 'machine learning', 'ml', 'llm', + 'gpt', 'claude', 'openai', 'anthropic', 'deepmind', 'neural', + 'chatgpt', 'transformer', 'diffusion', 'generative', 'newsletter' +] + +def is_ai_newsletter(from_addr, subject): + text = f"{from_addr} {subject}".lower() + return any(keyword in text for keyword in AI_KEYWORDS) + +def main(): + # Fetch unread emails + cmd = [ + "python3", + str(EMAIL_SKILL / "scripts" / "imap-py.py"), + "search", + "--unseen", + "--limit", "50" + ] + + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0: + print("Error fetching emails", file=sys.stderr) + sys.exit(1) + + # Parse output + emails = [] + lines = result.stdout.strip().split('\n') + + current_email = {} + for line in lines: + line = line.strip() + + if 'UID:' in line: + if current_email: + emails.append(current_email) + uid = line.split('UID:')[1].strip().split()[0] + current_email = {'uid': uid} + elif line.startswith('From:'): + current_email['from'] = line.replace('From:', '').strip() + elif line.startswith('Subject:'): + current_email['subject'] = line.replace('Subject:', '').strip() + + if current_email: + emails.append(current_email) + + # Filter AI newsletters + ai_newsletters = [e for e in emails if is_ai_newsletter(e.get('from', ''), e.get('subject', ''))] + + print(f"Found {len(ai_newsletters)} AI newsletters out of {len(emails)} unread emails:\n") + + for n in ai_newsletters: + print(f"UID: {n['uid']}") + print(f"From: {n.get('from', 'Unknown')}") + print(f"Subject: {n.get('subject', 'No subject')}") + print() + +if __name__ == '__main__': + main() diff --git a/automations/backup-to-gitea.sh b/automations/backup-to-gitea.sh index 491b77f..7da6d61 100755 --- a/automations/backup-to-gitea.sh +++ b/automations/backup-to-gitea.sh @@ -18,6 +18,21 @@ if ! git config --global credential.helper &>/dev/null; then echo " Run: git config --global credential.helper store" | tee -a "$LOG_FILE" fi +# Gotify alert function +send_gotify() { + local title="$1" + local message="$2" + local priority="${3:-0}" + local gotify_url="${GOTIFY_URL:-http://runtipi.kangaroo-eel.ts.net:8129}" + local gotify_token="${GOTIFY_API_KEY}" + + if [[ -n "$gotify_token" ]]; then + curl -s -X POST "$gotify_url/message?token=$gotify_token" \ + -H "Content-Type: application/json" \ + -d "{\"title\":\"$title\",\"message\":\"$message\",\"priority\":$priority}" > /dev/null 2>&1 + fi +} + # Function to backup a repo backup_repo() { local path=$1 @@ -36,8 +51,7 @@ backup_repo() { echo "āœ… $name: Backup successful" | tee -a "$LOG_FILE" else echo "āŒ $name: Push failed - check credentials" | tee -a "$LOG_FILE" - echo " To fix: git config --global credential.helper store" | tee -a "$LOG_FILE" - echo " Then: cd $path && git push (enter credentials once)" | tee -a "$LOG_FILE" + send_gotify "āš ļø Backup Failed" "$name push to Gitea failed. Check credentials." 5 fi else echo "ā­ļø $name: No changes to backup" | tee -a "$LOG_FILE" @@ -55,4 +69,7 @@ echo "šŸ“„ Log saved to: $LOG_FILE" | tee -a "$LOG_FILE" # Show recent backups echo "" | tee -a "$LOG_FILE" echo "šŸ“Š Recent backups:" | tee -a "$LOG_FILE" -cd /home/openclaw/.openclaw/workspace && git log --oneline -3 | tee -a "$LOG_FILE" \ No newline at end of file +cd /home/openclaw/.openclaw/workspace && git log --oneline -3 | tee -a "$LOG_FILE" + +# Send success notification +send_gotify "āœ… Backup Complete" "OpenClaw backup to Gitea succeeded" \ No newline at end of file diff --git a/automations/morning-briefing/README.md b/automations/morning-briefing/README.md new file mode 100644 index 0000000..d9d9c84 --- /dev/null +++ b/automations/morning-briefing/README.md @@ -0,0 +1,105 @@ +# Morning Intelligence Briefing - n8n Workflow + +## šŸ“ Files + +1. **n8n-workflow.json** - Full workflow (requires credentials) +2. **n8n-workflow-simple.json** - Simpler version (fewer dependencies) + +## šŸš€ Setup Instructions + +### Step 1: Import to n8n +1. Open your n8n: https://n8n.kangaroo-eel.ts.net +2. Go to **Workflows** → **Import from File** +3. Select `n8n-workflow.json` + +### Step 2: Configure Credentials + +You'll need to create these credentials in n8n: + +#### A. FreshRSS (HTTP Basic Auth) +- **Name**: FreshRSS Credentials +- **Username**: Anthony +- **Password**: RecOvery2026! + +#### B. Perplexity (HTTP Header Auth) +- **Name**: Perplexity API +- **Header Name**: Authorization +- **Header Value**: Bearer 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 + +#### C. Telegram Bot +- **Name**: Telegram Bot +- **Access Token**: (Your bot token - I can help get this) + +### Step 3: Test +1. Click **Execute Workflow** +2. Check if you receive a Telegram message + +### Step 4: Activate +1. Toggle **Active** switch +2. Workflow runs daily at 6:00 AM (Perth time) + +## šŸ”§ What It Does + +``` +6:00 AM Trigger + ↓ +Fetch FreshRSS (your RSS feeds) + ↓ +Fetch News Aggregator (HN, GitHub, Product Hunt, etc.) + ↓ +Query Perplexity AI ("Today's top news") + ↓ +Combine all sources + ↓ +AI Deduplication & Summarization + ↓ +Telegram to You (5-7 key stories) +``` + +## šŸ“± Expected Output Example + +``` +šŸŒ… Morning Intelligence Briefing + +1. šŸ”„ OpenAI announces GPT-5... +2. šŸ’° Tech stocks rally... +3. šŸš€ New AI tool from... +4. šŸ“° Major news from... +5. šŸ’” Innovation in... + +--- +Sources: FreshRSS, News Aggregator, Perplexity AI +``` + +## āš ļø Troubleshooting + +**Issue**: FreshRSS authentication fails +**Fix**: Check API password in FreshRSS → Settings → Profile → API Management + +**Issue**: News Aggregator fails +**Fix**: Ensure Python venv exists at `/skills/news-aggregator-skill/.venv` + +**Issue**: Telegram not received +**Fix**: Check bot token and chat ID (1793951355) + +## šŸŽØ Customization + +### Change time: +Edit "6 AM Daily" node → Change trigger time + +### Add more sources: +Add HTTP Request nodes for additional APIs + +### Change summary style: +Edit "AI Summarize" system prompt + +### Filter categories: +Add Code node to filter FreshRSS by category + +## šŸ“ž Support + +Need help? Ask me to: +- Debug credential issues +- Customize the workflow +- Add more news sources +- Change the schedule diff --git a/automations/morning-briefing/morning-briefing.sh b/automations/morning-briefing/morning-briefing.sh new file mode 100644 index 0000000..ab243ca --- /dev/null +++ b/automations/morning-briefing/morning-briefing.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Morning Briefing - Premium Version +# Calls OpenClaw agent to generate comprehensive briefing + +set -e + +echo "šŸŒ… Morning Briefing Generator" >&2 +echo "============================" >&2 + +# Get weather +WEATHER=$(curl -s "wttr.in/Perth?format=%l:+%c+%t+%h+wind:%w" 2>/dev/null || echo "Weather unavailable") +echo "Weather: $WEATHER" >&2 + +# Output just the weather for now - the agent will build the full briefing +echo "WEATHER=$WEATHER" diff --git a/automations/morning-briefing/n8n-workflow.json b/automations/morning-briefing/n8n-workflow.json new file mode 100644 index 0000000..93fa6d8 --- /dev/null +++ b/automations/morning-briefing/n8n-workflow.json @@ -0,0 +1,208 @@ +{ + "name": "Morning Intelligence Briefing", + "nodes": [ + { + "parameters": { + "rule": { + "interval": [ + { + "field": "hours", + "hoursInterval": 24, + "triggerAtHour": 6 + } + ] + } + }, + "id": "cron-trigger", + "name": "6 AM Daily", + "type": "n8n-nodes-base.scheduleTrigger", + "typeVersion": 1, + "position": [250, 300] + }, + { + "parameters": { + "url": "http://freshrss.kangaroo-eel.ts.net/api/greader.php/reader/api/0/stream/items/ids", + "sendQuery": true, + "queryParameters": { + "parameters": [ + { + "name": "output", + "value": "json" + }, + { + "name": "n", + "value": "20" + } + ] + }, + "options": {} + }, + "id": "freshrss-fetch", + "name": "Fetch FreshRSS", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.1, + "position": [450, 200], + "credentials": { + "httpBasicAuth": { + "id": "freshrss-creds", + "name": "FreshRSS Credentials" + } + } + }, + { + "parameters": { + "command": "cd /home/openclaw/.openclaw/workspace/skills/news-aggregator-skill && .venv/bin/python scripts/fetch_news.py --source all --limit 15" + }, + "id": "news-aggregator", + "name": "News Aggregator", + "type": "n8n-nodes-base.executeCommand", + "typeVersion": 1, + "position": [450, 400] + }, + { + "parameters": { + "model": "llama-3.1-sonar-large-128k-online", + "messages": { + "message": [ + { + "role": "user", + "content": "What are the top 5 tech, AI, and business news stories from today?" + } + ] + }, + "options": {} + }, + "id": "perplexity-search", + "name": "Perplexity Search", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.1, + "position": [650, 300], + "credentials": { + "httpHeaderAuth": { + "id": "perplexity-creds", + "name": "Perplexity API" + } + } + }, + { + "parameters": { + "jsCode": "// Combine all news sources and deduplicate\nconst freshRSS = $input.first().json;\nconst newsAgg = $input.all()[1].json;\nconst perplexity = $input.all()[2].json;\n\n// Create combined list\nlet allStories = [];\n\n// Add FreshRSS items\nif (freshRSS && freshRSS.items) {\n allStories = allStories.concat(freshRSS.items.map(item => ({\n source: 'FreshRSS',\n title: item.title,\n url: item.url,\n time: item.timestamp\n })));\n}\n\n// Add News Aggregator items\nif (newsAgg && Array.isArray(newsAgg)) {\n allStories = allStories.concat(newsAgg.map(item => ({\n source: item.source || 'News Aggregator',\n title: item.title,\n url: item.url,\n heat: item.heat\n })));\n}\n\n// Add Perplexity insights\nif (perplexity && perplexity.choices) {\n allStories.push({\n source: 'Perplexity AI',\n title: 'AI-Synthesized Briefing',\n content: perplexity.choices[0].message.content\n });\n}\n\n// Return combined for AI analysis\nreturn [{\n json: {\n stories: allStories,\n count: allStories.length,\n sources: ['FreshRSS', 'News Aggregator', 'Perplexity']\n }\n}];" + }, + "id": "combine-sources", + "name": "Combine Sources", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [850, 300] + }, + { + "parameters": { + "model": "gpt-4o-mini", + "options": {}, + "messages": { + "message": [ + { + "role": "system", + "content": "You are a news editor creating a morning intelligence briefing. Analyze the provided news stories from multiple sources, remove duplicates, identify genuinely new information, and create a concise summary of the top 5-7 most important stories. Format as markdown with emojis. Focus on tech, AI, business, and relevant world news." + }, + { + "role": "user", + "content": "=Create a morning briefing from these sources:\n\n{{ $json.stories }}" + } + ] + } + }, + "id": "ai-summarize", + "name": "AI Summarize", + "type": "@n8n/n8n-nodes-langchain.agent", + "typeVersion": 1.6, + "position": [1050, 300] + }, + { + "parameters": { + "chatId": "1793951355", + "text": "=šŸŒ… **Morning Intelligence Briefing**\n\n{{ $json.output }}\n\n---\n_Sources: FreshRSS, News Aggregator, Perplexity AI_", + "options": {} + }, + "id": "telegram-send", + "name": "Send Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [1250, 300], + "credentials": { + "telegramApi": { + "id": "telegram-bot-creds", + "name": "Telegram Bot" + } + } + } + ], + "connections": { + "6 AM Daily": { + "main": [ + [ + { + "node": "Fetch FreshRSS", + "type": "main", + "index": 0 + }, + { + "node": "News Aggregator", + "type": "main", + "index": 0 + } + ] + ] + }, + "Fetch FreshRSS": { + "main": [ + [ + { + "node": "Combine Sources", + "type": "main", + "index": 0 + } + ] + ] + }, + "News Aggregator": { + "main": [ + [ + { + "node": "Combine Sources", + "type": "main", + "index": 0 + } + ] + ] + }, + "Combine Sources": { + "main": [ + [ + { + "node": "AI Summarize", + "type": "main", + "index": 0 + } + ] + ] + }, + "AI Summarize": { + "main": [ + [ + { + "node": "Send Telegram", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "settings": { + "executionOrder": "v1" + }, + "staticData": null, + "tags": [], + "pinData": {}, + "description": "Daily morning briefing combining FreshRSS, News Aggregator, and Perplexity AI into a single Telegram message at 6 AM" +}