ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Github Copilot 实战:从零开始用 AI 写一个 OCR 工具(3)——WPF + C# 接入 TaoToken 统一 Key 的配置骨架

Github Copilot 实战:从零开始用 AI 写一个 OCR 工具(3)——WPF + C# 接入 TaoToken 统一 Key 的配置骨架 1. 从截图到回填WPF OCR 工具为什么卡在 Key 管理上用 Github Copilot 辅助写一个 WPF C# 的 OCR 工具前两篇我们已经把截图窗口、PaddleOCR 识别内核、结果高亮都跑通了。到了第三篇真正让人头疼的往往不是识别算法而是「截图→识别→回填」这条链路里AI 能力调用的入口太散截图后想调一次视觉模型做版面理解识别完想调一次大模型做文本纠错回填时又想接一个 Agent 做结构化抽取——每个能力一个 Key、一个 BaseUrl、一套鉴权头配置文件越写越长换台机器就得重新配一遍。这篇就聚焦这个工程化问题在 WPF/C# 桌面端 OCR 工具里用 TaoToken 统一 Key 把多 AI 能力的调用通道收敛成一份配置骨架。适合已经能跑通 PaddleOCR 基础识别、准备把「截图→识别→回填」做成最小闭环的开发者。我会给出可复制的settings.json/config.toml骨架、CC Switch 与 Cline 的接入步骤以及一次完整的 OCR 调用链验证动作。TaoToken 在这里扮演的是统一入口官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 一个 Key 覆盖对话、编码、Agent 多类模型桌面端只需要维护一份配置。2. TaoToken 前置把分散的 Key 收敛成一份配置2.1 为什么桌面端更需要统一 KeyWPF 应用和 Web 服务不一样它跑在用户本机配置散落在%AppData%、项目目录、环境变量三处。如果每个 AI 能力都单独配 Key用户换机、重装、分享配置时就会漏。TaoToken 的做法是提供一个兼容 OpenAI 协议的统一端点你只需要在配置里写一次base_url和api_key剩下的模型名按需切换。对 OCR 工具来说典型的三类调用是调用场景用途建议模型类型版面理解截图后判断区域类型视觉/多模态文本纠错PaddleOCR 结果后处理通用对话结构化回填抽取字段写入表单编码/Agent三类调用共用一份 Key配置骨架只需要维护一个providers节点。2.2 获取 Key 与端点先到控制台创建 API Key入口在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。创建后复制一次后面配置里用。API 基址统一写https://taotoken.net/api注意这个地址不带任何查询参数。注意Key 只显示一次建议先存到本机密码管理器再写入配置文件。桌面端不要把 Key 硬编码进源码提交到仓库。3. 可复制配置settings.json 与 config.toml 骨架3.1 settings.json给 Cline / CC Switch 用Cline 和 CC Switch 都读 JSON 配置。下面这份骨架可以直接复制把api_key换成你自己的{ providers: { taotoken: { base_url: https://taotoken.net/api, api_key: sk-你的Key, models: { chat: gpt-4o-mini, coding: claude-3-5-sonnet, vision: gpt-4o } } }, ocr: { engine: PaddleOCR, model_dir: %AppData%/MiOcr/models, timeout_ms: 1500 } }models节点是给不同能力做映射用的OCR 工具里视觉调用走vision纠错走chatAgent 回填走coding。这样切换模型只改一处。3.2 config.toml给 C# 侧读取C# 读 TOML 可以用Tomlyn包。配置骨架如下[taotoken] base_url https://taotoken.net/api api_key sk-你的Key timeout_seconds 30 [taotoken.models] chat gpt-4o-mini coding claude-3-5-sonnet vision gpt-4o [ocr] engine PaddleOCR model_dir models timeout_ms 1500在 WPF 启动时加载using Tomlyn; using Tomlyn.Model; public sealed class AppConfig { public string BaseUrl { get; init; } ; public string ApiKey { get; init; } ; public string ChatModel { get; init; } ; public string CodingModel { get; init; } ; public string VisionModel { get; init; } ; public static AppConfig Load(string path) { var text File.ReadAllText(path); var model Toml.ToModel(text); var tt (TomlTable)model[taotoken]; var models (TomlTable)tt[models]; return new AppConfig { BaseUrl tt[base_url].ToString()!, ApiKey tt[api_key].ToString()!, ChatModel models[chat].ToString()!, CodingModel models[coding].ToString()!, VisionModel models[vision].ToString()! }; } }3.3 CC Switch 接入步骤CC Switch 用来在多个配置间切换接入 TaoToken 的步骤第一步打开 CC Switch新增一个 Provider名称填taotoken。第二步Base URL 填https://taotoken.net/apiAPI Key 粘贴控制台创建的那串。第三步在模型映射里把chat、coding、vision分别指向你要用的模型名。第四步保存后设为默认回到 WPF 项目里读取这份配置即可。这样 Copilot 辅助编码时Cline 侧和桌面端侧用的是同一份 Key。3.4 Cline 接入步骤Cline 是 VS Code 里的编码 Agent接入 TaoToken 后可以让它直接读你的 OCR 项目上下文第一步在 Cline 设置里选 API Provider 为 OpenAI Compatible。第二步Base URL 填https://taotoken.net/apiAPI Key 填同一串。第三步Model ID 填claude-3-5-sonnet或你映射的编码模型。第四步保存后在项目根目录放一份settings.jsonCline 会优先读项目级配置。这样 Copilot 补全和 Cline Agent 走的是同一条通道。4. 验证请求跑通一次 OCR 调用链4.1 最小验证先确认 Key 可用在写业务代码前先用一条 curl 确认通道通curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 回复 OK}] }返回里能看到choices字段就说明 Key 和端点都对。这一步别跳过后面 OCR 链路出问题时能快速定位是通道问题还是业务问题。4.2 C# 侧封装统一客户端public sealed class AiClient { private readonly HttpClient _http; private readonly AppConfig _cfg; public AiClient(AppConfig cfg) { _cfg cfg; _http new HttpClient { BaseAddress new Uri(cfg.BaseUrl), Timeout TimeSpan.FromSeconds(30) }; _http.DefaultRequestHeaders.Authorization new AuthenticationHeaderValue(Bearer, cfg.ApiKey); } public async Taskstring ChatAsync(string model, string prompt) { var payload new { model, messages new[] { new { role user, content prompt } } }; var resp await _http.PostAsJsonAsync(/v1/chat/completions, payload); resp.EnsureSuccessStatusCode(); var json await resp.Content.ReadFromJsonAsyncJsonElement(); return json.GetProperty(choices)[0] .GetProperty(message) .GetProperty(content) .GetString() ?? ; } }4.3 串起截图→识别→回填在RunOcrAndDraw里识别完成后加一步纠错回填private async Task RunOcrAndDraw(byte[] imageBytes) { ProcessingText.Visibility Visibility.Visible; ProcessingText.Text 正在识别...; var ocr new PaddleOCRService(); var results await ocr.StartOCR(imageBytes, msg { Dispatcher.Invoke(() { ProcessingText.Text msg; ProcessingText.Visibility Visibility.Visible; }); }); ProcessingText.Visibility Visibility.Collapsed; if (results.strings null || results.strings.Count 0) { OcrTextBox.Text 未识别到文本; return; } var raw string.Join(Environment.NewLine, results.strings); // 用统一 Key 调一次纠错 var ai new AiClient(AppConfig.Load(config.toml)); var fixedText await ai.ChatAsync( ai.ChatModel, $请修正以下 OCR 结果中的错别字只返回修正后的文本\n{raw}); OcrTextBox.Text fixedText; _lastOcrResult results.result; var drawed DrawOcrResultsOnImage(_currentImage, results.result); MainImage.Source drawed; }跑一次截图 → PaddleOCR 出原始文本 → TaoToken 通道纠错 → 回填到OcrTextBox。整条链路只用了config.toml里的一份 Key。4.4 验证成功的判断标准识别结果里出现修正后的文本、OcrTextBox内容与截图区域一致、MainImage上高亮框位置正确这三条同时满足就算闭环跑通。如果纠错那步返回空先看 curl 是否通再看模型名是否在映射里。5. 本篇常见错排查5.1 401 或 403Key 没生效最常见的是Authorization头拼错或者 Key 前后带了空格。检查config.toml里api_key是否被引号包住、有没有换行符。另一个坑是把 Base URL 写成了带路径的形式正确写法是https://taotoken.net/api请求时再拼/v1/chat/completions。5.2 模型名报 not foundmodels映射里的名字必须和通道支持的模型名一致。如果你在settings.json里写了gpt-4o但通道侧叫别的名字就会 404。排查方法先用 curl 带同一个模型名请求一次确认通道认识这个名字再写进配置。5.3 超时提示不触发StartOCR里的timeoutMs默认 1500 毫秒如果模型已经下载过DownloadAsync会秒过超时任务被cts.Cancel()取消UI 不会弹提示。这是预期行为。如果首次下载很慢但提示没出现检查onStatusChanged是否在 UI 线程调用——WPF 里必须用Dispatcher.Invoke包一层否则回调在后台线程执行UI 不更新。5.4 配置文件路径找不到WPF 发布后工作目录可能不是项目目录。建议用AppDomain.CurrentDomain.BaseDirectory拼配置路径或者把config.toml设为「复制到输出目录」。%AppData%这种环境变量在 TOML 里不会自动展开需要在 C# 侧用Environment.ExpandEnvironmentVariables处理。5.5 截图 DPI 缩放导致坐标偏移高 DPI 屏上截图区域和实际像素对不上是因为 WPF 的逻辑坐标和屏幕物理像素有缩放比。NativeMethods.GetDpiScale拿到的M11就是缩放系数截图时乘上去即可。如果回填时高亮框偏移检查DrawOcrResultsOnImage里是否也做了同样的缩放换算。6. 下一步把统一 Key 用到长期编码与 Agent到这里「截图→识别→回填」的最小闭环已经跑通配置骨架也收敛成了一份。接下来如果你想让 Cline 或 Copilot 长期在这个项目上做编码和 Agent 任务建议把编码类调用单独走 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 这样对话类调用和编码类调用的额度、模型可以分开管理桌面端配置里只需要多一个coding映射。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各语言 SDK 的调用示例。想先在网页上验证模型对话是否正常可以用 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 直接试。Key 管理和创建还是回到 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。我自己的习惯是桌面端只保留一份config.toml所有 AI 调用都通过AiClient走统一通道新增能力时只改models映射不动业务代码。这样 Copilot 补全出来的调用代码风格也统一后面维护省心。
返回列表