人类程序员还有用,记一次 GPT 把 Figma 两个接口搞反的事

项目起因

上周Deepseek Harness刚发布时,用来测试将一个旧项目的工具发布到github的任务,然后突然想起当时开发这个工具时产生的一些问题还是挺值得记录的。

先简单讲一下项目背景,是需要将 figma 的设计稿直接在web浏览器上重现,将进行二次互动开发。其中核心工具就是 figma 的数据导出功能。今天主要是想讲讲当时这个工具开发过程中遇到的问题,以及实现方案的决策过程。

先说明一下,我本人主要的是服务端开发,对前端web并不是十分熟悉(勉强能读懂,修改),对于复杂的实现还是交给AI进行辅助开发。先找GPT进行数据导出方案的讨论,告诉它我要实现的功能,然后让它出一个可行的实行方案。

最初GPT的方案是使用 figma 内的第三方插件,因为官方手动导出的数据不是json格式,难以直接用于解析和生成web内容。而且我用的是figma只是免费的个人用户,在导出功能上也会受限。

但是按GPT的方案去找第三方插件,却发现要么付费,要么导出的json并非原始的官方数据,是经过修改后的,第一感觉就是不靠谱,怕之后生成的web内容与设计稿相差很远。插件的方案看来是行不通了,于是让GPT去找下使用官方API的方式来导出数据。 GPT一开始提供接口与实现方案的大致如下:

  1. /v1/files/:key/nodes 接口拿到节点数据
  2. /v1/images/:key 接口导出图片
  3. 根据拿到的节点数据中的 imageRef 与导出的图片进行绑定,最终再节点数据进行内容展现

将GPT提供的方案扔给Trae去执行,是的,因为当时Trae还是免费,没办法,能省就省狗头。题外话,其实Trae的性价比还是不错的,只要需求提示词到位,一般的小功能实现都没什么问题。不过就是要选比较好的模型,我自己测试下来,免费的,能写代码就推荐DS 和 QWen,后面的Kimi K3 出来没用过,其他的就算了。

回正题,代码写好了,脚本按要求跑起来,显示:

csharp 复制代码
[Rate Limited] Waiting 392245s.

问一下AI,好家伙,原来是直接限流 4.5 天了~ 因为 figma 免费用户是每4.5天左右恢复一次接口使用机会,一个月最多就6次。

开始以为是 nodes 没有按要求拼接,但实际节点数据是成功导出了。而另一边后台也提示图片只处理到49的位置,所以估计是图片限流了。然后问关于 GPT 图片导出接口的相关限流政策,以及解决方案。这时GPT还没发现问题,各种让我排查是否拼接,还是节点数据没写好,甚至让我去手动导出图片。

当时其中的推断记录:

当时在对 /v1/images/:key 排查时,检查过可用的其他参数,发现一个 scale 参数很奇怪,明明只是导出下载,为什么会有这个类似缩放大小的参数呢?然后隔了几天,修改了拼接参数,这次只填一个节点,只做图片接口的测试,结果图片成功下载,但是发现图片并非原图,而是设计稿中某个节点渲染后的效果图。

看到图片的那一下,蛋都快震碎了。再上 figma 官网看下了接口,发现有一个与 /v1/images/:key 接口相似的另一个接口:/v1/files/:key/images ,是的无错,只是两单词位置变了。但实际作用却完全不一样:

  • /v1/images/:key ------ 实际是 节点渲染 接口。你给它 nodeId,它在云端把整个节点的文稿渲染成 PNG/SVG,然后给你一张渲染图的下载链接。
  • /v1/files/:key/images ------ 这才是 原始图片资源 接口。你给它文件 key,它返回这个 key 里所有的原始图片下载地址。

所以GPT把这两个接口理解成了同一个意思------"下载图片"。它给我的接口是节点渲染接口来导出图片,而实际我需要的是原始图片的导出,实际是资源下载链接。估计是渲染会使用更多限流策略,可能一个节点就当调一次api调用,既然拼接也没有用。我不确定GPT是否真的知道两个接口的存在,还只是不理解两个接口的具体用法,又或者未理解我的需求。

再进一步求证:

最后测试新的接口,成功获得文件稿对应的所有资源下载地址。数据大概是这样的:

jsonc 复制代码
// 文件:public/figma-assets/image-url-mapping.json
{
  "error": false,
  "status": 200,
  "meta": {
    "images": {
      "c6e0ad893532649b1357a9a5a4fd9e7742661490": "https://s3-alpha-sig.figma.com/img/c6e0/ad89/3532649b1357a9a5a4fd9e7742661490?Expires=1788134400&Key-Pair-Id=<REDACTED>&Signature=<REDACTED>",
      "b27ec86a87c1d4e1761779f2eba3027620a8c039": "https://s3-alpha-sig.figma.com/img/b27e/c86a/87c1d4e1761779f2eba3027620a8c039?Expires=1788134400&Key-Pair-Id=<REDACTED>&Signature=<REDACTED>",
      "494975f1edad82b4dfbfed963cfe51e49f842f2f": "https://s3-alpha-sig.figma.com/img/4949/75f1/edad82b4dfbfed963cfe51e49f842f2f?Expires=1788134400&Key-Pair-Id=<REDACTED>&Signature=<REDACTED>"
      // ...更多映射条目...
    }
  }
}

到这里,最主要的接口已经调通,再根据之前的设想,通过对获得的两份数据(一份节点数据,一份资源映射数据)进行本地处理,重新按节点生成可用于直接渲染使用的数据文件。通过接口 /v1/files/:key/nodes 获得的节点数据大概是这样的:

jsonc 复制代码
// 文件:public/figma-assets/main-page/figma-main-page.json
{
  "frames": [
    {
      "name": "main-page",
      "nodeId": "113:30",
      "data": {
        "id": "113:30",
        "name": "main-page",
        "type": "FRAME",
        "scrollBehavior": "SCROLLS",
        "children": [
          {
            "id": "113:46",
            "name": "Rectangle 3",
            "type": "RECTANGLE",
            "fills": [
              {
                "blendMode": "NORMAL",
                "type": "SOLID",
                "color": { "r": 0.196, "g": 0.290, "b": 0.329, "a": 1 }
              }
            ],
            "absoluteBoundingBox": { "x": 8825, "y": -5004, "width": 1920, "height": 1269 }
          }
        ]
      }
    }
  ]
}

而通过第三步脚本,将2份接口数据处理后,则会拆分为每个节点一个数据文件,生成的数据大概是:

jsonc 复制代码
// 文件:public/figma-assets/main-page/pixi-main-page.json
{
  "name": "main-page",
  "nodeId": "113:30",
  "imageUrl": null,
  "absoluteBoundingBox": { "x": 8825, "y": -5004, "width": 1920, "height": 1269 },
  "images": [
    {
      "nodeId": "113:45",
      "nodeName": "Vector (override)",
      "imageRef": "b27ec86a87c1d4e1761779f2eba3027620a8c039",
      "url": "https://s3-alpha-sig.figma.com/img/b27e/c86a/87c1d4e1761779f2eba3027620a8c039?Expires=1788134400&Key-Pair-Id=<REDACTED>&Signature=<REDACTED>",
      "absoluteBoundingBox": { "x": 9000, "y": -4846, "width": 1496, "height": 952 },
      "source": "override"
    }
    // ...更多图片条目...
  ]
}

注意:这时的地址还是远程,这个需要等资源真正下载完成后,再修改为本地的相对路径。

最终通过第四步脚本下载所有资源,根据 imgaeRef 替换本地相对路径后的数据文件:

jsonc 复制代码
// 步骤4 下载完成后的 pixi-main-page.json 中的 images 条目
{
  "nodeId": "113:45",
  "nodeName": "Vector",
  "imageRef": "c6e0ad893532649b1357a9a5a4fd9e7742661490",
  "url": "/figma-assets/main-page/c6e0ad893532649b1357a9a5a4fd9e7742661490.png",  // ← 已改为本地路径
  "absoluteBoundingBox": { "x": 9000, "y": -4846, "width": 1496, "height": 952 },
  "source": "fills"
}

到此整个 figma 数据导出的流程就完成了。希望对使用或项目源码有进一步了解的,可以直接移步去仓库:figma-export-tool

现在回头看

本次之所以想将这个开发过程写下来,其中很大的原因是最近看了很多关于 AI 是否能代替人类程序员的问题。在这次的项目中,从GPT出方案,到Trae的实现,整个过程基本没什么大问题。但是在关键的一些架构决策,以及语义的理解,还是需要人类界入。就正如上面提及的接口问题,如果不是人工去发现解决,可能AI就会一到在绕弯路,最终走出复杂的,甚至是不可行的方案。

由此可见,至少目前阶段,人类程序员还是有必要存在的价值,但是所承担的工作量也确实在变少。至于未来的某一天,可能真的人类不再需要写代码,AI可以直接生成机器码,提交终端自动执行了,到时就坦然接受,享受生活吧。

相关推荐
云存储小精灵2 小时前
DeepSeek Harness COS 插件上线:让 Agent 管理文件更简单
人工智能·产品
乐橙开放平台2 小时前
监控开放平台是什么?从设备接入到视频能力开放一次讲清
网络·人工智能·音视频
码士集团小青2 小时前
编辑 OpenCode × DeepSeek 配置优化实战:一次「费用 和 Token 效率优先」的深度重构
人工智能·ai
fthux2 小时前
装修怕增项、合同看不懂?我做了 RenoPit,帮普通业主提前发现装修坑
人工智能·ai·开源·github·open source·renopit
a187927218312 小时前
从一条直线到大模型输出一个token(一):从一条直线到高维空间
人工智能
Vuji2 小时前
Pi 插件解剖|summarize.ts:199 行,给 Agent 的对话做一份 Markdown 总结
前端·人工智能·agent
星核0penstarry2 小时前
边缘AI选型:记录NVIDIA Holoscan测试
人工智能·硬件架构·压力测试·ai编程
陆枫Larry2 小时前
Sandbox(沙箱)到底是什么?
人工智能
径硕科技JINGdigital2 小时前
AI 训练时 GPU 利用率低,哪些云上高性能存储方案更适合优化训练成本?AWS 按 I/O 瓶颈分层选型
人工智能·云计算·aws