Initial commit with translated description
This commit is contained in:
240
scripts/setup.py
Normal file
240
scripts/setup.py
Normal file
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Interactive onboarding wizard for topic-monitor skill.
|
||||
Runs on first use when no config.json exists.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SKILL_DIR = Path(__file__).parent.parent
|
||||
CONFIG_FILE = SKILL_DIR / "config.json"
|
||||
|
||||
|
||||
def print_welcome():
|
||||
print()
|
||||
print("=" * 55)
|
||||
print(" 🔍 Topic Monitor - Setup Wizard")
|
||||
print("=" * 55)
|
||||
print()
|
||||
print("Welcome! Let's set up your personal topic monitoring.")
|
||||
print("You can mix web search, RSS/Atom feeds, and GitHub release feeds.")
|
||||
print()
|
||||
|
||||
|
||||
def prompt(question: str, default: str = None) -> str:
|
||||
question = f"{question} [{default}]: " if default else f"{question}: "
|
||||
response = input(question).strip()
|
||||
return response if response else (default or "")
|
||||
|
||||
|
||||
def prompt_yes_no(question: str, default: bool = True) -> bool:
|
||||
default_hint = "Y/n" if default else "y/N"
|
||||
response = input(f"{question} ({default_hint}): ").strip().lower()
|
||||
if not response:
|
||||
return default
|
||||
return response in ('y', 'yes', 'ja', 'si', 'oui')
|
||||
|
||||
|
||||
def prompt_choice(question: str, choices: list, default: str = None) -> str:
|
||||
print(f"\n{question}")
|
||||
for i, choice in enumerate(choices, 1):
|
||||
marker = " *" if choice == default else ""
|
||||
print(f" {i}. {choice}{marker}")
|
||||
while True:
|
||||
response = input(f"\nEnter number or value [{default or choices[0]}]: ").strip()
|
||||
if not response:
|
||||
return default or choices[0]
|
||||
try:
|
||||
idx = int(response)
|
||||
if 1 <= idx <= len(choices):
|
||||
return choices[idx - 1]
|
||||
except ValueError:
|
||||
pass
|
||||
for choice in choices:
|
||||
if choice.lower() == response.lower():
|
||||
return choice
|
||||
print(f" Please enter a number 1-{len(choices)} or a valid option.")
|
||||
|
||||
|
||||
def prompt_multiline(question: str, hint: str = None) -> list:
|
||||
print(f"\n{question}")
|
||||
if hint:
|
||||
print(f" {hint}")
|
||||
print(" (Enter each item on a new line. Empty line when done)")
|
||||
print()
|
||||
items = []
|
||||
while True:
|
||||
line = input(" > ").strip()
|
||||
if not line:
|
||||
break
|
||||
items.append(line)
|
||||
return items
|
||||
|
||||
|
||||
def prompt_csv(question: str) -> list:
|
||||
response = input(f" {question}: ").strip()
|
||||
if not response:
|
||||
return []
|
||||
return [item.strip() for item in response.split(",") if item.strip()]
|
||||
|
||||
|
||||
def create_topic_id(name: str) -> str:
|
||||
topic_id = name.lower().replace(" ", "-")
|
||||
topic_id = "".join(c for c in topic_id if c.isalnum() or c == "-")
|
||||
topic_id = "-".join(filter(None, topic_id.split("-")))
|
||||
return topic_id[:30]
|
||||
|
||||
|
||||
def gather_topics() -> list:
|
||||
topics = []
|
||||
print("-" * 55)
|
||||
print("📋 STEP 1: Topics to Monitor")
|
||||
print("-" * 55)
|
||||
topic_names = prompt_multiline(
|
||||
"What topics do you want to monitor?",
|
||||
"Examples: AI Models, Security Alerts, Product Updates"
|
||||
)
|
||||
if not topic_names:
|
||||
print("\n⚠️ No topics entered. You can add them later with manage_topics.py")
|
||||
return []
|
||||
|
||||
for i, name in enumerate(topic_names, 1):
|
||||
print(f"\n--- Topic {i}/{len(topic_names)}: {name} ---")
|
||||
query = prompt(f" Search query for '{name}'", f"{name} news updates")
|
||||
keywords = prompt_csv(f"Keywords for '{name}' (comma-separated)")
|
||||
feeds = prompt_csv(f"RSS/Atom feeds for '{name}' (comma-separated, optional)")
|
||||
github_repos = prompt_csv(f"GitHub repos for release monitoring (owner/repo, optional)")
|
||||
required_keywords = prompt_csv(f"Required keywords (all must appear, optional)")
|
||||
exclude_keywords = prompt_csv(f"Exclude keywords (filter out if present, optional)")
|
||||
alert_on_sentiment_shift = prompt_yes_no("Alert on sentiment shift?", default=False)
|
||||
|
||||
topic = {
|
||||
"id": create_topic_id(name),
|
||||
"name": name,
|
||||
"query": query,
|
||||
"keywords": keywords,
|
||||
"feeds": feeds,
|
||||
"github_repos": github_repos,
|
||||
"required_keywords": required_keywords,
|
||||
"exclude_keywords": exclude_keywords,
|
||||
"frequency": None,
|
||||
"importance_threshold": None,
|
||||
"channels": ["telegram"],
|
||||
"context": "",
|
||||
"alert_on": ["keyword_exact_match"] + (["github_release"] if github_repos else []),
|
||||
"alert_on_sentiment_shift": alert_on_sentiment_shift,
|
||||
"ignore_sources": [],
|
||||
"boost_sources": [],
|
||||
}
|
||||
topics.append(topic)
|
||||
return topics
|
||||
|
||||
|
||||
def gather_settings() -> dict:
|
||||
print()
|
||||
print("-" * 55)
|
||||
print("⚙️ STEP 2: Monitoring Settings")
|
||||
print("-" * 55)
|
||||
frequency = prompt_choice("How often should I check for updates?", ["hourly", "daily", "weekly"], default="daily")
|
||||
importance = prompt_choice("Importance threshold for alerts?", ["low", "medium", "high"], default="medium")
|
||||
digest_enabled = prompt_yes_no("Enable weekly digest?", default=True)
|
||||
digest_day = "sunday"
|
||||
if digest_enabled:
|
||||
digest_day = prompt_choice("Which day should I send the digest?", ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], default="sunday")
|
||||
|
||||
return {
|
||||
"frequency": frequency,
|
||||
"importance_threshold": importance,
|
||||
"digest_enabled": digest_enabled,
|
||||
"digest_day": digest_day,
|
||||
"digest_time": "18:00",
|
||||
"max_alerts_per_day": 5,
|
||||
"max_alerts_per_topic_per_day": 2,
|
||||
"deduplication_window_hours": 72,
|
||||
"learning_enabled": True,
|
||||
"quiet_hours": {"enabled": False, "start": "22:00", "end": "08:00"},
|
||||
}
|
||||
|
||||
|
||||
def build_config(topics: list, settings: dict) -> dict:
|
||||
frequency = settings.pop("frequency")
|
||||
importance = settings.pop("importance_threshold")
|
||||
for topic in topics:
|
||||
topic["frequency"] = frequency
|
||||
topic["importance_threshold"] = importance
|
||||
|
||||
return {
|
||||
"topics": topics,
|
||||
"settings": settings,
|
||||
"channels": {
|
||||
"telegram": {
|
||||
"enabled": True,
|
||||
"chat_id": None,
|
||||
"silent": False,
|
||||
"effects": {"high_importance": "🔥", "medium_importance": "📌"},
|
||||
},
|
||||
"discord": {"enabled": False, "webhook_url": None, "username": "Topic Monitor", "avatar_url": None},
|
||||
"email": {
|
||||
"enabled": False,
|
||||
"to": None,
|
||||
"from": "monitor@yourdomain.com",
|
||||
"smtp_server": "smtp.gmail.com",
|
||||
"smtp_port": 587,
|
||||
"smtp_user": None,
|
||||
"smtp_password": None,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def save_config(config: dict):
|
||||
with open(CONFIG_FILE, 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
|
||||
|
||||
def print_summary(config: dict):
|
||||
print()
|
||||
print("=" * 55)
|
||||
print(" ✅ Setup Complete!")
|
||||
print("=" * 55)
|
||||
print()
|
||||
for topic in config.get("topics", []):
|
||||
print(f"• {topic['name']}")
|
||||
print(f" Query: {topic['query'] or '—'}")
|
||||
print(f" Keywords: {', '.join(topic.get('keywords', [])) or '—'}")
|
||||
print(f" Feeds: {', '.join(topic.get('feeds', [])) or '—'}")
|
||||
print(f" GitHub repos: {', '.join(topic.get('github_repos', [])) or '—'}")
|
||||
print(f" Required keywords: {', '.join(topic.get('required_keywords', [])) or '—'}")
|
||||
print(f" Exclude keywords: {', '.join(topic.get('exclude_keywords', [])) or '—'}")
|
||||
print(f" Sentiment shift alerts: {topic.get('alert_on_sentiment_shift')}")
|
||||
print()
|
||||
print("Test with: python3 scripts/monitor.py --dry-run --verbose")
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
if CONFIG_FILE.exists():
|
||||
print("\n⚠️ config.json already exists!\n")
|
||||
if not prompt_yes_no("Do you want to start fresh and overwrite it?", default=False):
|
||||
print("\nKeeping existing config. Use manage_topics.py to edit topics.")
|
||||
sys.exit(0)
|
||||
|
||||
print_welcome()
|
||||
try:
|
||||
topics = gather_topics()
|
||||
settings = gather_settings()
|
||||
config = build_config(topics, settings)
|
||||
save_config(config)
|
||||
print_summary(config)
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n⚠️ Setup cancelled. No changes made.")
|
||||
sys.exit(1)
|
||||
except EOFError:
|
||||
print("\n\n⚠️ Input ended. No changes made.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user