model-manager:readCatalog + DB_EXEC_SRC 全改 sys.stdout.buffer.write(防 GBK UnicodeEncodeError)
This commit is contained in:
+31
-19
@@ -69,22 +69,30 @@ function fileLog(msg: string) {
|
|||||||
// 读 catalog(只读 SQLite,OC 自身持锁但只读不冲突;用 Python 子进程读保证一致)
|
// 读 catalog(只读 SQLite,OC 自身持锁但只读不冲突;用 Python 子进程读保证一致)
|
||||||
async function readCatalog(): Promise<any | null> {
|
async function readCatalog(): Promise<any | null> {
|
||||||
try {
|
try {
|
||||||
const r = spawn("python", [
|
const py = process.platform === "win32" ? "python" : "python3"
|
||||||
"-c",
|
const r = spawn(
|
||||||
`
|
py,
|
||||||
import sqlite3, json, sys
|
[
|
||||||
db = r"${DB_PATH.replace(/\\/g, "\\\\")}"
|
"-c",
|
||||||
|
`
|
||||||
|
import sqlite3, json, sys, os
|
||||||
|
db = os.path.join(os.path.expanduser("~"), ".local", "share", "opencode", "opencode.db")
|
||||||
con = sqlite3.connect(db)
|
con = sqlite3.connect(db)
|
||||||
row = con.execute("SELECT value FROM kv WHERE key='models-dev:catalog'").fetchone()
|
row = con.execute("SELECT value FROM kv WHERE key='models-dev:catalog'").fetchone()
|
||||||
con.close()
|
con.close()
|
||||||
if not row:
|
if not row:
|
||||||
print(json.dumps({"error": "catalog row missing"}))
|
sys.stdout.buffer.write(json.dumps({"error": "catalog row missing"}).encode("utf-8"))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
print(row[0])
|
sys.stdout.buffer.write(row[0].encode("utf-8"))
|
||||||
`,
|
`,
|
||||||
], { stdio: ["ignore", "pipe", "pipe"] })
|
],
|
||||||
|
{
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
env: { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" },
|
||||||
|
},
|
||||||
|
)
|
||||||
let out = ""
|
let out = ""
|
||||||
r.stdout.on("data", (d) => (out += d))
|
r.stdout.on("data", (d) => (out += d.toString("utf-8")))
|
||||||
await new Promise((res) => r.on("close", res))
|
await new Promise((res) => r.on("close", res))
|
||||||
if (!out.trim()) return null
|
if (!out.trim()) return null
|
||||||
return JSON.parse(out.trim())
|
return JSON.parse(out.trim())
|
||||||
@@ -161,10 +169,15 @@ async function processOutbox(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SQLite 写执行器(Python,子进程独立连接)
|
// SQLite 写执行器(Python,子进程独立连接)
|
||||||
|
// 注意:Windows 控制台默认 GBK,provider/modelID 可能含非 GBK 字符 → print 会 UnicodeEncodeError。
|
||||||
|
// 所有 stdout 输出统一走 sys.stdout.buffer.write(s.encode('utf-8'))。
|
||||||
const DB_EXEC_SRC = `
|
const DB_EXEC_SRC = `
|
||||||
import sqlite3, json, sys, os, hashlib
|
import sqlite3, json, sys, os, hashlib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
def out(s):
|
||||||
|
sys.stdout.buffer.write(str(s).encode("utf-8"))
|
||||||
|
|
||||||
DB = os.path.join(os.path.expanduser("~"), ".local", "share", "opencode", "opencode.db")
|
DB = os.path.join(os.path.expanduser("~"), ".local", "share", "opencode", "opencode.db")
|
||||||
KEY = "models-dev:catalog"
|
KEY = "models-dev:catalog"
|
||||||
PRISTINE = os.path.join(os.path.expanduser("~"), ".config", "opencode", "model-manager.pristine.json")
|
PRISTINE = os.path.join(os.path.expanduser("~"), ".config", "opencode", "model-manager.pristine.json")
|
||||||
@@ -174,12 +187,11 @@ def load():
|
|||||||
row = con.execute("SELECT value FROM kv WHERE key=?", (KEY,)).fetchone()
|
row = con.execute("SELECT value FROM kv WHERE key=?", (KEY,)).fetchone()
|
||||||
con.close()
|
con.close()
|
||||||
if not row:
|
if not row:
|
||||||
sys.exit("catalog row missing")
|
out("catalog row missing"); sys.exit(0)
|
||||||
return json.loads(row[0])
|
return json.loads(row[0])
|
||||||
|
|
||||||
def save(cat):
|
def save(cat):
|
||||||
cat["updatedAt"] = int(datetime.now().timestamp() * 1000)
|
cat["updatedAt"] = int(datetime.now().timestamp() * 1000)
|
||||||
# digest = sha256(body)
|
|
||||||
import hashlib as h
|
import hashlib as h
|
||||||
cat["digest"] = h.sha256(cat["body"].encode("utf-8")).hexdigest()
|
cat["digest"] = h.sha256(cat["body"].encode("utf-8")).hexdigest()
|
||||||
con = sqlite3.connect(DB, timeout=30)
|
con = sqlite3.connect(DB, timeout=30)
|
||||||
@@ -206,14 +218,14 @@ if op == "disable":
|
|||||||
cat = load()
|
cat = load()
|
||||||
body, p = get_provider_models(cat, provider)
|
body, p = get_provider_models(cat, provider)
|
||||||
if not p:
|
if not p:
|
||||||
print("provider not found: " + provider); sys.exit(0)
|
out("provider not found: " + provider); sys.exit(0)
|
||||||
if model_id in p["models"]:
|
if model_id in p["models"]:
|
||||||
p["models"].pop(model_id, None)
|
p["models"].pop(model_id, None)
|
||||||
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
||||||
save(cat)
|
save(cat)
|
||||||
print("disabled " + provider + "/" + model_id)
|
out("disabled " + provider + "/" + model_id)
|
||||||
else:
|
else:
|
||||||
print("model not present (already disabled?): " + model_id)
|
out("model not present (already disabled?): " + model_id)
|
||||||
|
|
||||||
elif op == "enable":
|
elif op == "enable":
|
||||||
# 从 pristine 恢复该 model
|
# 从 pristine 恢复该 model
|
||||||
@@ -229,9 +241,9 @@ elif op == "enable":
|
|||||||
p["models"][model_id] = pmodels[model_id]
|
p["models"][model_id] = pmodels[model_id]
|
||||||
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
||||||
save(cat)
|
save(cat)
|
||||||
print("enabled " + provider + "/" + model_id)
|
out("enabled " + provider + "/" + model_id)
|
||||||
else:
|
else:
|
||||||
print("model not in pristine: " + model_id)
|
out("model not in pristine: " + model_id)
|
||||||
|
|
||||||
elif op == "reset":
|
elif op == "reset":
|
||||||
# 整个 provider 的 models 换回 pristine
|
# 整个 provider 的 models 换回 pristine
|
||||||
@@ -243,12 +255,12 @@ elif op == "reset":
|
|||||||
body[provider] = pbody[provider]
|
body[provider] = pbody[provider]
|
||||||
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
cat["body"] = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
|
||||||
save(cat)
|
save(cat)
|
||||||
print("reset " + provider)
|
out("reset " + provider)
|
||||||
else:
|
else:
|
||||||
print("provider not in pristine: " + provider)
|
out("provider not in pristine: " + provider)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("unknown op: " + op)
|
out("unknown op: " + op)
|
||||||
`
|
`
|
||||||
|
|
||||||
// 把 DB 执行器落盘(首次 setup 时写一次,幂等)
|
// 把 DB 执行器落盘(首次 setup 时写一次,幂等)
|
||||||
|
|||||||
Reference in New Issue
Block a user