Files
dobotai-platform/deploy/dobotai-dingtalk/configure_env.py
T

122 lines
6.5 KiB
Python

#!/usr/bin/env python3
import argparse
import getpass
import json
import os
from pathlib import Path
from urllib.parse import quote, unquote, urlsplit
import subprocess
import sys
FIELDS = (
("WEKNORA_BASE_URL", "WeKnora 地址", "应用容器通过宿主机网络访问既有WeKnora。", "http://127.0.0.1:8080", False),
("WEKNORA_API_KEY", "WeKnora API Key", "DobotAI专用WeKnora API Key。", "<你的WeKnora API Key>", True),
("DOBOTAI_QUICK_AGENT_ID", "快速问答Agent ID", "默认问答实际调用的WeKnora Agent。", "<快速问答Agent ID>", False),
("DOBOTAI_REASONING_AGENT_ID", "智能推理Agent ID", "/think和持续智能推理实际调用的WeKnora Agent。", "<智能推理Agent ID>", False),
("DINGTALK_CLIENT_ID", "钉钉 Client ID", "钉钉应用Client ID/AppKey。", "dingxxxxxxxx", False),
("DINGTALK_CLIENT_SECRET", "钉钉 Client Secret", "钉钉应用Client Secret/AppSecret。", "<你的钉钉 AppSecret>", True),
)
def prompt_rds(values):
"""分字段录入阿里云RDS并组装DATABASE_URL;已有值作为默认。"""
existing = values.get("DATABASE_URL", "").strip()
host = port = database = user = password = ""
if existing:
u = urlsplit(existing)
host = u.hostname or ""
port = str(u.port or "") if u.port else ""
database = u.path.lstrip("/")
user = unquote(u.username or "")
password = unquote(u.password or "")
def ask(key, label, default, secret=False):
suffix = "(已配置,直接回车保留)" if default else "(必填)"
reader = getpass.getpass if secret else input
entered = reader(f"{label}{suffix}: ").strip()
return entered or default
print("\n阿里云RDS PostgreSQL(分字段填写)\n用途:DobotAI专用数据库;空库自动初始化,已有表只校验不改结构。")
host = ask("host", "RDS主机地址", host)
port = ask("port", "RDS端口", port or "5432")
database = ask("database", "数据库名", database)
user = ask("user", "数据库账号", user)
password = ask("password", "数据库密码", password, secret=True)
if not all((host, port, database, user, password)):
raise SystemExit("RDS字段不完整,未保存。")
if not database.startswith(("dobotai", "dobotai_")):
print("警告:数据库名不是DobotAI专用库,继续前请确认。")
values["DATABASE_URL"] = f"postgres://{quote(user, safe='')}:{quote(password, safe='')}@{host}:{port}/{database}"
OSS_FIELDS = (
("DOBOTAI_OUTBOUND_IMAGE_OSS_ENDPOINT", "OSS Endpoint", "私有Bucket的接入地址。", "https://oss-cn-shenzhen.aliyuncs.com", False),
("DOBOTAI_OUTBOUND_IMAGE_OSS_REGION", "OSS Region", "Bucket所在地域。", "cn-shenzhen", False),
("DOBOTAI_OUTBOUND_IMAGE_OSS_BUCKET", "OSS Bucket", "外发图片专用私有Bucket。", "dobot-xxx", False),
("DOBOTAI_OUTBOUND_IMAGE_OSS_ACCESS_KEY_ID", "OSS AccessKey ID", "仅授权该Bucket的AK。", "<AK ID>", False),
("DOBOTAI_OUTBOUND_IMAGE_OSS_ACCESS_KEY_SECRET", "OSS AccessKey Secret", "仅授权该Bucket的SK。", "<AK Secret>", True),
("DOBOTAI_OUTBOUND_IMAGE_PUBLIC_BASE_URL", "图片稳定外发基础地址", "钉钉可见的稳定HTTPS入口,不含凭据。", "https://host/dingtalk/i", False),
)
def prompt_oss(values):
"""OSS整组录入:全部留空即禁用;任一项填写则六项必填。"""
print("\n回答图片外发OSS(可选,OSS整组录入;直接回车表示整组禁用)")
entered = {}
for key, label, description, example, secret in OSS_FIELDS:
default = values.get(key, "").strip()
suffix = "(已配置,直接回车保留)" if default else ""
print(f"用途:{description} 格式示例:{example}")
reader = getpass.getpass if secret else input
value = reader(f"{label}{suffix}: ").strip()
entered[key] = value or default
if not any(entered.values()):
for key, *_ in OSS_FIELDS:
values.pop(key, None)
return
missing = [label for key, label, *_ in OSS_FIELDS if not entered[key]]
if missing:
raise SystemExit("OSS为整组可选能力,以下项未填写:" + "、".join(missing))
values.update(entered)
def parse_env(path):
lines = path.read_text(encoding="utf-8").splitlines(); values = {}
for line in lines:
if line and not line.lstrip().startswith("#") and "=" in line:
key, value = line.split("=", 1); values[key.strip()] = value
return lines, values
def write_env(path, lines, values):
rendered=[]; written=set()
for line in lines:
if line and not line.lstrip().startswith("#") and "=" in line:
key=line.split("=",1)[0].strip()
if key in values: rendered.append(f"{key}={values[key]}"); written.add(key); continue
rendered.append(line)
rendered.extend(f"{key}={value}" for key,value in values.items() if key not in written)
temp=path.with_name(path.name+".new"); temp.write_text("\n".join(rendered)+"\n",encoding="utf-8"); os.chmod(temp,0o600); os.replace(temp,path)
def main():
parser=argparse.ArgumentParser(description="配置DobotAI阿里云RDS和渠道凭证")
parser.add_argument("--env-file",required=True); parser.add_argument("--schema-script",required=True); parser.add_argument("--start-script",required=True)
args=parser.parse_args(); path=Path(args.env_file)
if not path.is_file(): raise SystemExit("DobotAI环境文件不存在,请先执行根目录install-docker.sh。")
lines,values=parse_env(path)
prompt_rds(values)
prompt_oss(values)
for key,label,description,example,secret in FIELDS:
suffix="(已配置,直接回车保留)" if values.get(key,"").strip() else "(必填)"
print(f"\n{label}\n用途:{description}\n格式示例:{example}")
entered=(getpass.getpass if secret else input)(f"{label}{suffix}: ").strip()
if entered: values[key]=entered
missing=[label for key,label,*_ in FIELDS if not values.get(key,"").strip()]
if missing: raise SystemExit("以下必填项未配置:"+"、".join(missing))
if values["DOBOTAI_QUICK_AGENT_ID"] == values["DOBOTAI_REASONING_AGENT_ID"]:
raise SystemExit("快速问答Agent ID与智能推理Agent ID必须不同。")
values["DOBOTAI_AGENT_BINDINGS"] = json.dumps({"dingtalk:*": values["DOBOTAI_QUICK_AGENT_ID"]}, separators=(",", ":"))
write_env(path,lines,values)
subprocess.run([args.schema_script], check=True)
os.execv(args.start_script,[args.start_script])
if __name__=="__main__":
try: main()
except KeyboardInterrupt: sys.exit(130)