fix: Codex 自动压缩不触发 —— 接管时链接模型目录(绝对路径)进 config.toml (hot 1.5.83)
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
// 在发布机执行:把免费多模态网关凭据写进未跟踪的打包资源。
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const key = String(process.env.TD_MULTIMODAL_GATEWAY_KEY || "").trim();
|
||||
if (!key) {
|
||||
console.error("缺少 TD_MULTIMODAL_GATEWAY_KEY,未生成多模态网关配置。");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const projectTarget = path.join(__dirname, "..", "resources", "multimodal-gateway.json");
|
||||
const userDataTarget = path.join(
|
||||
process.env.TD_MULTIMODAL_USER_DATA_DIR || path.join(process.env.HOME || process.cwd(), "Library", "Application Support", "codex-market"),
|
||||
"multimodal-gateway.json"
|
||||
);
|
||||
const config = {
|
||||
baseUrl: String(process.env.TD_MULTIMODAL_GATEWAY_URL || "https://api.tokendun.com").trim(),
|
||||
key,
|
||||
model: String(process.env.TD_MULTIMODAL_MODEL || "MiniMax-M3").trim(),
|
||||
sttModel: String(process.env.TD_MULTIMODAL_STT_MODEL || "").trim(),
|
||||
};
|
||||
for (const target of Array.from(new Set([projectTarget, userDataTarget]))) {
|
||||
fs.mkdirSync(path.dirname(target), { recursive: true });
|
||||
fs.writeFileSync(target, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 });
|
||||
console.log(`已生成 ${path.relative(process.cwd(), target)}`);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env node
|
||||
// publish-codex-installer.js —— 发布 Codex 安装器资源到自建 gitea。
|
||||
//
|
||||
// 用法:
|
||||
// node scripts/publish-codex-installer.js /Users/mac/Downloads/Codex-Windows-x64.msix
|
||||
// node scripts/publish-codex-installer.js /Users/mac/Downloads/ChatGPT.dmg
|
||||
// token 可设置 GIT_TOKEN,或写入 ~/.tokendun-git-token。
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
const { execFileSync, spawnSync } = require("child_process");
|
||||
|
||||
const OWNER = "mhgmh";
|
||||
const REPO = "codex-market-app";
|
||||
const TAG = "codex-installers";
|
||||
const MSIX_NAME = "Codex-Windows-x64.msix";
|
||||
const DMG_NAME = "ChatGPT.dmg";
|
||||
const ALLOWED_NAMES = new Set([MSIX_NAME, DMG_NAME]);
|
||||
const API = `https://up.tokendun.cc/api/v1/repos/${OWNER}/${REPO}`;
|
||||
const DL = `https://update.tokendun.cc/${OWNER}/${REPO}/releases/download/${TAG}`;
|
||||
|
||||
const installerPath = path.resolve(process.argv[2] || "/Users/mac/Downloads/Codex-Windows-x64.msix");
|
||||
const installerName = path.basename(installerPath);
|
||||
if (!ALLOWED_NAMES.has(installerName)) {
|
||||
console.error(`安装包文件名必须是 ${Array.from(ALLOWED_NAMES).join(" 或 ")},当前是 ${installerName}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (!fs.existsSync(installerPath)) {
|
||||
console.error(`安装包不存在:${installerPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let token = process.env.GIT_TOKEN || "";
|
||||
if (!token) {
|
||||
try { token = fs.readFileSync(path.join(os.homedir(), ".tokendun-git-token"), "utf8").trim(); } catch {}
|
||||
}
|
||||
if (!token) {
|
||||
console.error("缺少 gitea token:设置 GIT_TOKEN 或写入 ~/.tokendun-git-token");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function hashFile(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const h = crypto.createHash("sha256");
|
||||
fs.createReadStream(file)
|
||||
.on("data", (chunk) => h.update(chunk))
|
||||
.on("error", reject)
|
||||
.on("end", () => resolve(h.digest("hex")));
|
||||
});
|
||||
}
|
||||
|
||||
function api(method, urlPath, body) {
|
||||
const args = ["-s", "-X", method, "-H", `Authorization: token ${token}`, `${API}${urlPath}`];
|
||||
if (body !== undefined) {
|
||||
args.push("-H", "Content-Type: application/json", "-d", JSON.stringify(body));
|
||||
}
|
||||
return execFileSync("curl", args, { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
|
||||
}
|
||||
|
||||
function apiJson(method, urlPath, body) {
|
||||
const out = api(method, urlPath, body);
|
||||
try { return JSON.parse(out); } catch { return null; }
|
||||
}
|
||||
|
||||
function upload(rel, file, name) {
|
||||
const result = spawnSync("curl", [
|
||||
"--progress-bar",
|
||||
"-o", "/dev/null",
|
||||
"-w", "%{http_code}",
|
||||
"-X", "POST",
|
||||
"-H", `Authorization: token ${token}`,
|
||||
"-F", `attachment=@${file};type=application/octet-stream`,
|
||||
`${API}/releases/${rel.id}/assets?name=${encodeURIComponent(name)}`,
|
||||
], { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"], maxBuffer: 64 * 1024 * 1024 });
|
||||
if (result.error) throw result.error;
|
||||
const code = String(result.stdout || "").trim();
|
||||
console.log(`上传 ${name} → HTTP ${code}`);
|
||||
if (code !== "201") {
|
||||
console.error(`上传失败:${name}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const stat = fs.statSync(installerPath);
|
||||
console.log(`准备发布 ${installerName}:${(stat.size / 1048576).toFixed(2)}MB`);
|
||||
const sha256 = await hashFile(installerPath);
|
||||
const shaPath = path.join(os.tmpdir(), `${installerName}.sha256`);
|
||||
fs.writeFileSync(shaPath, `${sha256} ${installerName}\n`);
|
||||
console.log(`sha256=${sha256}`);
|
||||
|
||||
let rel = apiJson("GET", `/releases/tags/${encodeURIComponent(TAG)}`);
|
||||
if (!rel || !rel.id) {
|
||||
console.log(`创建 release ${TAG} …`);
|
||||
rel = apiJson("POST", "/releases", {
|
||||
tag_name: TAG,
|
||||
target_commitish: "main",
|
||||
name: "Codex 安装器资源",
|
||||
body: "TD工具箱内置安装器使用的远程安装包资源。",
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
});
|
||||
}
|
||||
if (!rel || !rel.id) {
|
||||
console.error(`无法创建/获取 release ${TAG}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const existing = new Map((rel.assets || []).map((a) => [a.name, a.id]));
|
||||
for (const name of [installerName, `${installerName}.sha256`]) {
|
||||
if (existing.has(name)) {
|
||||
api("DELETE", `/releases/${rel.id}/assets/${existing.get(name)}`);
|
||||
console.log(`删除旧 asset: ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
upload(rel, installerPath, installerName);
|
||||
upload(rel, shaPath, `${installerName}.sha256`);
|
||||
|
||||
console.log("\n发布完成:");
|
||||
console.log(` ${DL}/${installerName}`);
|
||||
console.log(` ${DL}/${installerName}.sha256`);
|
||||
})();
|
||||
@@ -0,0 +1,46 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const media = require("../electron/lib/media-understanding");
|
||||
const { gatewayConfig } = require("../electron/lib/multimodal-config");
|
||||
|
||||
const imagePath = process.argv[2] || path.join(__dirname, "..", "renderer", "logo.png");
|
||||
const config = gatewayConfig();
|
||||
|
||||
if (!config.key) {
|
||||
console.error("缺少多模态网关 Key:请先生成 resources/multimodal-gateway.json,或设置 TD_MULTIMODAL_GATEWAY_KEY。");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const ext = path.extname(imagePath).toLowerCase();
|
||||
const mime =
|
||||
ext === ".jpg" || ext === ".jpeg" ? "image/jpeg" :
|
||||
ext === ".webp" ? "image/webp" :
|
||||
"image/png";
|
||||
const data = fs.readFileSync(imagePath).toString("base64");
|
||||
const request = {
|
||||
input: [{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "请识别这张图片里的主要内容和可见文字。" },
|
||||
{ type: "input_image", image_url: `data:${mime};base64,${data}` },
|
||||
],
|
||||
}],
|
||||
};
|
||||
|
||||
media.enrichResponsesRequest(request, { instruction: "请识别这张图片里的主要内容和可见文字。" })
|
||||
.then((result) => {
|
||||
if (!result.processed) throw new Error("没有检测到可处理的图片附件");
|
||||
const evidence = result.evidence || {};
|
||||
console.log(JSON.stringify({
|
||||
provider: evidence.provider,
|
||||
modality: evidence.modality,
|
||||
summary: evidence.summary,
|
||||
items: evidence.items,
|
||||
unsupported: evidence.unsupported,
|
||||
}, null, 2));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(String((error && error.message) || error));
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user