惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Announcements
Recent Announcements
IT之家
IT之家
Google DeepMind News
Google DeepMind News
罗磊的独立博客
爱范儿
爱范儿
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
U
Unit 42
MongoDB | Blog
MongoDB | Blog
S
SegmentFault 最新的问题
B
Blog
博客园 - 叶小钗
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
C
Check Point Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派
使用 Airtable 构建个人单词本 - 少数派
2021-05-02 · via 少数派

Matrix 首页推荐

Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。

文章代表作者个人观点,少数派仅对标题和排版略作修改。


词到用时方恨少,这句话说的就是第一次写论文的时候的我。口语表达需要用到的词,真的比书面表达的词少很多。但是,在平时的论文阅读的过程中,总能发现一些「陌生词」,而这些陌生词往往用得非常的巧妙,在英语语境中,是更能 precisely(编注:恰好) 地表达语义。我就是一直在思考这个问题,如何才能收藏起来以便以后为我所用呢?

本文就是提出这么一个免费的解决方案,来帮助我们摘抄陌生词,形成自己的词典,并能方便地查看和温故。当然,我们的目标还是希望能够多平台覆盖和同步的,不然实用意义就变小了。

Airtable as a Database

首先要解决的第一个问题,就是如何把想要的单词摘抄并存储起来。这里,很多的单词翻译软件都有自己的单词本功能,但是同步功能基本上都是付费的功能。对我这种低频使用者而言,不太实惠。

我考虑了使用在线表格作为后端的存储,Airtable 就是这个领域的佼佼者了,并且它提供的基于 HTTP 的 API 接口方便和其他的软件交互完成存储和访问,就非常地符合我们的需求。

你需要做的准备有以下的几点:

  • 准备一个 Airtable 的账户,新建一个 Table,并将主 sheet 命名为 Main
  • 根据以下的 scheme 建立表头
# Name - Field Type
Query - Long text
Translation - Single line text
isWord - Check box
Explains - Long text
US-Phonetic - Single line text
UK-Phonetic - Single line text
Count - Number - Integer
  • 最后,你需要获取 Airtable 相关的 API Token。

访问 https://airtable.com/api,点击对应的 Table,选择左侧的 AUTHENTICATION,点击右上角的 show API key,你就能找到对应的 <your table id><your app token>

  • (可选) 在 Airtable 里增加 Gallery View,制作你自己的单词卡片,点击 Share View 可获取访问链接

Youdao as a Translator

当选择了「陌生词」后,我们需要做的是存储它原词的同时,存储其对应的中文翻译。当然,这个版本也可以离线完成,通过 Airtable Automation 或者 Serverless Function 可以做到。但是前者需要付费订阅 Pro,后者使得平台更复杂化了。后来实际考虑,其实这个也放在本地完成就是可以的,从某种程度上来说也更简单一些。

首先,要做的是获取有道智云 AI 开放平台的接口密钥。你需要访问:https://ai.youdao.com/doc.s#guide,根据上述的指南注册开发者账号并获取密钥,上述官方有详细的图解步骤,我在这里就不重复了。关于价格,有道云文本翻译服务是 48 元/百万字符,每月调用量清零。换句话说,每月 100 万字符以下翻译免费,对于我们翻译几个单词来说,实在是绰绰有余。更详细的价格可以参考 官方定价文档

最终你获得的有两个关键的字符串:<your app key> and <your app secret>, 这里的 app 指的是有道智云 AI 开放平台上面的一个实例。

JSBox as a Client

好了,万事俱备,只欠东风。接下来,就是通过 HTTP 接口,把「陌生词」存储到 Airtable 中。

这里,由于选择了本地调用有道云的接口,因此需要比较复杂的 JS 代码才能构建出 API 访问的参数,否则其实可以使用更轻量级的捷径 App 来完成这样的动作的。所以,我终于不得不选择 JSBox 作为 Client 调用接口。对于读者来说的好消息是,JSBox 免费下载且 1.x 版本的功能免费且我们只需要用到 1.x 版本的功能。对于我来说,我开发这个 workflow 专门买了JSBox,—_—

关于调用的代码,我已经全部开源并放到这个 Gist 里面了,文末我也放置了一份相同的作为附录,以便不方便访问 Gist 的读者们访问。

在 JSBox 里面,选择 New Project,名称可以自定义,Type 选择 JSBox script 即可,把开源的代码粘贴到里面,并替换其中的对应的密钥即可。

<your app key> -> 你的有道云应用ID
<your app secret> -> 你的有道云应用密钥
<your table id> -> 你的Airtable的表格ID
<your app token> -> 你的Airtable的API Token

为了在调用菜单里简化一级跳转逻辑,我们还需要借助捷径 APP 调用 JSBox

Workflow Demo

由于我阅读论文的设备是 iPad,因此这里用 iPad 做个演示。在你喜欢的论文阅读软件中选中相应的单词/短语,通过系统分享菜单选择对应的捷径。

对应的 Gallery View 的单词卡效果是这样子的,而且对响应式网站有适配,写论文的时候它给了我很大的帮助。

理论上,这个 worflow 也支持句子摘抄和翻译,新增一个 Gallery View 和 Filtering 就可以,只不过我没有这个需求而已。

好了,以上就是全部的内容。感谢阅读。

附录

lexicon.js

const CryptoJS = require("crypto-js")

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

var entrance = null
var query = null
if ($context.text) {
  query = $context.text
  entrance = 'jsbox'
} else if (Object.keys($context.query).length) {
  query = $context.query.word
  entrance = 'shortcut'
} else {
  console.log('Please execute via share sheet')
  $context.close()
  $app.close()
}
console.log('query', query)

const appkey = '<your app key>'
const salt = uuidv4()
console.log('salt:', salt)
const curtime = (Math.round(new Date().getTime() / 1000)).toString()
console.log('curtime:', curtime)
const appsecret = '<your app secret>'
var input = query
if (query && query.length > 20) {
  input = query.slice(0, 10) + query.length + query.slice(query.length - 10, query.length)
}
console.log('input:', input)
var concat = appkey + input + salt + curtime + appsecret
console.log('concat:', concat)
const sign = CryptoJS.SHA256(concat).toString()
console.log('sign:', sign)

var formData = {
  q: query,
  from: 'en',
  to: 'zh-CHS',
  appKey: appkey,
  salt: salt,
  sign: sign,
  signType: 'v3',
  curtime: curtime,
  strict: 'true'
}

if (query) {
  $http.post({
    url: "https://openapi.youdao.com/api",
    form: formData,
    handler: function (resp) {
      var ydreq = resp.data
      console.log(ydreq)
      var field = {
        Query: ydreq['query'],
        Translation: ydreq['translation'].join('\n'),
        isWord: ydreq['isWord'],
        Count: 1
      }
      if (ydreq['isWord']) {
        field['Explains'] = ydreq['basic']['explains'].join('\n')
        field['US-Phonetic'] = ydreq['basic']['us-phonetic']
        field['UK-Phonetic'] = ydreq['basic']['uk-phonetic']
      }
      $http.post({
        url: "https://api.airtable.com/v0/<your table id>/Main",
        header: {
          'Authorization': 'Bearer <your app token>',
          'Content-Type': 'application/json'
        },
        body: {
          records: [{
            fields: field
          }]
        },
        handler: function(resp) {
          var atreq = resp.data
          console.log(atreq)
          var display = 'Created: ' + atreq.records[0].id
          if (entrance === 'shortcut') {
            $intents.finish(display)
          } else if (entrance === 'jsbox') {
            $ui.preview({
              title: "AirTable API Response",
              text: display
            });
          }
        }
      });
    }
  })
}

关联阅读:

> 下载 少数派 2.0 客户端、关注少数派公众号,解锁全新阅读体验📰

> 实用、好用的 正版软件,少数派为你呈现🚀