WWW.YOUINFO.SITE
标签聚合 稍作

/tag/稍作

LinuxDo 最新话题 · 2026-05-30 21:25:50+08:00 · tech

如题所示,CLI Proxy API,也就是 CPA,它是支持导出已登录的 Codex 凭据的,我们只要稍作调整即可适配到 OpenCode 上。 到 CPA 下载 Codex 凭据: 运行下面的代码,需要 Python 3.10+ 神秘代码: """Convert CPA/CLIProxyAPI Codex OAuth credentials to opencode auth.json.""" from __future__ import annotations import json import os import shutil import sys from datetime import datetime, timezone from pathlib import Path from urllib.parse import unquote, urlparse DEFAULT_PROVIDER_ID = "openai" REQUIRED_FIELDS = ("access_token", "refresh_token", "expired", "account_id") def mask_token(value: object) -> str: if not isinstance(value, str) or not value: return "<missing>" if len(value) <= 12: return "******" return f"{value[:6]}...{value[-4:]}" def normalize_path(raw: str) -> Path: text = raw.strip() if text.startswith("& "): text = text[2:].strip() if (text.startswith('"') and text.endswith('"')) or ( text.startswith("'") and text.endswith("'") ): text = text[1:-1].strip() if text.lower().startswith("file:"): parsed = urlparse(text) text = unquote(parsed.path or "") if os.name == "nt" and len(text) >= 3 and text[0] == "/" and text[2] == ":": text = text[1:] text = os.path.expandvars(os.path.expanduser(text)) return Path(text).resolve() def read_json(path: Path) -> dict: with path.open("r", encoding="utf-8") as f: data = json.load(f) if not isinstance(data, dict): raise ValueError("JSON 顶层必须是对象。") return data def prompt_credential_path() -> Path: while True: raw = input("请输入 CPA/Codex 凭据 JSON 路径: ").strip() if not raw: print("路径不能为空。") continue path = normalize_path(raw) if not path.is_file(): print(f"未找到文件: {path}") continue if path.suffix.lower() != ".json": print("请输入 .json 文件。") continue return path def parse_expired_to_ms(value: object) -> tuple[int, str]: if isinstance(value, (int, float)): number = int(value) expires_ms = number if number > 10_000_000_000 else number * 1000 dt = datetime.fromtimestamp(expires_ms / 1000, tz=timezone.utc).astimezone() return expires_ms, dt.strftime("%Y-%m-%d %H:%M:%S %z") if not isinstance(value, str) or not value.strip(): raise ValueError("expired 字段不能为空。") text = value.strip() candidates = [] iso_text = text[:-1] + "+00:00" if text.endswith("Z") else text try: candidates.append(datetime.fromisoformat(iso_text)) except ValueError: pass formats = ( "%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%d %H:%M:%S%z", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S", "%Y/%m/%d %H:%M:%S", "%m/%d/%Y %H:%M:%S", ) for fmt in formats: try: candidates.append(datetime.strptime(text, fmt)) except ValueError: continue if not candidates: raise ValueError(f"无法解析 expired 时间: {text}") dt = candidates[0] expires_ms = int(dt.timestamp() * 1000) display_dt = dt.astimezone() if dt.tzinfo else datetime.fromtimestamp(dt.timestamp()).astimezone() return expires_ms, display_dt.strftime("%Y-%m-%d %H:%M:%S %z") def ask_yes_no(prompt: str, default: bool = False) -> bool: suffix = "[Y/n]" if default else "[y/N]" while True: answer = input(f"{prompt} {suffix}: ").strip().lower() if not answer: return default if answer in {"y", "yes"}: return True if answer in {"n", "no"}: return False print("请输入 y 或 n。") def default_auth_candidates() -> list[Path]: candidates: list[Path] = [] local_app_data = os.environ.get("LOCALAPPDATA") user_profile = os.environ.get("USERPROFILE") if local_app_data: candidates.append(Path(local_app_data) / "opencode" / "auth.json") if user_profile: candidates.append(Path(user_profile) / ".local" / "share" / "opencode" / "auth.json") return candidates def prompt_auth_path() -> Path: while True: raw = input("未找到默认 opencode 目录,请输入 auth.json 路径或目标目录: ").strip() if not raw: print("路径不能为空。") continue path = normalize_path(raw) if path.exists() and path.is_dir(): return path / "auth.json" if path.suffix.lower() == ".json": target = path target_dir = path.parent else: target_dir = path target = target_dir / "auth.json" if target_dir.exists(): return target if ask_yes_no(f"目标目录不存在,是否创建?{target_dir}"): target_dir.mkdir(parents=True, exist_ok=True) return target print("已取消使用该路径,请重新输入。") def resolve_auth_path() -> Path: candidates = default_auth_candidates() for candidate in candidates: if candidate.is_file(): return candidate for candidate in candidates: if candidate.parent.is_dir(): return candidate return prompt_auth_path() def load_auth(path: Path) -> dict: if not path.exists(): return {} data = read_json(path) return data def backup_auth(path: Path) -> Path | None: if not path.exists(): return None timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") backup_path = path.with_name(f"{path.name}.bak-{timestamp}") shutil.copy2(path, backup_path) return backup_path def write_auth(path: Path, auth_data: dict) -> None: path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8", newline="\n") as f: json.dump(auth_data, f, ensure_ascii=False, indent=2) f.write("\n") def validate_credential(data: dict) -> None: missing = [field for field in REQUIRED_FIELDS if not data.get(field)] if missing: raise ValueError("凭据 JSON 缺少必要字段: " + ", ".join(missing)) def main() -> int: print("Codex OAuth -> opencode auth.json 转换工具") print("安全提示: 本脚本只读取/写入本机文件,不会联网;token 只打码显示。") credential_path = prompt_credential_path() try: credential = read_json(credential_path) validate_credential(credential) expires_ms, expires_human = parse_expired_to_ms(credential["expired"]) except Exception as exc: print(f"读取或解析凭据失败: {exc}") return 1 provider_id = input(f"请输入 provider ID,直接回车默认 {DEFAULT_PROVIDER_ID}: ").strip() if not provider_id: provider_id = DEFAULT_PROVIDER_ID auth_path = resolve_auth_path() print("\n即将写入:") print(f"凭据文件: {credential_path}") print(f"auth.json: {auth_path}") print(f"provider ID: {provider_id}") print(f"access_token: {mask_token(credential.get('access_token'))}") print(f"refresh_token: {mask_token(credential.get('refresh_token'))}") print(f"expires: {expires_human} ({expires_ms})") print(f"account_id: {credential.get('account_id')}") if credential.get("id_token"): print("id_token: 已忽略") if credential.get("email"): print(f"email: {credential.get('email')}") if not ask_yes_no("确认写入?"): print("已取消,未写入任何文件。") return 0 try: auth_data = load_auth(auth_path) backup_path = backup_auth(auth_path) auth_data[provider_id] = { "type": "oauth", "refresh": credential["refresh_token"], "access": credential["access_token"], "expires": expires_ms, "accountId": credential["account_id"], } write_auth(auth_path, auth_data) except Exception as exc: print(f"写入失败: {exc}") return 1 print("\n写入完成:") print(f"auth.json 路径: {auth_path}") print(f"provider ID: {provider_id}") print(f"expires: {expires_human}") if backup_path: print(f"备份: 已创建 {backup_path}") else: print("备份: 未创建,原 auth.json 不存在") return 0 if __name__ == "__main__": sys.exit(main()) 按照提示输入 凭据文件位置 就好。 然后你的 C:\Users\用户名\.local\share\opencode\auth.json 大概长这样: { "openai": { "type": "oauth", "refresh": "", "access": "", "expires": 1780837337000, "accountId": "" } } 这个时候再 opencode , /models ,就会发现那个 OpenAI 官方标志的 GPT 5.5 了: 顺带一提,这是直接请求了 OpenAI Codex 官方的后端地址(Cloudflare CDN) https://chatgpt.com/backend-api/codex/responses : 2 个帖子 - 2 位参与者 阅读完整话题

www.ithome.com · 2026-05-03 15:08:31+08:00 · tech

IT之家 5 月 3 日消息,自圆满完成第三次出舱活动后,神二十一乘组稍作休整,随即投入到新一轮的在轨工作中。“五一”假期,神舟二十一号航天员乘组张陆、武飞、张洪章值守在中国空间站, 他们已经在轨驻留满 6 个月 ,官方发布最新一期“太空出差”Vlog。 IT之家从视频获悉,在轨脑电测试研究进展顺利, 乘组利用脑电采集设备、VR 眼镜等 ,开展弱刺激脑机、微重力直觉物理、空间合作编码及调控等多项脑电实验测试,地面科研人员将依托下行数据开展后续研究。 在心理与行为能力研究方面,乘组完成了应急决策能力评估和在轨情绪状态测试,持续积累测试数据。 在天和核心舱内,三名航天员使用遥操作交会对接系统和平移与姿态控制手柄开展交会对接在轨训练,同步进行运动学特性实验, 通过采集微重力环境下的人体运动学数据 ,可定量分析航天员舱内操作与运动的姿态特点及规律。 此外,乘组按计划开展了再生生保系统设备检查维护工作;使用专业噪声测量仪对舱内不同区域噪声水平进行测量,完成站内声环境监测。同时,进行舱内环境清洁、物资整理等常态化平台维护工作。 在健康维护与保障方面,乘组完成了听力测试、肌肉超声检查等多项医学检查, 持续开展在轨锻炼 ,积极对抗失重生理效应。 目前,神舟二十一号乘组已在轨驻留满 6 个月,工作生活状态良好。根据当前任务需求,三名航天员将继续他们的飞天旅程。