告别 API 付费!用 Bob + Ollama 在 Mac 上白嫖谷歌最强翻译模型 TranslateGemma
在 macOS 上使用 Bob 划词翻译时,最头疼的往往是各种翻译 API 的额度与网络问题:DeepL 免费额度少且易被风控,OpenAI API 容易断连且需要持续付费,传统的机器翻译虽然免费但翻译效果差。 今天分享一个完全免费、零延迟、隐私性极高,且翻译质量直逼专业水平的终极方案:Bob + Ollama + TranslateGemma。通过在本地运行 Google 专门为翻译任务优化的 TranslateGemma 模型,实现真正的“翻译自由”。 1. 核心优势:为什么是 TranslateGemma? 在介绍具体步骤前,先简单说明一下为什么这个组合是目前 macOS 翻译方案的“天花板”: Google 官方翻译微调:TranslateGemma 是 Google 专门针对翻译任务微调的 Gemma 模型,支持 55 种语言互译。相比通用的 LLM,它在多语种翻译的准确性和信达雅程度上表现更出色。 完全免费 & 离线运行:模型运行在本地,不依赖任何第三方 API,不消耗流量,且完全不用担心隐私泄露(特别适合翻译公司敏感文档)。 极速响应:Ollama 完美适配 Apple Silicon (M1/M2/M3/M4) 的 Metal 架构,推理速度极快,体验上快于调用 Gemini 或 ChatGPT API。 生态成熟:配合 Bob 这款 macOS 最强翻译聚合工具,可以无缝融入日常工作流(划词、截图、输入框翻译)。 2. 准备工作 在开始之前,请确保你已经安装了以下软件: Ollama: https://ollama.com/ (用于运行本地大模型) Bob: https://bobtranslate.com/ (macOS 上的老牌翻译软件) 硬件建议: 建议使用 M1 芯片及以上的 Mac 设备。8GB 内存推荐使用 4b 量化版本,16GB 及以上可以尝试更高精度的模型。 3. 部署 TranslateGemma 模型 安装好 Ollama 后,我们需要拉取 Google 的翻译模型 TranslateGemma。 ...
唯一索引这玩意儿,真得好好掂量掂量
在大厂(就是那种用户多、数据量大、需求快速迭代的地方),如果不是对账那种一分钱不能错的业务,想着靠数据库的 UNIQUE INDEX(唯一索引)来拦重复数据,说实话,效果不一定好,伺候它的成本还很高。更好的办法是把去重的主要活儿放应用层,数据库那个唯一索引,能不用就先别用,或者想清楚了再用。 一、 为啥我开始琢磨唯一索引这事儿?因为坑踩了 数据库唯一索引,听着挺靠谱,对吧?保证数据不重复的最后一道防线。以前我也是这么想的,表里哪个字段不让重,随手就给它来个唯一索引。 直到被现实狠狠摩擦了。 很久之前,当我头发还很茂密的时候,给一个千万级的表加个组合唯一索引(比如 tenant_id 和 is_deleted 这俩字段不能重复)。听着简单吧?结果呢,整个变更从头到尾折腾了几天!这期间,主从延迟跟过山车似的,时不时还得担心线上服务会不会抖一下。事儿完了我在想,就为了数据库层面这个“唯一”,搭进去这么多工夫、担这么大风险,值吗? 还有个事儿也挺别扭。 业务上,我们都知道 [email protected] 和 [email protected] 其实是一个邮箱,你注册的时候,应用代码肯定也会把它们统一处理成小写再判断有没有重复。结果呢,数据库里的唯一索引(区分大小写)不认这个账。有时候因为一些历史数据或者旁路数据同步没做好规范化,数据库里就存了两种大小写格式的“同一个”邮箱。这时候,唯一索引它要么“眼瞎”发现不了这种业务上的重复,要么在你修数据的时候,因为它那死板的规矩,反而碍手碍脚。 更别提业务迭代了。 比如,以前光是“邮箱唯一”就行,现在要改成“租户 ID+邮箱唯一”。好家伙,应用代码得改吧?数据库的唯一索引也得跟着 DROP 旧的 CREATE 新的吧?这两拨操作怎么配合?谁先谁后?万一中间出岔子怎么办?在大表上搞这种操作,每次都跟拆炸弹似的,提心吊胆。 就这些事儿搞得我不得不琢磨:数据量大、并发高、需求又变得快,唯一索引这一套,是不是该重新掂量掂量了?它带来的麻烦,是不是已经比它的好处多了? 这篇文章,就是想跟大家伙儿聊聊我的反思。 二、 UNIQUE INDEX:我们为啥那么信它? 在吐槽之前,咱也得公平点,说说唯一索引为啥那么招人待见,它确实有几个看上去不错的点: 数据不跑偏的最后保险: 防止数据重复的最后一道关卡。 上手简单: 建表的时候或者后来加个 DDL,几行 SQL 就搞定了。 表结构一看就懂: Schema 里标着呢,这字段不能重。 顺便还能快点查: 反正也是个索引,按这个键查数据能快点。 这些好处,在小项目或者数据量不大、业务不复杂的时候,确实挺香。但一到大数据量+快速迭代“修罗场”,情况就变了。 三、 大厂滤镜下的UNIQUE INDEX:那些“好处”还好使吗? 接下来咱们挨个盘盘上面说的那些“好处”,看看在大厂这环境下,它们是不是还那么“美”。 “最后保险”?这保险靠谱吗?保的是啥险? 业务上的“重复”它认不全啊!就像前面说的邮箱大小写,还有手机号带不带+86,用户名清不清除特殊字符……这些业务上才认的“一样”,数据库那简单粗暴的“字节必须一样”的唯一索引根本管不过来。它防不住业务层面的“逻辑重复”。 应用层反正要干活。 既然这些复杂的“一样不一样”都得在应用代码里判断(总不能直接把数据库报错丢给用户吧?),那应用层才是真正保证“业务数据不重复”的主力军。数据库那个唯一索引,充其量是个标准可能还跟业务不一致的“辅警”。 分布式系统里它就是个“本地保镖”。在分布式场景下一旦分表,表内的唯一索引,管不了全局唯一性。全局唯一还得靠 ID 生成服务或者应用层的全局校验。这时候,数据库本地那点“保险”作用就更小了。 这个“最后保险”既可能保不到点子上,覆盖面也有限,全指望它优点悬。 “上手简单”?一次上线,一周折腾 新表新加个唯一索引,确实就一条 SQL。但更多的时候是给已经跑了好久、数据堆成山的旧表改规则。你想给千万行的表改个唯一索引(比如从一个字段唯一改成俩字段组合唯一),可能就是几分钟的锁表!在线 DDL 工具,也只是让你不用停服务,但整个过程照样漫长、耗资源、有风险。 敏捷?快不起来啊!在快速迭代+多区域同步+合规要求的场景下。数据库这儿一个唯一索引的变更就要卡你好几天,啥敏捷都白搭。 所以开始那一下“简单”,跟后来改起来的“要老命”比,简直是钓鱼。 “表结构一看就懂”?懂的可能跟实际要的不一样啊! 唯一索引在表结构里写着,是,算是一种“技术文档”。可是“文档”可能误导人,如果这个唯一索引定义的“唯一”跟业务上实际的、更复杂的唯一规则对不上(比如大小写问题),那这份“文档”不光没用,还可能误导后来的开发。 如果改这份“文档”(就是改唯一索引)就要经历九九八十一难,那我们为啥不把业务规则好好写在真正的设计文档、Wiki 或者代码注释里呢?那些地方改起来可方便多了。 “顺便还能快点查”?为了这点醋,才包的这顿饺子? 这是个很常见的误解,或者说是一个被过分强调的“附加值”。如果你只是想让某个字段或某几个字段的查询快一点,你完全可以给它们建一个普普通通的、非唯一的索引(Non-Unique Index)啊!非唯一索引照样能嗖嗖地提高查询速度,而且它还没有唯一性约束带来的那些写入开销、DDL 痛苦和业务逻辑的死板限制。 ...
羊了个羊科技通关攻略
最近羊了个羊比较火,但是难度非常高,打了几天几十盘都通不过,所以犯了职业病,想看看有没有科技手段,实践有效后整理出来方便大家科技通关。 原理 科技通关的原理比较简单,游戏每天都有两幅地图,第一个地图是练手的可以无脑通过,第二个是难度爆表的版本,所以只要能够把第二个地图改成第一个,就可以实现通关。 准备工作 实现科技通关需要一个 Web 调试代理 App,在 iOS 上可以用 HTTP Catcher(需要内购),Storm Sniffer(三天试用),Android 上也可以找类似的软件。以 HTTP Catcher 为例,安装好之后需要安装并启用 Root 证书,以实现 HTTPS 解密。 步骤 首先需要启动 HTTP Catcher,打开羊了个羊进入游戏开始挑战,然后返回 HTTP Catcher,筛选 JSON 类型的请求,找到包含 map_info_ex 的请求。 点进这个请求里的 Response,可以看到返回内容里有个 map_md5 的列表,里面有两个 md5 值,分别对应第一个地图和第二个地图,我们要做的就是把返回值里第二个地图的 md5 替换成第一个的。 接下来返回上一个界面,左滑选择更多,新建重写,在弹出的界面中新增规则。 按下图的选择 Response 和 Body,将第二张地图的 md5(可以提前复制好)填入 Find,将第二张地图的 md5 填入 Replace,然后一路保存。 接下来重新启动 HTTP Catcher,回到羊了个羊重新开始游戏,第二关就变成和第一关一样简单的地图了。
基于Clean Architecture的Go项目架构实践
经过这些年的发展,Go 语言已经成为一门被广泛使用在各个领域的编程语言。从 k8s、docker 等基础组件,到业务领域的微服务,都可以用 Go 构建。在构建这些 Go 项目时,采用哪种架构模式和代码布局,是一个仁者见仁智者见智的事情。有 Java Spring 经验的可能会采用 MVC 模式,有 Python Flask 经验的可能会采用 MTV 模式。加上 Go 语言领域并没有出现主流的企业级开发框架,很多项目甚至没有明确的架构模式。 Clean Architecture Clean Architecture 是 Uncle Bob 提出的适用于复杂业务系统的架构模式,其核心思想是将业务复杂度与技术复杂度解藕,相比于 MVC、MTV 等模式,Clean Architecture 除了进行分层,还通过约定依赖原则,明确了与外部依赖的交互方式,以及外部依赖与业务逻辑的边界。感兴趣的朋友可以直接阅读作者原文https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html。 由于 Clean Architecture 具有脱离语言和框架的灵活性,作者在提出时也没有规定实现细节,给 Clean Architecture 的落地带来了困难,接下来以一个例子来说明如何在 Go 项目中应用 Clean Architecture 的思想。 布局 作为一个 Go 项目,不管用哪种架构模式,建议都建立 app 和 scripts 这两个路径。app 存放启动 Go 项目的入口文件,通常是 main.go。而 scripts 可以放一些构建和部署时候用到的脚本。 clean_architecture_demo ├── README.md ├── app │ └── main.go ├── scripts │ ├── build.sh │ └── run.sh ├── go.mod ├── go.sum └── usecases 接下来是代码部分,分为 entities、usecases、adapters 三个部分。 ...
Python跨服务传递作用域的坑
背景 在一个古老的系统中,有这样一段代码: scope = dict(globals(), **locals()) exec( """ global_a = 123 def func_a(): print(global_a) """ , scope) exec("func_a()", scope) 第一段用户代码定义了函数,第二段用户代码执行函数(不要问为什么这么做,因为用户永远是正确的)。第一个代码段执行后,func_a 和 global_a 都会被加入作用域 scope,由于第二个代码段也使用同一个 scope,所以第二个代码段调用 func_a 是可以正确输出 123 的。 但是使用 exec 执行用户代码毕竟不优雅,也很危险,于是把 exec 函数封装在了一个 Python 沙箱环境中(简单理解就是另一个 Python 服务,将 code 和 scope 传给这个服务后,服务会在沙箱环境调用 exec(code,scope)执行代码),相当于每一次对 exec 调用都替换成了对沙箱服务的 RPC 请求。 于是代码变成了这个样子: scope = dict(globals(), **locals()) scope = call_sandbox( """ global_a = 123 def func_a(): print(global_a) """ , scope) call_sandbox("func_a()", scope) 作用域跨服务传递问题 由于多次 RPC 调用需要使用同一个作用域,所以沙箱服务返回了新的 scope,以保证下次调用时作用域不会丢失。但是执行代码会发现第二次 call_sandbox 调用时候,会返回错误: ...