docs: 更新 auth_runtime 使用文档
正确模式(参考 TypeScript 版本): - auth_runtime 模块不加载 .env 文件 - 具体 skill 自己实现 load_env_local() 函数 - 在 main() 函数开始时调用 load_env_local() - 然后导入并使用 auth_runtime 新增文件: - scripts/load_env.py: 可复用的 .env 加载函数 - scripts/example_usage.py: 完整使用示例 更新: - README.md: 详细说明正确的集成方式
This commit is contained in:
parent
98ca8a3965
commit
161ebf6e9b
|
|
@ -1,56 +1,75 @@
|
|||
# @clawd/auth-runtime-py
|
||||
|
||||
Python 版本的 OpenClaw Auth Runtime,基于 `~/clawd/skills/_shared/auth-runtime` 的 TypeScript 实现。
|
||||
Python 版本的 OpenClaw Auth Runtime。
|
||||
|
||||
**注意**: 本模块**不加载 .env 文件**,只从环境变量读取配置。
|
||||
|
||||
加载 `.env.local` 应该在具体的 skill 中实现。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
your-skill/
|
||||
├── .env.local # 敏感配置(不提交到 git)
|
||||
├── scripts/
|
||||
│ ├── main.py # 加载 .env.local 并调用 auth_runtime
|
||||
│ └── load_env.py # 从 python_auth_runtime 复制
|
||||
└── pyproject.toml
|
||||
```
|
||||
|
||||
## 安装
|
||||
|
||||
### 方式 1: 作为本地包安装(推荐)
|
||||
|
||||
```bash
|
||||
# 在具体 skill 的目录中
|
||||
uv pip install /path/to/python_auth_runtime
|
||||
```
|
||||
|
||||
### 方式 2: 作为文件依赖
|
||||
|
||||
在 `pyproject.toml` 中添加:
|
||||
|
||||
```toml
|
||||
[project]
|
||||
dependencies = [
|
||||
"python-auth-runtime-py @ file:///path/to/python_auth_runtime",
|
||||
]
|
||||
```
|
||||
|
||||
### 方式 3: 复制源码
|
||||
|
||||
直接复制 `src/python_auth_runtime` 到你的项目中:
|
||||
|
||||
```bash
|
||||
cp -r /path/to/python_auth_runtime/src/python_auth_runtime ./your-skill/
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 1. 设置环境变量
|
||||
### 步骤 1: 在具体 skill 中加载 .env.local
|
||||
|
||||
```bash
|
||||
export CLIENT_KEY="your-client-key"
|
||||
export AUTH_BASE="https://api-gw-test.yuanwei-lnc.com" # 可选
|
||||
```
|
||||
|
||||
### 2. 导入并使用
|
||||
参考 `~/clawd/skills/1688-product-master/scripts/run.ts` 的 `loadEnvLocal()` 实现:
|
||||
|
||||
```python
|
||||
from python_auth_runtime import create_env_config, get_access_token, request_api_with_auto_refresh
|
||||
# your-skill/scripts/main.py
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
# 创建配置(自动从环境变量加载)
|
||||
def load_env_local():
|
||||
"""加载 .env.local 文件到环境变量"""
|
||||
script_dir = Path(__file__).parent
|
||||
env_local_path = script_dir.parent / ".env.local"
|
||||
|
||||
if env_local_path.exists():
|
||||
with open(env_local_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
eq_index = line.find("=")
|
||||
if eq_index > 0:
|
||||
key = line[:eq_index].strip()
|
||||
value = line[eq_index + 1:].strip()
|
||||
# 去除引号
|
||||
if (value.startswith('"') and value.endswith('"')) or \
|
||||
(value.startswith("'") and value.endswith("'")):
|
||||
value = value[1:-1]
|
||||
# 只设置尚未存在的环境变量
|
||||
if key not in os.environ:
|
||||
os.environ[key] = value
|
||||
|
||||
# 在 main() 函数开始时调用
|
||||
load_env_local()
|
||||
```
|
||||
|
||||
### 步骤 2: 使用 auth_runtime
|
||||
|
||||
```python
|
||||
from python_auth_runtime import create_env_config, request_api_with_auto_refresh
|
||||
|
||||
# 创建配置(自动从环境变量读取)
|
||||
config = create_env_config()
|
||||
|
||||
# 获取访问令牌(带缓存)
|
||||
token = get_access_token(dry_run=False, config=config)
|
||||
|
||||
# 发送 API 请求(自动处理令牌刷新)
|
||||
# 调用 API
|
||||
response = request_api_with_auto_refresh(
|
||||
method="POST",
|
||||
url=f"{config.auth_base}/ecom/tasks/scrape",
|
||||
|
|
@ -65,62 +84,44 @@ if response.status == 200:
|
|||
print("商品价格:", data["price"])
|
||||
```
|
||||
|
||||
## API 参考
|
||||
|
||||
### 配置
|
||||
|
||||
#### `create_env_config() -> EnvConfig`
|
||||
|
||||
从环境变量创建配置:
|
||||
|
||||
| 环境变量 | 默认值 | 说明 |
|
||||
|---------|--------|------|
|
||||
| `AUTH_BASE` | `https://api-gw-test.yuanwei-lnc.com` | 认证基础 URL |
|
||||
| `CLIENT_KEY` | **必需** | 客户端密钥 |
|
||||
| `AUTH_CACHE_DIR` | `/tmp/skill-auth-cache` | 缓存目录 |
|
||||
| `AUTH_MIN_TTL_SEC` | `60` | 最小令牌 TTL(秒) |
|
||||
|
||||
### 令牌管理
|
||||
|
||||
#### `get_access_token(dry_run, config) -> str`
|
||||
|
||||
获取访问令牌(带缓存)
|
||||
|
||||
#### `refresh_access_token(dry_run, config) -> str`
|
||||
|
||||
刷新访问令牌(绕过缓存)
|
||||
|
||||
### API 请求
|
||||
|
||||
#### `request_api(method, url, auth_token, body) -> ApiResponse`
|
||||
|
||||
发送 HTTP 请求
|
||||
|
||||
#### `request_api_with_auto_refresh(method, url, dry_run, config, body) -> ApiResponse`
|
||||
|
||||
发送 API 请求并自动刷新令牌
|
||||
|
||||
## 与 TypeScript 版本对比
|
||||
|
||||
| 特性 | TypeScript | Python |
|
||||
|------|-----------|--------|
|
||||
| 包名 | `@clawd/auth-runtime` | `@clawd/auth-runtime-py` |
|
||||
| 安装方式 | `bun add file:../_shared/auth-runtime` | `uv pip install /path/to/python_auth_runtime` |
|
||||
| 导入 | `import { ... } from '@clawd/auth-runtime'` | `from python_auth_runtime import ...` |
|
||||
| HTTP 客户端 | `fetch()` | `requests` |
|
||||
|
||||
## 示例项目
|
||||
### 完整示例
|
||||
|
||||
```python
|
||||
# your-skill/main.py
|
||||
from python_auth_runtime import create_env_config, request_api_with_auto_refresh
|
||||
#!/usr/bin/env python3
|
||||
# your-skill/scripts/main.py
|
||||
import os
|
||||
from pathlib import Path
|
||||
from python_auth_runtime import create_env_config, request_api_with_auto_refresh
|
||||
|
||||
def load_env_local():
|
||||
"""加载 .env.local 文件到环境变量"""
|
||||
script_dir = Path(__file__).parent
|
||||
env_local_path = script_dir.parent / ".env.local"
|
||||
|
||||
if env_local_path.exists():
|
||||
with open(env_local_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
eq_index = line.find("=")
|
||||
if eq_index > 0:
|
||||
key = line[:eq_index].strip()
|
||||
value = line[eq_index + 1:].strip()
|
||||
if (value.startswith('"') and value.endswith('"')) or \
|
||||
(value.startswith("'") and value.endswith("'")):
|
||||
value = value[1:-1]
|
||||
if key not in os.environ:
|
||||
os.environ[key] = value
|
||||
|
||||
def main():
|
||||
# 从环境变量加载 CLIENT_KEY
|
||||
# 加载 .env.local
|
||||
load_env_local()
|
||||
|
||||
# 创建配置
|
||||
config = create_env_config()
|
||||
|
||||
# 调用 1688 API
|
||||
# 调用 API
|
||||
response = request_api_with_auto_refresh(
|
||||
method="POST",
|
||||
url=f"{config.auth_base}/ecom/tasks/scrape",
|
||||
|
|
@ -129,35 +130,42 @@ def main():
|
|||
body={"url": "https://detail.1688.com/offer/123.html"},
|
||||
)
|
||||
|
||||
if response.status == 200:
|
||||
print("成功:", response.body)
|
||||
else:
|
||||
print("失败:", response.status, response.body)
|
||||
print(f"状态:{response.status}")
|
||||
print(f"响应:{response.body}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
## 环境变量配置
|
||||
## 环境变量
|
||||
|
||||
在项目根目录创建 `.env` 文件(不提交到 git):
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `CLIENT_KEY` | **必需** | 客户端密钥 |
|
||||
| `AUTH_BASE` | `https://api-gw-test.yuanwei-lnc.com` | 认证基础 URL |
|
||||
| `AUTH_CACHE_DIR` | `/tmp/skill-auth-cache` | 缓存目录 |
|
||||
| `AUTH_MIN_TTL_SEC` | `60` | 最小令牌 TTL(秒) |
|
||||
|
||||
## 命令行参数覆盖
|
||||
|
||||
可以在命令行设置环境变量,优先级高于 `.env.local`:
|
||||
|
||||
```bash
|
||||
# .env
|
||||
CLIENT_KEY=your-client-key-here
|
||||
AUTH_BASE=https://api-gw-test.yuanwei-lnc.com
|
||||
CLIENT_KEY="override-key" python scripts/main.py
|
||||
```
|
||||
|
||||
然后在代码中加载:
|
||||
## 测试
|
||||
|
||||
```python
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv() # 加载 .env 文件到环境变量
|
||||
|
||||
from python_auth_runtime import create_env_config
|
||||
config = create_env_config()
|
||||
```bash
|
||||
cd /Users/xiaolongxia/Documents/ai-build-app/skills/excel-toolkit/python_auth_runtime
|
||||
uv run python scripts/example_usage.py
|
||||
```
|
||||
|
||||
## 许可证
|
||||
## 与 TypeScript 版本对比
|
||||
|
||||
MIT
|
||||
| 特性 | TypeScript | Python |
|
||||
|------|-----------|--------|
|
||||
| 模块 | `@clawd/auth-runtime` | `python_auth_runtime` |
|
||||
| .env 加载 | skill 自己实现 (`loadEnvLocal()`) | skill 自己实现 (`load_env_local()`) |
|
||||
| 环境变量 | `process.env` | `os.getenv()` |
|
||||
| 缓存 | `/tmp/skill-auth-cache` | `/tmp/skill-auth-cache` |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
示例:如何在具体 skill 中使用 auth_runtime
|
||||
|
||||
参考:~/clawd/skills/1688-product-master/scripts/run.ts
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 添加当前目录到路径
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
# 步骤 1: 加载 .env.local
|
||||
from load_env import load_env
|
||||
load_env() # 加载 .env.local 或 .env
|
||||
|
||||
# 步骤 2: 导入 auth_runtime
|
||||
from python_auth_runtime import create_env_config, request_api_with_auto_refresh
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("Auth Runtime 使用示例")
|
||||
print("=" * 60)
|
||||
|
||||
# 步骤 3: 创建配置(从环境变量读取)
|
||||
config = create_env_config()
|
||||
print(f"\n✓ 配置创建成功")
|
||||
print(f" AUTH_BASE: {config.auth_base}")
|
||||
print(f" CLIENT_KEY: {config.client_key[:10]}..." if config.client_key else " CLIENT_KEY: <empty>")
|
||||
|
||||
# 步骤 4: 调用 API
|
||||
print(f"\n【测试】获取访问令牌...")
|
||||
try:
|
||||
response = request_api_with_auto_refresh(
|
||||
method="POST",
|
||||
url=f"{config.auth_base}/auth/skill-credit/session",
|
||||
dry_run=False,
|
||||
config=config,
|
||||
body={"clientKey": config.client_key} if config.client_key else {},
|
||||
)
|
||||
print(f"✓ 响应状态:{response.status}")
|
||||
if response.status == 200:
|
||||
print(f" 响应体:{response.body[:100]}...")
|
||||
else:
|
||||
print(f" 响应体:{response.body}")
|
||||
except Exception as e:
|
||||
print(f"❌ 失败:{e}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
加载 .env.local 或 .env 文件到环境变量
|
||||
|
||||
在具体 skill 中使用:
|
||||
from load_env import load_env
|
||||
load_env() # 加载 .env.local 或 .env
|
||||
|
||||
参考:~/clawd/skills/1688-product-master/scripts/run.ts 中的 loadEnvLocal()
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_env(env_path: Path | None = None) -> bool:
|
||||
"""
|
||||
加载 .env.local 或 .env 文件到环境变量
|
||||
|
||||
优先级:
|
||||
1. 指定的 env_path
|
||||
2. 当前目录的 .env.local
|
||||
3. 当前目录的 .env
|
||||
4. 父目录的 .env.local
|
||||
5. 父目录的 .env
|
||||
|
||||
Returns:
|
||||
bool: 是否成功加载
|
||||
"""
|
||||
if env_path is None:
|
||||
# 查找 .env 文件
|
||||
possible_paths = [
|
||||
Path.cwd() / ".env.local",
|
||||
Path.cwd() / ".env",
|
||||
Path.cwd().parent / ".env.local",
|
||||
Path.cwd().parent / ".env",
|
||||
]
|
||||
for p in possible_paths:
|
||||
if p.exists():
|
||||
env_path = p
|
||||
break
|
||||
|
||||
if env_path is None or not env_path.exists():
|
||||
return False
|
||||
|
||||
print(f"📄 加载环境变量:{env_path}")
|
||||
|
||||
with open(env_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
# 跳过空行和注释
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
|
||||
# 解析 KEY=VALUE
|
||||
eq_index = line.find("=")
|
||||
if eq_index <= 0:
|
||||
continue
|
||||
|
||||
key = line[:eq_index].strip()
|
||||
value = line[eq_index + 1:].strip()
|
||||
|
||||
# 去除引号
|
||||
if (value.startswith('"') and value.endswith('"')) or \
|
||||
(value.startswith("'") and value.endswith("'")):
|
||||
value = value[1:-1]
|
||||
|
||||
# 只设置尚未存在的环境变量(命令行参数优先级更高)
|
||||
if key not in os.environ:
|
||||
os.environ[key] = value
|
||||
print(f" ✓ {key} = {value[:10]}..." if len(str(value)) > 10 else f" ✓ {key} = {value}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
env_file = Path(sys.argv[1]) if len(sys.argv) > 1 else None
|
||||
|
||||
if load_env(env_file):
|
||||
print("\n✅ 环境变量加载成功")
|
||||
print(f"\n当前环境变量:")
|
||||
for key in ["CLIENT_KEY", "AUTH_BASE", "AUTH_CACHE_DIR"]:
|
||||
value = os.getenv(key, "<not set>")
|
||||
print(f" {key} = {value[:10]}..." if len(str(value)) > 10 else f" {key} = {value}")
|
||||
else:
|
||||
print("❌ 未找到 .env 文件")
|
||||
sys.exit(1)
|
||||
Loading…
Reference in New Issue