fix: suppress loguru noise in CLI, fix birdx text parser

- CLI now suppresses loguru INFO logs by default (use -v/--verbose to show)
- Fixed birdx output parser to correctly extract author, url, date, text
- birdx search now uses plain text output (--json returns empty arrays)
This commit is contained in:
Panniantong 2026-02-24 05:21:57 +01:00
parent d891af5b7d
commit e7cd04655e
2 changed files with 63 additions and 22 deletions

View file

@ -17,15 +17,25 @@ import sys
import asyncio
import argparse
import json
import os
from agent_eyes import __version__
def _configure_logging(verbose: bool = False):
"""Suppress loguru output unless --verbose is set."""
from loguru import logger
logger.remove() # Remove default stderr handler
if verbose:
logger.add(sys.stderr, level="INFO")
def main():
parser = argparse.ArgumentParser(
prog="agent-eyes",
description="👁️ Give your AI Agent eyes to see the entire internet",
)
parser.add_argument("-v", "--verbose", action="store_true", help="Show debug logs")
sub = parser.add_subparsers(dest="command", help="Available commands")
# ── read ──
@ -66,6 +76,9 @@ def main():
args = parser.parse_args()
# Suppress loguru noise unless --verbose
_configure_logging(getattr(args, "verbose", False))
if not args.command:
parser.print_help()
sys.exit(0)

View file

@ -38,46 +38,74 @@ async def _search_birdx(query: str, limit: int) -> List[Dict[str, Any]]:
"""Search Twitter via birdx CLI."""
logger.info(f"birdx search: {query} (n={limit})")
try:
# birdx --json returns [] for search, so use plain text output
result = subprocess.run(
["birdx", "search", query, "-n", str(limit), "--json"],
["birdx", "search", query, "-n", str(limit)],
capture_output=True, text=True, timeout=30,
)
if result.returncode != 0:
# birdx might not support --json, try plain output
result = subprocess.run(
["birdx", "search", query, "-n", str(limit)],
capture_output=True, text=True, timeout=30,
)
return _parse_birdx_text(result.stdout)
data = json.loads(result.stdout)
if isinstance(data, list):
return data
return data.get("tweets", data.get("results", []))
except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError) as e:
logger.error(f"birdx search failed: {result.stderr}")
return []
return _parse_birdx_text(result.stdout)
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
logger.error(f"birdx search failed: {e}")
return []
def _parse_birdx_text(text: str) -> List[Dict[str, Any]]:
"""Parse birdx plain text output into structured data."""
"""Parse birdx plain text output into structured data.
Format:
@handle (Display Name):
Tweet text here
possibly multiple lines
date: Mon Feb 24 12:00:00 +0000 2026
url: https://x.com/handle/status/123
"""
results = []
current = {}
current: Dict[str, Any] = {}
text_lines = []
for line in text.strip().split("\n"):
line = line.strip()
if not line:
# Separator between tweets
if line.startswith(""):
if current:
if text_lines:
current["text"] = "\n".join(text_lines).strip()
results.append(current)
current = {}
text_lines = []
continue
if line.startswith("@"):
current["author"] = line.split()[0] if line else ""
elif line.startswith("http"):
current["url"] = line
else:
current["text"] = current.get("text", "") + " " + line
# Author line: @handle (Display Name):
if line.startswith("@") and line.endswith(":") and "(" in line:
handle = line.split()[0]
current["author"] = handle
continue
# Date line
if line.startswith("date:"):
current["date"] = line[5:].strip()
continue
# URL line
if line.startswith("url:"):
current["url"] = line[4:].strip()
continue
# Content line
if current:
text_lines.append(line)
# Last tweet
if current:
if text_lines:
current["text"] = "\n".join(text_lines).strip()
results.append(current)
return results