Add clear cache indicators to output
- Show "⚡ CACHED RESULTS (Xh old)" in compact output header - Add "use --refresh for fresh data" hint - Track from_cache and cache_age_hours in Report schema - Update UI to show cache age in stderr message Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -236,11 +236,13 @@ def main():
|
|||||||
progress = ui.ProgressDisplay(args.topic, show_banner=True)
|
progress = ui.ProgressDisplay(args.topic, show_banner=True)
|
||||||
|
|
||||||
if not args.refresh and not args.mock:
|
if not args.refresh and not args.mock:
|
||||||
cached = cache.load_cache(cache_key)
|
cached, cache_age = cache.load_cache_with_age(cache_key)
|
||||||
if cached:
|
if cached:
|
||||||
# Use cached data
|
# Use cached data
|
||||||
progress.show_cached()
|
progress.show_cached(cache_age)
|
||||||
report = schema.Report.from_dict(cached)
|
report = schema.Report.from_dict(cached)
|
||||||
|
report.from_cache = True
|
||||||
|
report.cache_age_hours = cache_age
|
||||||
output_result(report, args.emit)
|
output_result(report, args.emit)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,39 @@ def load_cache(cache_key: str, ttl_hours: int = DEFAULT_TTL_HOURS) -> Optional[d
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_cache_age_hours(cache_path: Path) -> Optional[float]:
|
||||||
|
"""Get age of cache file in hours."""
|
||||||
|
if not cache_path.exists():
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
stat = cache_path.stat()
|
||||||
|
mtime = datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc)
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
return (now - mtime).total_seconds() / 3600
|
||||||
|
except OSError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def load_cache_with_age(cache_key: str, ttl_hours: int = DEFAULT_TTL_HOURS) -> tuple:
|
||||||
|
"""Load data from cache with age info.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (data, age_hours) or (None, None) if invalid
|
||||||
|
"""
|
||||||
|
cache_path = get_cache_path(cache_key)
|
||||||
|
|
||||||
|
if not is_cache_valid(cache_path, ttl_hours):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
age = get_cache_age_hours(cache_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(cache_path, 'r') as f:
|
||||||
|
return json.load(f), age
|
||||||
|
except (json.JSONDecodeError, OSError):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
def save_cache(cache_key: str, data: dict):
|
def save_cache(cache_key: str, data: dict):
|
||||||
"""Save data to cache."""
|
"""Save data to cache."""
|
||||||
ensure_cache_dir()
|
ensure_cache_dir()
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ def render_compact(report: schema.Report, limit: int = 15) -> str:
|
|||||||
# Header
|
# Header
|
||||||
lines.append(f"## Research Results: {report.topic}")
|
lines.append(f"## Research Results: {report.topic}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
# Cache indicator
|
||||||
|
if report.from_cache:
|
||||||
|
age_str = f"{report.cache_age_hours:.1f}h old" if report.cache_age_hours else "cached"
|
||||||
|
lines.append(f"**⚡ CACHED RESULTS** ({age_str}) - use `--refresh` for fresh data")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
lines.append(f"**Date Range:** {report.range_from} to {report.range_to}")
|
lines.append(f"**Date Range:** {report.range_from} to {report.range_to}")
|
||||||
lines.append(f"**Mode:** {report.mode}")
|
lines.append(f"**Mode:** {report.mode}")
|
||||||
if report.openai_model_used:
|
if report.openai_model_used:
|
||||||
|
|||||||
@@ -156,6 +156,9 @@ class Report:
|
|||||||
# Status tracking
|
# Status tracking
|
||||||
reddit_error: Optional[str] = None
|
reddit_error: Optional[str] = None
|
||||||
x_error: Optional[str] = None
|
x_error: Optional[str] = None
|
||||||
|
# Cache info
|
||||||
|
from_cache: bool = False
|
||||||
|
cache_age_hours: Optional[float] = None
|
||||||
|
|
||||||
def to_dict(self) -> Dict[str, Any]:
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
d = {
|
d = {
|
||||||
@@ -178,6 +181,10 @@ class Report:
|
|||||||
d['reddit_error'] = self.reddit_error
|
d['reddit_error'] = self.reddit_error
|
||||||
if self.x_error:
|
if self.x_error:
|
||||||
d['x_error'] = self.x_error
|
d['x_error'] = self.x_error
|
||||||
|
if self.from_cache:
|
||||||
|
d['from_cache'] = self.from_cache
|
||||||
|
if self.cache_age_hours is not None:
|
||||||
|
d['cache_age_hours'] = self.cache_age_hours
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -248,6 +255,8 @@ class Report:
|
|||||||
context_snippet_md=data.get('context_snippet_md', ''),
|
context_snippet_md=data.get('context_snippet_md', ''),
|
||||||
reddit_error=data.get('reddit_error'),
|
reddit_error=data.get('reddit_error'),
|
||||||
x_error=data.get('x_error'),
|
x_error=data.get('x_error'),
|
||||||
|
from_cache=data.get('from_cache', False),
|
||||||
|
cache_age_hours=data.get('cache_age_hours'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -177,8 +177,12 @@ class ProgressDisplay:
|
|||||||
sys.stderr.write(f"{Colors.CYAN}X:{Colors.RESET} {x_count} posts\n\n")
|
sys.stderr.write(f"{Colors.CYAN}X:{Colors.RESET} {x_count} posts\n\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
|
||||||
def show_cached(self):
|
def show_cached(self, age_hours: float = None):
|
||||||
sys.stderr.write(f"{Colors.GREEN}⚡{Colors.RESET} {Colors.DIM}Using cached results{Colors.RESET}\n\n")
|
if age_hours is not None:
|
||||||
|
age_str = f" ({age_hours:.1f}h old)"
|
||||||
|
else:
|
||||||
|
age_str = ""
|
||||||
|
sys.stderr.write(f"{Colors.GREEN}⚡{Colors.RESET} {Colors.DIM}Using cached results{age_str} - use --refresh for fresh data{Colors.RESET}\n\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
|
||||||
def show_error(self, message: str):
|
def show_error(self, message: str):
|
||||||
|
|||||||
Reference in New Issue
Block a user