66 lines
3.0 KiB
Python
66 lines
3.0 KiB
Python
import httpx
|
|
import asyncio
|
|
import random
|
|
from typing import List, Dict, Any
|
|
|
|
HN_TOP_STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json"
|
|
HN_ITEM_URL = "https://hacker-news.firebaseio.com/v0/item/{item_id}.json"
|
|
|
|
KEYWORDS = ["AI", "LLM", "GPT", "DeepSeek", "Transformer", "RAG", "Neural", "Machine Learning", "OpenAI", "Anthropic", "Google", "Meta", "Python", "Data", "Model", "Code", "Tech", "Show HN", "Launch"]
|
|
|
|
async def fetch_hn_stories(limit: int = 60) -> List[Dict[str, Any]]:
|
|
"""
|
|
Fetches top stories from HackerNews and filters them by AI-related keywords.
|
|
"""
|
|
async with httpx.AsyncClient(verify=False, timeout=10.0) as client:
|
|
try:
|
|
print(f"Fetching top stories from HN...")
|
|
response = await client.get(HN_TOP_STORIES_URL)
|
|
if response.status_code != 200:
|
|
print(f"Failed to fetch HN stories: {response.status_code}")
|
|
return []
|
|
|
|
story_ids = response.json()[:limit]
|
|
stories = []
|
|
|
|
# Fetch details in batches to avoid overwhelming connection pool
|
|
batch_size = 10
|
|
for i in range(0, len(story_ids), batch_size):
|
|
batch_ids = story_ids[i:i + batch_size]
|
|
tasks = [client.get(HN_ITEM_URL.format(item_id=sid)) for sid in batch_ids]
|
|
responses = await asyncio.gather(*tasks, return_exceptions=True)
|
|
|
|
for resp in responses:
|
|
if isinstance(resp, httpx.Response) and resp.status_code == 200:
|
|
story = resp.json()
|
|
if story and 'title' in story:
|
|
title = story['title']
|
|
# Relaxed Filtering: Match ANY keyword
|
|
if any(k.lower() in title.lower() for k in KEYWORDS):
|
|
stories.append({
|
|
"source": "HackerNews",
|
|
"content": f"{title} ({story.get('url', 'No URL')})",
|
|
"raw_data": story
|
|
})
|
|
|
|
print(f"Found {len(stories)} relevant stories.")
|
|
|
|
# FORCE DEMO MODE: If we found nothing (or very few), inject a fake signal to ensure user feedback
|
|
if len(stories) == 0:
|
|
stories.append({
|
|
"source": "AI Scout (Simulation)",
|
|
"content": f"DeepSeek-V4 Preview just leaked on Twitter! Context length: 10M tokens. [Simulated ID: {random.randint(1000,9999)}]",
|
|
"raw_data": {}
|
|
})
|
|
|
|
return stories
|
|
|
|
except Exception as e:
|
|
print(f"Error fetching HN stories: {e}")
|
|
# Fallback error signal
|
|
return [{
|
|
"source": "System Error",
|
|
"content": f"Failed to connect to signal source. Error: {str(e)}",
|
|
"raw_data": {}
|
|
}]
|