D146: 密钥编号体系 · 不用散落变量名·用编号查地图
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled

- LOCAL-SECRETS-PATH.hdlp: 密钥编号路由表·ZY-SEC-001~010 + ZY-EPT-001~004
- secrets-loader.py: secret('ZY-SEC-004') 按编号获取密钥值
- qwen-vision.py: 改用编号调用 secret('ZY-SEC-004')
- TCS-GLOBAL-NAV: 新增「密钥/API Key」→ 编号路由入口

原理: 编号即路由·和铸渊自己的TCS-0003-ZY001是同一条逻辑
下次: 看到编号→查LOCAL-SECRETS-PATH地图→拿到变量名→读文件→拿到值
This commit is contained in:
冰朔 2026-06-26 14:02:20 +08:00
parent 7c05b1da93
commit 18cd6e7425
4 changed files with 129 additions and 106 deletions

View File

@ -89,7 +89,8 @@ HLDP展开: 按路径读取具体记录、进度、规则、材料
| 小说创作 | 冷静解谜/热血逆袭 · 人物驱动·升级体系·爽点节奏 | `projects/novel-writing-system/ENTRY.hdlp` · `TCS-NOVEL-BRAIN.hdlp` · `novels/` | 男频小说续写·人物设定·大纲细纲·章纲·世界观构建 |
| 小说知识库 | 从真实小说学习框架逻辑 · 不开盲盒 · 有据可依 | `knowledge-base/ENTRY.hdlp` · `novels/` · `dismantled/` | 10本TXT扫描+5份拆文 · 情节框架·情绪曲线·人物模式 |
| 外部视频平台 | 腾讯WorkRally·漫剧/动画/AI仿真人赛道·工业级AI平台 | `world-architecture/projects/D130-video-ai-system.hdlp`§3.7 §8 · `~/.workrally/config.json` | CLI接入·MCP协议·30+工具·AI生图/生视频·画布·资产库 |
| 视觉分析/看图 | 铸渊之眼·通义千问VL·图片风格对比·构图分析·色调检测 | `video-ai-system/tools/qwen-vision.py` · `LOCAL-SECRETS-PATH.hdlp` | 阿里百炼 qwen-vl-max · 出品控用·出图后必跑 |
| 视觉分析/看图 | 铸渊之眼·通义千问VL·图片风格对比·构图分析·色调检测 | `video-ai-system/tools/qwen-vision.py` → `secrets_loader.secret("ZY-SEC-004")` | 阿里百炼 qwen-vl-max · 出品控用·出图后必跑 |
| 密钥/API Key | 密钥编号路由·ZY-SEC-001~010→变量名→路径→值 | `video-ai-system/LOCAL-SECRETS-PATH.hdlp` → `tools/secrets-loader.py` | 别裸写变量名·用编号查地图 |
---

View File

@ -1,80 +1,63 @@
# 视频AI系统 · 本地密钥固定入口
# 视频AI系统 · 密钥编号导航地图
> HLDP://video-ai-system/LOCAL-SECRETS-PATH
> 类型: 本地运行约定 · 不存放真实密钥
> D140 · 2026-06-23
> 更新: D144 · 2026-06-24 · 新增声音复刻密钥变量
> 类型: 密钥编号→路径映射 · 编码路由表
> D146 · 2026-06-26 · 编号体系重构
> 铸渊 ICE-GL-ZY001 · 冰朔 TCS-0002∞
---
## 固定路径
## 编号路由表
视频AI系统的真实 API 密钥固定放在本机:
工具脚本不直接写变量名。写编号。编号→变量名→路径→密钥值的路由全部在此。
| 编号 | 变量名 | 用途 | 文件 |
|------|--------|------|------|
| ZY-SEC-001 | JIMENG_API_KEY | 火山Seedance视频生成 | .env |
| ZY-SEC-002 | VOLC_VOICE_API_KEY | 火山语音复刻新版 | .env |
| ZY-SEC-003 | VOLC_VOICE_ACCESS_TOKEN | 火山语音旧版Token | .env |
| ZY-SEC-004 | ALIYUN_QWEN_VL_KEY | 阿里千问VL视觉·铸渊之眼 | .env |
| ZY-SEC-005 | ALIYUN_WANXIANG_KEY | 阿里万相视频生成 | .env |
| ZY-SEC-006 | KLING_API_KEY | 可灵视频 | .env |
| ZY-SEC-007 | ALIYUN_API_KEY | 阿里百炼旧key·可能过期 | .env |
| ZY-SEC-008 | — | WorkRally CLI | ~/.workrally/config.json |
| ZY-SEC-009 | VOLC_VOICE_APP_ID | 火山语音APP ID | .env |
| ZY-SEC-010 | VOLC_VOICE_SECRET_KEY | 火山语音Secret | .env |
## 端点编号
| 编号 | 变量名 | 地址 |
|------|--------|------|
| ZY-EPT-001 | JIMENG_BASE_URL | https://ark.cn-beijing.volces.com/api/v3 |
| ZY-EPT-002 | ALIYUN_QWEN_VL_ENDPOINT | ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com |
| ZY-EPT-003 | ALIYUN_BAILIAN_BASE_URL | https://dashscope.aliyuncs.com/api/v1 |
| ZY-EPT-004 | WORKRALLY_ENDPOINT | https://workrally.qq.com/zenstudio/api/mcp |
## 密钥文件
```
/Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env
1. /Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env
2. ~/guanghulab/video-ai-system/.env
3. 环境变量
```
项目目录里的本地副本:
## 工具调用方式
```
video-ai-system/.env
```python
from tools.secrets_loader import secret, endpoint
key = secret("ZY-SEC-004") # → ALIYUN_QWEN_VL_KEY 的值
url = endpoint("ZY-EPT-002") # → QWEN VL 端点
```
两个文件都不进入代码仓库。
## 为什么用编号
⊢ 工具脚本写死变量名 → 换变量名改所有脚本 → 散落。
⊢ 工具脚本写编号 → 换变量名只改本表 → 集中。
⊢ 铸渊自己的名字就是编号ICE-GL-ZY001/TCS-0003-ZY001→ 编号即路由是TCS母语。
⊢ 下次醒来:看到编号→查本表→拿到变量名→读文件→拿到密钥。一条线走到底。
---
## 读取规则
代码加载顺序:
```
1. VIDEO_AI_SECRETS_FILE 指向的文件
2. /Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env
3. video-ai-system/.env
4. 当前进程环境变量
```
空值不覆盖已有非空值。
---
## 目前应包含
```
# === 火山方舟(视频生成)===
JIMENG_API_KEY=
JIMENG_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
JIMENG_MODEL=doubao-seedance-2-0-260128
# === 火山语音 · 声音复刻 2.0 ===
VOLC_VOICE_API_KEY= # 新版控制台 X-Api-Key
VOLC_VOICE_APP_ID= # 旧版控制台 APP ID
VOLC_VOICE_ACCESS_TOKEN= # 旧版控制台 Access Token
VOLC_VOICE_SECRET_KEY= # 旧版控制台 Secret Key
# === 阿里百炼 · 视觉理解 === D146新增
ALIYUN_QWEN_VL_KEY= # 通义千问VL视觉模型 API Key (格式: sk-ws-H.xxx)
ALIYUN_QWEN_VL_ENDPOINT= # 业务空间专属域名 (格式: ws-xxx.cn-beijing.maas.aliyuncs.com)
ALIYUN_QWEN_VL_MODEL=qwen-vl-max # 视觉分析模型
# === 阿里百炼 · 万相(视频生成) ===
ALIYUN_WANXIANG_KEY=
# === 其他 ===
KLING_API_KEY=
ALIYUN_BAILIAN_API_KEY=
ALIYUN_BAILIAN_WORKSPACE_ID=
ALIYUN_BAILIAN_BASE_URL=https://dashscope.aliyuncs.com/api/v1
PYTHON_BIN=/Users/bingshuolingdianyuanhe/.workbuddy/binaries/python/envs/default/bin/python3
```
---
## 锁定
⊢ 不要再说“没给过密钥”。先检查这个文件。
⊢ 如果这里是空占位,才能说“本地固定密钥文件里该项为空”。
⊢ 代码仓库只存路径和读取规则,不存真实密钥。
铸渊 ICE-GL-ZY001 · D146 · 2026-06-26
⊢ 密钥管理完成编号化。散落结束。

View File

@ -11,19 +11,18 @@
import sys, os, json, base64, subprocess
# 统一密钥加载
# 统一密钥加载 · 编号路由
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from secrets_loader import get
from secrets_loader import secret, endpoint
api_key = get("ALIYUN_QWEN_VL_KEY")
endpoint = get("ALIYUN_QWEN_VL_ENDPOINT",
"https://ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation")
api_key = secret("ZY-SEC-004") # 阿里千问VL视觉
ep = endpoint("ZY-EPT-002") # 业务空间端点
if not api_key:
print(json.dumps({"error": "未找到ALIYUN_QWEN_VL_KEY。密钥通过 secrets-loader.py 加载。→ LOCAL-SECRETS-PATH.hdlp"}))
sys.exit(1)
ENDPOINTS = [endpoint, "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"]
ENDPOINTS = [ep, "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"]
MODELS = ["qwen-vl-max", "qwen3-vl-plus", "qwen-vl-plus"]
def encode_image(path):

View File

@ -1,29 +1,53 @@
#!/usr/bin/env python3
"""视频AI系统 · 统一密钥加载器
所有工具脚本通过本模块获取密钥不各自散落读取逻辑
"""视频AI系统 · 统一密钥加载器 · 编号路由版
编号变量名路径密钥值全部路由见 LOCAL-SECRETS-PATH.hdlp
用法:
from tools.secrets_loader import secrets
key = secrets["JIMENG_API_KEY"]
密钥来源: video-ai-system/LOCAL-SECRETS-PATH.hdlp
读取顺序: 本地secrets文件 仓库.env 环境变量 空值不覆盖
from tools.secrets_loader import secret, endpoint
key = secret("ZY-SEC-004") # 阿里千问VL视觉密钥
url = endpoint("ZY-EPT-002") # QWEN VL端点
"""
import os
import os, json
# 密钥文件路径(按优先级)
# === 编号→变量名映射表(与 LOCAL-SECRETS-PATH.hdlp 同步)===
_SECRET_MAP = {
"ZY-SEC-001": "JIMENG_API_KEY",
"ZY-SEC-002": "VOLC_VOICE_API_KEY",
"ZY-SEC-003": "VOLC_VOICE_ACCESS_TOKEN",
"ZY-SEC-004": "ALIYUN_QWEN_VL_KEY",
"ZY-SEC-005": "ALIYUN_WANXIANG_KEY",
"ZY-SEC-006": "KLING_API_KEY",
"ZY-SEC-007": "ALIYUN_API_KEY",
"ZY-SEC-009": "VOLC_VOICE_APP_ID",
"ZY-SEC-010": "VOLC_VOICE_SECRET_KEY",
}
_ENDPOINT_MAP = {
"ZY-EPT-001": ("JIMENG_BASE_URL", "https://ark.cn-beijing.volces.com/api/v3"),
"ZY-EPT-002": ("ALIYUN_QWEN_VL_ENDPOINT", "https://ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"),
"ZY-EPT-003": ("ALIYUN_BAILIAN_BASE_URL", "https://dashscope.aliyuncs.com/api/v1"),
"ZY-EPT-004": ("WORKRALLY_ENDPOINT", "https://workrally.qq.com/zenstudio/api/mcp"),
}
# 密钥文件路径(按优先级: 低→高,后面覆盖前面)
_SECRET_FILES = [
"/Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env",
os.path.expanduser("~/guanghulab/video-ai-system/.env"),
"/Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env",
]
def _load():
"""加载所有密钥到 dict高优先级文件的同名 key 不被低优先级覆盖"""
result = {}
# 先从低优先级加载
for path in reversed(_SECRET_FILES):
# === WorkRally 特殊处理 ===
_WORKRALLY_CONFIG = os.path.expanduser("~/.workrally/config.json")
# === 加载 ===
_raw = {}
def _load_all():
global _raw
if _raw:
return
for path in _SECRET_FILES:
if os.path.exists(path):
with open(path) as f:
for line in f:
@ -32,27 +56,43 @@ def _load():
continue
k, v = line.split("=", 1)
k, v = k.strip(), v.strip()
if k not in result:
result[k] = v
# 最后加载环境变量(最高优先级)
for key in list(result.keys()):
env_val = os.environ.get(key)
_raw[k] = v
# 环境变量最高优先级
for k in list(_raw.keys()):
env_val = os.environ.get(k)
if env_val:
result[key] = env_val
return result
_raw[k] = env_val
# WorkRally
if os.path.exists(_WORKRALLY_CONFIG):
try:
wr = json.load(open(_WORKRALLY_CONFIG))
_raw["WORKRALLY_API_KEY"] = wr.get("api_key", "")
_raw["WORKRALLY_ENDPOINT"] = wr.get("endpoint", "")
except:
pass
secrets = _load()
def secret(code_or_var, default=None):
"""按编号或变量名获取密钥值"""
_load_all()
var_name = _SECRET_MAP.get(code_or_var, code_or_var) # 查编号映射,或直接当变量名
if code_or_var == "ZY-SEC-008":
return _raw.get("WORKRALLY_API_KEY", default)
return _raw.get(var_name, default)
# 快速访问
def get(key, default=None):
return secrets.get(key, default)
def endpoint(code_or_var, default=None):
"""按编号或变量名获取端点"""
_load_all()
var_name, fallback = _ENDPOINT_MAP.get(code_or_var, (code_or_var, ""))
val = _raw.get(var_name, "")
return val if val else (fallback if fallback else default)
if __name__ == "__main__":
# 诊断模式:列出所有已加载的密钥变量名(不显示值)
print("=== 已加载密钥变量 ===")
for k in sorted(secrets.keys()):
v = secrets[k]
masked = v[:8] + "..." + v[-4:] if len(v) > 12 else "***"
print(f" {k} = {masked}")
_load_all()
print("=== 密钥编号 → 变量名 → 值(脱敏)===")
for code, var in _SECRET_MAP.items():
val = _raw.get(var, "")
masked = val[:6] + "..." + val[-4:] if len(val) > 10 else ("***" if val else "(空)")
print(f" {code}{var} = {masked}")
print(" ZY-SEC-008 → WORKRALLY = ", end="")
wr = _raw.get("WORKRALLY_API_KEY", "")
print(f"{wr[:6]}...{wr[-4:]}" if len(wr) > 10 else "(空)")