全中文输出 + 积极正向的状态提示
所有 doctor 输出和渠道描述改为中文。 状态提示从'不支持/需要配置'的语气改为'配置一下就能用'。 Before: ⬜ Reddit posts — Need config: reddit_proxy After: ⬜ Reddit 帖子和评论 — 配个代理就能用 Before: ⬜ XiaoHongShu — Need config: xhs_cookie After: ⬜ 小红书笔记 — 导入浏览器 Cookie 就能用
This commit is contained in:
parent
904f8dfb49
commit
2098dacd37
13 changed files with 54 additions and 44 deletions
28
README.md
28
README.md
|
|
@ -108,25 +108,25 @@ agent-eyes configure proxy http://用户名:密码@IP:端口
|
|||
```
|
||||
$ agent-eyes doctor
|
||||
|
||||
👁️ Agent Eyes Status
|
||||
👁️ Agent Eyes 状态
|
||||
========================================
|
||||
|
||||
✅ Ready (no setup needed):
|
||||
✅ GitHub repos and code — Public repos only
|
||||
✅ Twitter/X posts — Full access (search + timeline + threads)
|
||||
✅ YouTube video transcripts — yt-dlp
|
||||
⚠️ Bilibili video info — May be blocked on servers
|
||||
✅ RSS and Atom feeds — feedparser
|
||||
✅ Web pages (any URL) — Jina Reader API
|
||||
✅ 装好即用:
|
||||
✅ GitHub 仓库和代码 — 公开仓库可用。配置 github_token 可访问私有仓库
|
||||
✅ Twitter/X 推文 — 可读取推文。安装 birdx + 配置 Cookie 可解锁搜索和发推
|
||||
✅ YouTube 视频字幕 — yt-dlp
|
||||
⚠️ B站视频信息和字幕 — 服务器 IP 可能被封,配置代理即可解决
|
||||
✅ RSS/Atom 订阅源 — feedparser
|
||||
✅ 网页(任意 URL) — Jina Reader API
|
||||
|
||||
🔍 Search (need free Exa API key):
|
||||
⬜ Semantic web search
|
||||
🔍 搜索(免费 Exa Key 即可解锁):
|
||||
⬜ 全网语义搜索 — 注册 exa.ai 获取免费 Key,配置一下就能用
|
||||
|
||||
🔧 Optional (advanced setup):
|
||||
⬜ Reddit posts and comments — Need proxy
|
||||
⬜ XiaoHongShu (小红书) — Need cookies
|
||||
🔧 配置后可用:
|
||||
⬜ Reddit 帖子和评论 — 配个代理就能用
|
||||
⬜ 小红书笔记 — 导入浏览器 Cookie 就能用
|
||||
|
||||
Status: 6/9 channels active
|
||||
状态:6/9 个渠道可用
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -118,14 +118,14 @@ class Channel(ABC):
|
|||
# Check required tools
|
||||
for tool in self.requires_tools:
|
||||
if not shutil.which(tool):
|
||||
return "off", f"Install: pip install {tool}"
|
||||
return "off", f"需要安装:pip install {tool}"
|
||||
|
||||
# Check required config
|
||||
for key in self.requires_config:
|
||||
if config and not config.get(key):
|
||||
return "off", f"Need config: {key}. Run: agent-eyes setup"
|
||||
return "off", f"需要配置 {key},运行 agent-eyes setup"
|
||||
|
||||
return "ok", f"{', '.join(self.backends) if self.backends else 'built-in'}"
|
||||
return "ok", f"{'、'.join(self.backends) if self.backends else '内置'}"
|
||||
|
||||
async def search(self, query: str, config=None, **kwargs) -> List[SearchResult]:
|
||||
"""Search this platform. Override if supported."""
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class BilibiliChannel(Channel):
|
||||
name = "bilibili"
|
||||
description = "Bilibili video info and subtitles"
|
||||
description = "B站视频信息和字幕"
|
||||
backends = ["Bilibili API"]
|
||||
tier = 0
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ class BilibiliChannel(Channel):
|
|||
def check(self, config=None):
|
||||
proxy = config.get("bilibili_proxy") if config else None
|
||||
if proxy:
|
||||
return "ok", "Via proxy"
|
||||
return "ok", "已配置代理,完整可用"
|
||||
# Detect if we're on a server (same logic as cli._detect_environment)
|
||||
import os
|
||||
indicators = [
|
||||
|
|
@ -34,8 +34,8 @@ class BilibiliChannel(Channel):
|
|||
]
|
||||
is_server = any(indicators)
|
||||
if is_server:
|
||||
return "warn", "May be blocked on servers. Fix: agent-eyes configure proxy URL"
|
||||
return "ok", "Local access"
|
||||
return "warn", "服务器 IP 可能被封,配置代理即可解决:agent-eyes configure proxy URL"
|
||||
return "ok", "本地直连可用"
|
||||
|
||||
async def read(self, url: str, config=None) -> ReadResult:
|
||||
# Proxy support (Bilibili blocks server IPs)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from typing import List
|
|||
|
||||
class ExaSearchChannel(Channel):
|
||||
name = "exa_search"
|
||||
description = "Semantic web search (powers Reddit/Twitter search too)"
|
||||
description = "全网语义搜索(同时支持 Reddit/Twitter 搜索)"
|
||||
backends = ["Exa API"]
|
||||
requires_config = ["exa_api_key"]
|
||||
tier = 1
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from typing import List
|
|||
|
||||
class GitHubChannel(Channel):
|
||||
name = "github"
|
||||
description = "GitHub repos and code"
|
||||
description = "GitHub 仓库和代码"
|
||||
backends = ["GitHub API"]
|
||||
tier = 0
|
||||
|
||||
|
|
@ -29,8 +29,8 @@ class GitHubChannel(Channel):
|
|||
def check(self, config=None):
|
||||
token = config.get("github_token") if config else None
|
||||
if token:
|
||||
return "ok", "Full access (authenticated)"
|
||||
return "ok", "Public repos only. Set github_token for private repos + higher rate limits"
|
||||
return "ok", "已认证,可访问私有仓库"
|
||||
return "ok", "公开仓库可用。配置 github_token 可访问私有仓库"
|
||||
|
||||
def can_handle(self, url: str) -> bool:
|
||||
domain = urlparse(url).netloc.lower()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class RedditChannel(Channel):
|
||||
name = "reddit"
|
||||
description = "Reddit posts and comments"
|
||||
description = "Reddit 帖子和评论"
|
||||
backends = ["Reddit JSON API"]
|
||||
requires_config = ["reddit_proxy"]
|
||||
tier = 2
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class RSSChannel(Channel):
|
||||
name = "rss"
|
||||
description = "RSS and Atom feeds"
|
||||
description = "RSS/Atom 订阅源"
|
||||
backends = ["feedparser"]
|
||||
tier = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import requests
|
|||
|
||||
class TwitterChannel(Channel):
|
||||
name = "twitter"
|
||||
description = "Twitter/X posts"
|
||||
description = "Twitter/X 推文"
|
||||
backends = ["birdx", "Jina Reader"]
|
||||
tier = 0 # Single tweet reading is zero-config
|
||||
|
||||
|
|
@ -27,8 +27,8 @@ class TwitterChannel(Channel):
|
|||
def check(self, config=None):
|
||||
# Basic reading always works (Jina fallback)
|
||||
if shutil.which("birdx"):
|
||||
return "ok", "Full access (search + timeline + threads)"
|
||||
return "ok", "Read-only (single tweets via Jina). Install birdx for search + timelines"
|
||||
return "ok", "搜索、时间线、发推全部可用"
|
||||
return "ok", "可读取推文。安装 birdx + 配置 Cookie 可解锁搜索和发推"
|
||||
return "ok", "Jina Reader (single tweets only)"
|
||||
|
||||
async def read(self, url: str, config=None) -> ReadResult:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class WebChannel(Channel):
|
||||
name = "web"
|
||||
description = "Web pages (any URL)"
|
||||
description = "网页(任意 URL)"
|
||||
backends = ["Jina Reader API"]
|
||||
tier = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class XiaoHongShuChannel(Channel):
|
||||
name = "xiaohongshu"
|
||||
description = "XiaoHongShu (小红书) notes"
|
||||
description = "小红书笔记"
|
||||
backends = ["XHS Web API"]
|
||||
requires_config = ["xhs_cookie"]
|
||||
tier = 2
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from .base import Channel, ReadResult
|
|||
|
||||
class YouTubeChannel(Channel):
|
||||
name = "youtube"
|
||||
description = "YouTube video transcripts"
|
||||
description = "YouTube 视频字幕"
|
||||
backends = ["yt-dlp"]
|
||||
requires_tools = ["yt-dlp"]
|
||||
tier = 0
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def check_all(config: Config) -> Dict[str, dict]:
|
|||
def format_report(results: Dict[str, dict]) -> str:
|
||||
"""Format results as a readable text report."""
|
||||
lines = []
|
||||
lines.append("👁️ Agent Eyes Status")
|
||||
lines.append("👁️ Agent Eyes 状态")
|
||||
lines.append("=" * 40)
|
||||
|
||||
ok_count = sum(1 for r in results.values() if r["status"] == "ok")
|
||||
|
|
@ -35,7 +35,7 @@ def format_report(results: Dict[str, dict]) -> str:
|
|||
|
||||
# Tier 0 — zero config
|
||||
lines.append("")
|
||||
lines.append("✅ Ready (no setup needed):")
|
||||
lines.append("✅ 装好即用:")
|
||||
for key, r in results.items():
|
||||
if r["tier"] == 0:
|
||||
if r["status"] == "ok":
|
||||
|
|
@ -49,23 +49,33 @@ def format_report(results: Dict[str, dict]) -> str:
|
|||
tier1 = {k: r for k, r in results.items() if r["tier"] == 1}
|
||||
if tier1:
|
||||
lines.append("")
|
||||
lines.append("🔍 Search (need free Exa API key):")
|
||||
lines.append("🔍 搜索(免费 Exa Key 即可解锁):")
|
||||
for key, r in tier1.items():
|
||||
icon = "✅" if r["status"] == "ok" else "⬜"
|
||||
lines.append(f" {icon} {r['name']}")
|
||||
if r["status"] == "ok":
|
||||
lines.append(f" ✅ {r['name']}")
|
||||
else:
|
||||
lines.append(f" ⬜ {r['name']} — 注册 exa.ai 获取免费 Key,配置一下就能用")
|
||||
|
||||
# Tier 2 — optional setup
|
||||
tier2 = {k: r for k, r in results.items() if r["tier"] == 2}
|
||||
if tier2:
|
||||
lines.append("")
|
||||
lines.append("🔧 Optional (advanced setup):")
|
||||
lines.append("🔧 配置后可用:")
|
||||
for key, r in tier2.items():
|
||||
icon = "✅" if r["status"] == "ok" else "⬜"
|
||||
lines.append(f" {icon} {r['name']} — {r['message']}")
|
||||
if r["status"] == "ok":
|
||||
lines.append(f" ✅ {r['name']} — {r['message']}")
|
||||
else:
|
||||
# Friendly message about what to configure
|
||||
if "proxy" in str(r.get("message", "")):
|
||||
lines.append(f" ⬜ {r['name']} — 配个代理就能用:agent-eyes configure proxy URL")
|
||||
elif "cookie" in str(r.get("message", "")):
|
||||
lines.append(f" ⬜ {r['name']} — 导入浏览器 Cookie 就能用:agent-eyes configure --from-browser chrome")
|
||||
else:
|
||||
lines.append(f" ⬜ {r['name']} — {r['message']}")
|
||||
|
||||
lines.append("")
|
||||
lines.append(f"Status: {ok_count}/{total} channels active")
|
||||
lines.append(f"状态:{ok_count}/{total} 个渠道可用")
|
||||
if ok_count < total:
|
||||
lines.append("Run `agent-eyes setup` to unlock more!")
|
||||
lines.append("运行 `agent-eyes setup` 解锁更多渠道")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@ class TestDoctor:
|
|||
report = format_report(results)
|
||||
assert "Agent Eyes" in report
|
||||
assert "✅" in report
|
||||
assert "channels active" in report
|
||||
assert "渠道可用" in report
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue