astrbot_help / main.py
qa1145's picture
Upload 28 files
d347708 verified
#!/usr/bin/env python3
"""
代码阅读智能助手
使用方法:
python main.py
python main.py --code-dir /path/to/code
"""
import os
import sys
import argparse
import re
from pathlib import Path
from src.agent import ReadAgent
from src.api_key_manager import init_manager, ApiKeyManager
def load_env_file(env_path: str = ".env") -> dict:
"""
使用标准库加载 .env 文件
"""
env_vars = {}
env_file = Path(env_path)
if env_file.exists():
with open(env_file, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
# 跳过注释和空行
if not line or line.startswith("#"):
continue
# 解析 KEY=VALUE 格式
match = re.match(r'^([A-Za-z_][A-Za-z0-9_]*)=(.*)$', line)
if match:
key = match.group(1)
value = match.group(2).strip('"').strip("'")
env_vars[key] = value
return env_vars
def get_env(key: str, default: str = "") -> str:
"""获取环境变量,优先使用系统环境变量,其次使用 .env 文件"""
value = os.getenv(key)
if value is not None:
return value
# 尝试从 .env 加载
if not hasattr(get_env, "_env_cache"):
get_env._env_cache = load_env_file()
return get_env._env_cache.get(key, default)
def get_env_bool(key: str, default: bool = False) -> bool:
"""获取布尔型环境变量"""
value = get_env(key, "").lower()
if value in ("true", "1", "yes", "on"):
return True
elif value in ("false", "0", "no", "off"):
return False
return default
def parse_args():
"""解析命令行参数"""
parser = argparse.ArgumentParser(
description="Read Agent - 代码阅读智能助手",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
python main.py
python main.py --code-dir /path/to/your/code
python main.py --api-key sk-xxx
"""
)
parser.add_argument(
"--code-dir", "-d",
default=get_env("CODE_DIR", "."),
help="代码目录路径 (默认: 当前目录)"
)
parser.add_argument(
"--api-key", "-k",
default=get_env("OPENAI_API_KEY", ""),
help="OpenAI API Key"
)
parser.add_argument(
"--base-url", "-b",
default=get_env("OPENAI_BASE_URL", "https://api.openai.com/v1"),
help="API 基础 URL"
)
parser.add_argument(
"--model", "-m",
default=get_env("OPENAI_MODEL", "gpt-4"),
help="模型名称"
)
parser.add_argument(
"--max-steps", "-s",
type=int,
default=int(get_env("MAX_STEPS", "10")),
help="最大步骤数"
)
parser.add_argument(
"--stream-output", "--stream",
action="store_true",
default=get_env_bool("STREAM_OUTPUT", True),
help="启用流式输出(每步实时显示)"
)
parser.add_argument(
"--no-stream",
action="store_true",
default=False,
help="禁用流式输出"
)
parser.add_argument(
"--tree-depth",
type=int,
default=int(get_env("TREE_DEPTH", "3")),
help="预加载目录树深度(默认: 3)"
)
parser.add_argument(
"--max-retries",
type=int,
default=int(get_env("MAX_RETRIES", "3")),
help="API 调用最大重试次数(默认: 3)"
)
parser.add_argument(
"--retry-delays",
type=str,
default=get_env("RETRY_DELAYS", "1,2,4"),
help="重试延迟策略,逗号分隔,单位:秒(默认: 1,2,4)"
)
return parser.parse_args()
def print_welcome():
"""打印欢迎信息"""
print("""
╔════════════════════════════════════════════════════════════╗
║ Read Agent v1.0.0 ║
╠════════════════════════════════════════════════════════════╣
║ 命令: ║
║ quit / exit / q - 退出 ║
║ clear - 清空对话历史 ║
║ status - 查看状态 ║
║ help - 显示帮助 ║
╚════════════════════════════════════════════════════════════╝
""")
def print_help():
"""打印帮助信息"""
print("""
可用命令:
quit / exit / q - 退出程序
clear - 清空对话历史和 Memory
status - 查看当前状态(对话轮数、Memory数量等)
help - 显示此帮助信息
示例问题:
🤔 这个项目是做什么的?
🤔 用户认证是如何实现的?
🤔 找到处理 API 请求的代码
🤔 这个函数的作用是什么?
🤔 数据库连接是怎么配置的?
""")
def main():
"""主函数"""
# 解析参数
args = parse_args()
# 初始化 API Key 管理器
api_keys = args.api_key or get_env("OPENAI_API_KEY", "")
if api_keys:
key_manager = init_manager(api_keys)
print(f"✅ API Key 管理器已初始化,共 {key_manager.key_count} 个 Key")
else:
print("❌ 错误: 请设置 OPENAI_API_KEY 环境变量或使用 --api-key 参数")
print("\n设置方式:")
print(" 方式1: echo 'OPENAI_API_KEY=your-api-key' > .env")
print(" 方式2: export OPENAI_API_KEY=your-api-key")
print(" 方式3: python main.py --api-key your-api-key")
print("\n支持多 key(逗号分隔):")
print(" OPENAI_API_KEY=key1,key2,key3")
print(" python main.py --api-key 'key1,key2,key3'")
sys.exit(1)
# 创建 Agent
stream_output = args.stream_output and not args.no_stream
# 解析重试延迟配置(支持浮点数)
retry_delays = [float(d.strip()) for d in args.retry_delays.split(",")] if args.retry_delays else [1, 2, 4]
agent = ReadAgent(
code_dir=args.code_dir,
base_url=args.base_url,
model=args.model,
max_steps=args.max_steps,
stream_output=stream_output,
tree_depth=args.tree_depth,
api_key_manager=key_manager,
max_retries=args.max_retries,
retry_delays=retry_delays
)
# 打印欢迎信息
print_welcome()
print(f"📁 代码目录: {agent.searcher.root_dir}")
print(f"🤖 使用模型: {agent.model}")
print(f"📝 最大步骤: {agent.max_steps}")
print(f"🌳 目录树深度: {agent.tree_depth}")
print()
# 初始化提示
print("💡 输入问题开始对话,输入 help 查看帮助")
print()
# 主循环
while True:
try:
user_input = input("🤔 ").strip()
# 处理空输入
if not user_input:
continue
# 处理命令
if user_input.lower() in ["quit", "exit", "q"]:
print("👋 再见!")
break
elif user_input.lower() == "clear":
agent.clear_history()
print("✅ 已清空对话历史和 Memory")
continue
elif user_input.lower() == "status":
stats = agent.get_stats()
print(f"\n📊 状态统计:")
print(f" 对话轮数: {stats['conversation_length']}")
print(f" Memory 数量: {stats['memory_count']}")
print(f" 总步骤数: {stats['total_steps']}")
print(f" 代码目录: {stats['code_dir']}")
continue
elif user_input.lower() == "help":
print_help()
continue
# 处理问题
print()
response = agent.ask(user_input)
print(response)
except KeyboardInterrupt:
print("\n👋 再见!")
break
except Exception as e:
print(f"\n❌ 错误: {e}")
print("💡 提示: 检查 API Key 和网络连接")
if __name__ == "__main__":
main()