// OcrSettingsForm:OCR 引擎与 Key 设置(百度 OCR / 智谱 GLM-OCR / 千帆 / UApiPro / Umi-OCR 本地) // 保存 → exe 旁 baidu_ocr.json(engine/api_key/secret_key/glm_api_key/qianfan_api_key/uapis_api_key/umi_url) // + 热更新 OcrClient + 作废百度 token 缓存。 using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using System.Web.Script.Serialization; namespace pdfbt { public partial class OcrSettingsForm : Form { private readonly OcrClient _ocr; public OcrSettingsForm(OcrClient ocr) { InitializeComponent(); _ocr = ocr; // 回填现有配置(默认 Key 在 Designer 的 Text 里,密码遮罩显示;保存过则文件值优先) string engine = "baidu"; try { string cfgPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "baidu_ocr.json"); if (File.Exists(cfgPath)) { var jsv = new JavaScriptSerializer().Deserialize>(File.ReadAllText(cfgPath)); if (jsv != null) { if (jsv.ContainsKey("engine")) engine = jsv["engine"] ?? "baidu"; txtApiKey.Text = jsv.ContainsKey("api_key") ? (jsv["api_key"] ?? "") : ""; txtSecretKey.Text = jsv.ContainsKey("secret_key") ? (jsv["secret_key"] ?? "") : ""; txtGlmKey.Text = jsv.ContainsKey("glm_api_key") ? (jsv["glm_api_key"] ?? "") : ""; txtQianfanKey.Text = jsv.ContainsKey("qianfan_api_key") ? (jsv["qianfan_api_key"] ?? "") : ""; txtUapisKey.Text = jsv.ContainsKey("uapis_api_key") ? (jsv["uapis_api_key"] ?? "") : ""; txtUmiUrl.Text = jsv.ContainsKey("umi_url") && !string.IsNullOrWhiteSpace(jsv["umi_url"]) ? jsv["umi_url"] : "http://127.0.0.1:1224"; } } } catch { } cboEngine.SelectedIndex = engine == "glm" ? 1 : engine == "qianfan" ? 2 : engine == "uapis" ? 3 : engine == "umi" ? 4 : 0; UpdateEnginePanels(); } /// 按引擎下拉显示对应的输入区(百度=两格;智谱/千帆/UApiPro=Key一格;Umi-OCR=服务地址一格)。 private void UpdateEnginePanels() { int sel = cboEngine.SelectedIndex; bool glm = sel == 1; bool qf = sel == 2; bool ua = sel == 3; bool umi = sel == 4; bool baidu = !glm && !qf && !ua && !umi; lblApiKey.Visible = baidu; txtApiKey.Visible = baidu; lblSecretKey.Visible = baidu; txtSecretKey.Visible = baidu; lblGlmKey.Visible = glm; txtGlmKey.Visible = glm; lblQianfanKey.Visible = qf; txtQianfanKey.Visible = qf; lblUapisKey.Visible = ua; txtUapisKey.Visible = ua; lblUmiUrl.Visible = umi; txtUmiUrl.Visible = umi; btnUmi下载.Visible = umi; btnUmi检测.Visible = umi; lblUmi状态.Visible = umi; if (umi) RefreshUmiStatus(); } /// 刷新 Umi 本体三态状态显示。 private void RefreshUmiStatus() { try { lblUmi状态.Text = UmiOcrHost.DetectText(); } catch { } } /// 检测 OCR 本体:刷新状态(未安装/已安装未运行/运行中)。 private void btnUmi检测_Click(object sender, EventArgs e) { RefreshUmiStatus(); MessageBox.Show(this, UmiOcrHost.DetectText(), "检测 OCR 本体", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// 下载 OCR 本体:网盘直链(~179MB)→解压到程序目录 Umi-OCR\→验证→删 zip。 private void btnUmi下载_Click(object sender, EventArgs e) { if (UmiOcrHost.IsInstalled) { var r = MessageBox.Show(this, "OCR 本体已存在,重新下载将覆盖安装。继续吗?", "下载 OCR 本体", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); if (r != DialogResult.OK) return; } btnUmi下载.Enabled = false; btnUmi检测.Enabled = false; lblUmi状态.ForeColor = System.Drawing.Color.DimGray; lblUmi状态.Text = "正在下载… 0%"; int lastPct = -1; UmiOcrHost.DownloadAndInstallAsync(pct => { if (pct == lastPct) return; lastPct = pct; try { this.BeginInvoke((MethodInvoker)delegate { lblUmi状态.Text = pct >= 100 ? "下载完成,正在解压安装…" : "正在下载… " + pct + "%"; }); } catch { } }).ContinueWith(t => { try { this.BeginInvoke((MethodInvoker)delegate { btnUmi下载.Enabled = true; btnUmi检测.Enabled = true; lblUmi状态.ForeColor = System.Drawing.SystemColors.GrayText; if (t.IsFaulted) { Exception root = t.Exception; while (root is AggregateException && root.InnerException != null) root = root.InnerException; lblUmi状态.Text = "下载/安装失败: " + root.Message; MessageBox.Show(this, "下载/安装失败:\n" + root.Message, "下载 OCR 本体", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { RefreshUmiStatus(); MessageBox.Show(this, "OCR 本体安装完成!\n" + UmiOcrHost.DetectText() + "\n\n选 Umi-OCR 引擎保存后即可使用(识别时自动启动)。", "下载 OCR 本体", MessageBoxButtons.OK, MessageBoxIcon.Information); } }); } catch { } }); } private void cboEngine_SelectedIndexChanged(object sender, EventArgs e) { UpdateEnginePanels(); } /// 帮助:全部引擎的 Key 获取方式与本地 OCR 设置流程。 private void btn帮助_Click(object sender, EventArgs e) { string help = "════════ OCR 识别引擎使用帮助 ════════\r\n" + "\r\n" + "【1. 百度 OCR 高精度(含位置)】 默认引擎,已内置 Key 可直接用\r\n" + " · 获取自己的 Key(更稳,免费额度足够日常):\r\n" + " ① 打开 console.baidu.com 登录百度账号\r\n" + " ② 进入\"产品服务 / 文字识别\"→ 创建应用\r\n" + " ③ 勾选\"文字识别\"全部接口,创建完成\r\n" + " ④ 在应用详情里复制 API Key 和 Secret Key 填入本窗口\r\n" + "\r\n" + "【2. 智谱 GLM-OCR(版面解析/手写强)】\r\n" + " · 到 open.bigmodel.cn 注册并实名 → API Keys 页面新建密钥\r\n" + " · 把密钥填入\"智谱 API Key\"\r\n" + " · 计费约 0.2 元/百万 tokens,适合手写体/复杂版面\r\n" + "\r\n" + "【3. 百度 PaddleOCR-VL(千帆版面解析)】\r\n" + " · 到 console.bce.baidu.com → 千帆 ModelBuilder → 应用管理\r\n" + " · 创建应用后复制 API Key 填入\"千帆 API Key\"\r\n" + " · 需在千帆控制台开通 PaddleOCR-VL 模型服务\r\n" + "\r\n" + "【4. UApiPro 通用OCR(免费积分/带位置)】\r\n" + " · 到 uapis.cn 注册账号 → 控制台 → API Keys → 新建\r\n" + " · 把 Key 填入\"UApiPro Key\"\r\n" + " · 注册送免费积分(约 4 积分/次识别),小量使用零成本\r\n" + "\r\n" + "【5. Umi-OCR 本地引擎(离线免费,无限次)】\r\n" + " · 本地引擎无需任何 Key,识别全在本机完成,数据不出电脑\r\n" + " · 设置流程:\r\n" + " ① 选本引擎后点\"下载 OCR 本体\"(约 179MB,自动下载安装)\r\n" + " ② 点\"检测 OCR 本体\"确认状态为\"运行中\"或\"已安装\"\r\n" + " ③ 点\"保存\"完成,之后识别时自动启动、关窗自动关闭\r\n" + " · 服务地址保持默认 http://127.0.0.1:1224 即可\r\n" + " (只有你在 Umi-OCR 软件里改过 HTTP 端口才需要改这里)\r\n" + "\r\n" + "════════════════════════════════\r\n" + "提示: Key 全部以密码方式显示,点\"保存\"后立即生效;\r\n" + "所有 Key 统一保存在程序目录 baidu_ocr.json。"; MessageBox.Show(this, help, "OCR 使用帮助", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void btn确定_Click(object sender, EventArgs e) { try { string cfgPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "baidu_ocr.json"); string engineValue = cboEngine.SelectedIndex == 1 ? "glm" : cboEngine.SelectedIndex == 2 ? "qianfan" : cboEngine.SelectedIndex == 3 ? "uapis" : cboEngine.SelectedIndex == 4 ? "umi" : "baidu"; var jsv = new JavaScriptSerializer(); File.WriteAllText(cfgPath, jsv.Serialize(new Dictionary { { "engine", engineValue }, { "api_key", txtApiKey.Text.Trim() }, { "secret_key", txtSecretKey.Text.Trim() }, { "glm_api_key", txtGlmKey.Text.Trim() }, { "qianfan_api_key", txtQianfanKey.Text.Trim() }, { "uapis_api_key", txtUapisKey.Text.Trim() }, { "umi_url", string.IsNullOrWhiteSpace(txtUmiUrl.Text.Trim()) ? "http://127.0.0.1:1224" : txtUmiUrl.Text.Trim() } })); // 热更新引擎/Key + 作废百度 token 缓存(下次识别重新换取) if (_ocr != null) { _ocr.LoadConfig(); try { File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "baidu_token.json")); } catch { } } // 选了 Umi-OCR 但还没装本体:提示引导下载(不阻断保存) if (engineValue == "umi" && !UmiOcrHost.IsInstalled) { MessageBox.Show(this, "Umi-OCR 本体尚未安装。\n请点\"下载 OCR 本体\"完成安装后即可使用。", "OCR 设置", MessageBoxButtons.OK, MessageBoxIcon.Information); } } catch (Exception ex) { MessageBox.Show(this, "保存失败: " + ex.Message, "OCR 设置", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } }