web-research-agent / sources.py
BonusLockSMith's picture
Upload folder using huggingface_hub
3e0f245 verified
Raw History Blame Contribute Delete
3.25 kB
#!/usr/bin/env python
"""Source adapters for the Web Research Agent (#13) β€” different areas need different sources.
Every adapter is keyless and returns the same shape [{title,url,snippet,source}] so the agent can
fetch + cite uniformly. Areas map to a blend of adapters:
web β†’ general web (opportunity/competitive/client baseline)
opportunity β†’ web + fresh news
competitive β†’ web + fresh news
technical β†’ web + arXiv + GitHub
client β†’ web
"""
import urllib.parse
import requests
import feedparser
from search import search as web_search, search_news
_UA = "Mozilla/5.0 (compatible; GritAI-Research/1.0)"
def arxiv(query: str, n: int = 4) -> list:
"""arXiv abstracts (keyless Atom API). Abstract pages are readable/fetchable."""
url = ("http://export.arxiv.org/api/query?search_query=all:"
f"{urllib.parse.quote(query)}&start=0&max_results={int(n)}&sortBy=relevance")
d = feedparser.parse(url)
out = []
for e in d.entries[:n]:
link = e.get("link", "")
out.append({"title": e.get("title", "").replace("\n", " ").strip(),
"url": link, "snippet": (e.get("summary", "") or "")[:300], "source": "arxiv"})
return [r for r in out if r["url"]]
def github(query: str, n: int = 4) -> list:
"""GitHub repository search (keyless public API; low-volume friendly)."""
try:
r = requests.get("https://api.github.com/search/repositories",
params={"q": query, "sort": "stars", "per_page": n},
headers={"User-Agent": _UA, "Accept": "application/vnd.github+json"}, timeout=15)
items = r.json().get("items", [])
return [{"title": f"{it['full_name']} (β˜…{it.get('stargazers_count', 0)})",
"url": it["html_url"], "snippet": (it.get("description") or "")[:300], "source": "github"}
for it in items[:n]]
except Exception:
return []
AREAS = {
"web": [("web", 1.0)],
"opportunity": [("web", 0.6), ("news", 0.4)],
"competitive": [("web", 0.6), ("news", 0.4)],
"technical": [("web", 0.5), ("arxiv", 0.25), ("github", 0.25)],
"client": [("web", 1.0)],
}
_ADAPTERS = {"web": web_search, "news": search_news, "arxiv": arxiv, "github": github}
def search_area(query: str, area: str = "web", n: int = 6) -> list:
"""Blend results from the adapters mapped to `area`, deduped by URL."""
plan = AREAS.get(area, AREAS["web"])
seen, out = set(), []
for name, weight in plan:
want = max(1, round(n * weight))
try:
hits = _ADAPTERS[name](query, want + 1)
except Exception:
hits = []
for h in hits[:want]:
key = (h["url"] or "").split("#")[0].rstrip("/")
if key and key not in seen:
seen.add(key)
out.append(h)
return out[:n]
if __name__ == "__main__":
import sys, json
area = sys.argv[1] if len(sys.argv) > 1 else "technical"
q = " ".join(sys.argv[2:]) or "retrieval augmented generation agents"
print(f"area={area} query={q}")
for r in search_area(q, area, 8):
print(f" [{r['source']}] {r['title'][:64]} β€” {r['url'][:70]}")