CF_AI提问

AnkiWeb addon 8664763

Adds a card button that sends a configured prompt field to an AI API and inserts the response into a chosen field, with configurable model and context.
AI-generated summary; may contain mistakes.

card-creationaicard-templates

Open on AnkiWeb GitHub Find alternatives

AnkiWeb

Votes
0 (👍 0 · 👎 0)
Updated
2025-12-31
Anki versions
2.1.1~
License
Not found (this does not mean that the addon has no license)
Virus scan
No ClamAV match A match does not prove malware. No match does not prove that the code is safe.
Languages
Python, JSON
Description language
ja

Maintenance

stale

  • Last update or commit: 2025-12-31 (305 days before the snapshot).
  • Commits in the last year: 5.
  • Issues: 0 open, 0 closed.
  • Pull requests: 0 open, 0 merged.

Will it work on my Anki?

Version branches
Min AnkiMax AnkiUpdated
2.1.1+2025-12-31
History across monthly snapshots

Loading…

Similar addons

OmniPrompt-Anki

Generates AI-powered flashcard content such as definitions, translations, and explanations from multiple cloud or local providers, with reusable prompts, batch processing, and multi-field output.

card-creationainote-managementformattingshortcuts

7 votes 65% approval 👍 7 · 👎 0 ⭐ 9 Anki 2.1.66~ Updated 2026-04-23
AnkiExplain

Adds an Explain button and dockable sidebar that uses Gemini AI to generate flashcard explanations, mnemonics, related concepts, and follow-up chat, with streaming responses and customizable prompts.

aireview-flowshortcutsaccessibility

6 votes 61% approval 👍 6 · 👎 0 Anki 2.1.1~ Updated 2026-02-12
LLM Card Fill

Queries Anthropic or OpenAI APIs with custom prompts to fill Anki note fields, supporting batch updates, card creation, and per-note-type configurations.

card-creationainote-management

2 votes 9% approval 👍 1 · 👎 1 ⭐ 1 Anki 26.09~ Updated 2026-09-24
Ankify

Turns clipboard text into Anki flashcards using a chosen AI provider directly in the Add window, with review, regeneration, note-type mapping, and specialization options.

card-creationaishortcutscloze

1 votes 21% approval 👍 1 · 👎 0 ⭐ 0 Anki 2.1.1~ Updated 2026-10-27

Description

Anki 插件:CF worker AI提问

这是一个Anki插件,允许您在卡片复习时一键调用AI(通过Cloudflare Workers或其他API)并将结果自动填入指定字段(需要配合1020366288插件)。

调用方式

卡片模板中添加按钮
例 <div style='font-size: 40px'><button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d4b40; font-size: 14px;float: right">——</button>

功能特性

  • 一键调用:在卡片模板中添加一个按钮,即可快速向AI提问。
  • 高度可配置:支持自定义 API Key、模型、系统提示词、上下文对话等。
  • 智能上下文:支持配置多轮对话作为上下文,让AI的回答更符合你的期望。
  • 无缝体验:优化了与 Edit Field During Review 插件的兼容性,更新解析后无需刷新卡片。
  • 自动创建配置:首次使用时会自动生成配置文件,简化初始设置。

安装与配置

  1. 安装插件与依赖插件:

    • 通过 AnkiWeb 页面下载,或使用代码 [还没发] 安装。
    • 或通过 Github releases 页面下载,并解压至anki插件目录。
    • 通过 AnkiWeb 页面下载,或使用代码 [1020366288] 安装依赖插件Edit Field During Review。
  2. 获取 API Key:

    • 参考下方的 CF AI worker部署说明 部署一个自己的CF AI worker
    • 访问 qwen-free-api部署反代API。
    • PS1. 其他反代AI大概也行
    • PS2. 这些反代项目都被投毒了,需要自己删除有毒的代码构建
  3. 配置插件:

    • 在 Anki 主界面,点击菜单栏的 工具 > AI提问配置。
    • 将你获取的 Authorization 填入 Authorization ,如 Bearer abc123sm 。
    • 根据你的卡片模板,设置 提问字段 (例如:Expression) 和 回答字段 (例如:Edit)。
    • (可选)根据你的需求修改系统提示词和其他参数。
    • 点击 "保存"。
  4. 在卡片模板中添加按钮:

    • 这是必须的步骤!你需要手动在你的卡片模板中添加一个按钮来触发AI。
    • 打开 Anki 的 工具 > 管理笔记类型,选择你使用的笔记类型,然后点击 卡片...。
    • 在“正面模板”或“背面模板”的 HTML 代码中,找到一个合适的位置,粘贴以下代码:
    <button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40; font-size: 14px;">AI提问</button>
    

CF AI worker部署说明

  1. 有一个CF账号,并且有域名,绑定信用卡等前置操作
  2. 登录 Cloudflare Dashboard
  3. 创建新的Worker,如 anki-ai-proxy
  4. 将 CF worker示例.js的内容粘贴进去
  5. 修改第9行的Bearer Token(改成你自己的)
  6. 保存并部署
  7. 测试可用性(可选) 网址改成你的,token改成你的
curl -X POST "https://anki-ai-proxy.abc123sm.workers.dev" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer abc123sm" \
  -d '{
    "messages": [{"role": "user", "content": "こんにちは"}],
    "model": "@cf/ibm-granite/granite-4.0-h-micro"
  }'

部署示例.js

export default {
  async fetch(request, env) {
    // 只允许 POST
    if (request.method !== "POST") {
      return new Response("Method Not Allowed", { status: 405 });
    }

    // Bearer Token 验证
    const EXPECTED_TOKEN = "Bearer abc123sm";

    const auth = request.headers.get("Authorization");
    if (!auth || auth !== EXPECTED_TOKEN) {
      return new Response("Unauthorized", { status: 401 });
    }

    let body;
    try {
      body = await request.json();
    } catch {
      return new Response("Invalid JSON", { status: 400 });
    }

    const messages = body.messages;
    if (!Array.isArray(messages)) {
      return new Response("Missing messages", { status: 400 });
    }

    const model = body.model || "@cf/ibm-granite/granite-4.0-h-micro";

    try {
      // 调用AI模型
      const result = await env.AI.run(model, { messages });
      
      // 调试:打印返回结果
      console.log("使用模型:", model);
      console.log("AI返回结果:", JSON.stringify(result));
      
      // 根据不同的模型返回格式,提取回复内容
      let replyContent;
      
      // ========== 模型1: @cf/ibm-granite/granite-4.0-h-micro ==========
      if (model === "@cf/ibm-granite/granite-4.0-h-micro") {
        // 处理IBM Granite模型的复杂嵌套格式
        if (result.choices && result.choices.length > 0) {
          if (result.choices[0].message && result.choices[0].message.content) {
            const content = result.choices[0].message.content;
            // 如果content是字符串,直接使用
            if (typeof content === 'string') {
              replyContent = content;
            } 
            // 如果content是对象,尝试进一步提取
            else if (typeof content === 'object' && content.choices) {
              replyContent = content.choices[0]?.message?.content || JSON.stringify(content);
            }
          }
        }
        // 方法2: 如果返回的是简单response字段
        else if (result.response) {
          replyContent = result.response;
        }
        // 方法3: 其他格式,直接转换为字符串
        else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      // ========== 模型2: @cf/meta/llama-3.2-1b-instruct ==========
      else if (model === "@cf/meta/llama-3.2-1b-instruct") {
        // 处理Llama模型的简单格式
        if (result.response) {
          replyContent = result.response;
        } 
        // 如果返回的是标准OpenAI格式
        else if (result.choices && result.choices.length > 0) {
          const message = result.choices[0].message;
          if (message && message.content) {
            replyContent = message.content;
          }
        }
        // 其他情况
        else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      // ========== 其他模型(通用处理) ==========
      else {
        // 通用处理逻辑
        if (result.response) {
          replyContent = result.response;
        } else if (result.choices && result.choices.length > 0) {
          const message = result.choices[0].message;
          if (message && message.content) {
            replyContent = message.content;
          }
        } else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      
      // 返回标准的OpenAI格式
      return new Response(JSON.stringify({
        choices: [{
          message: {
            role: "assistant",
            content: replyContent || "AI未返回有效回复"
          }
        }]
      }), {
        headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*"
        },
      });
    } catch (error) {
      console.error("AI调用失败:", error);
      return new Response(JSON.stringify({
        error: "AI模型调用失败",
        details: error.message
      }), { status: 500 });
    }
  },
};

示例模板

正面模板

{{Audio}}
<div>{{Snapshot}}</div>
<div>{{am-highlighted}}</div>

<script>
function copyReading(button) {
  // 从按钮的anniu属性获取特定字段的内容
  const readingText = button.getAttribute('data-copy-anniu');
  
  // 创建临时textarea元素
  const textarea = document.createElement('textarea');
  textarea.value = readingText;
  document.body.appendChild(textarea);
  
  // copy
  textarea.select();
  document.execCommand('copy');
  
  // delete
  document.body.removeChild(textarea);
  
  // update
  const originalText = button.textContent;
  button.textContent = '搞掂';
  button.classList.add('copied');
}
</script>

背面模板

<button class="copy-btn" onclick="copyReading(this)" data-copy-anniu="{{Expression}}">复制</button>
<div>{{am-highlighted}}</div>
<div>{{Snapshot}}</div>
<button onclick="pycmd('aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d8b40; font-size: 14px;float: right">——</button><div style='font-size: 40px'><button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d4b40; font-size: 14px;float: right">——</button>{{edit:Meaning}}</div>

<div style='font-size: 25px; text-align:start'>{{edit:Edit}}</div>

CSS样式

.card {
  font-family: arial;
  font-size: 50px;
  text-align: center;
  color: #CDC8B1;
  background-color: #25390c;##f1e5c9;
}
.card.nightMode {
  font-family: arial;
  font-size: 50px;
  text-align: center;
  color: #8B8878;
  #background-color: #25390c;
}

.expression{
  font-size: 40px;
}
[morph-status=unknown] { color: red; }
[morph-status=learning] { color: #1E90FF; }
[morph-status=known] { color: green; }


.copy-btn {
  padding: 10px 1px;
  background-color: #3d8b40;
  font-size: 18px;     /* 可用 !important增大字体 */
  float: left;
}

.copy-btn.copied {
  background-color: #666;
}

效果预览

效果预览

因为使用的字段不同,所以可以与AI提问共存(一个是 CF_aiGenerate,一个是 aiGenerate) 共存

插件设置参考

CF AI worker

CF AI worker

反代API

反代API

模型

CF 模型价格

每天有免费0.11美元额度,反正对我来说是够够的

  1. worker AI model页面
  2. CF的文档

模型个人使用体验

便宜

@cf/ibm-granite/granite-4.0-h-micro 最便宜,但有些时候给英文 $0.017

@cf/meta/llama-3.2-1b-instruct 也挺便宜,但有些时候给英文,幻觉还多 $0.027

@cf/meta/llama-3.2-3b-instruct 我目前感觉很不错的,推荐 $0.051

@cf/meta/llama-3.1-8b-instruct-fast @cf/meta/llama-3.1-8b-instruct-fp8-fast 8b还会天天爆英文…… $0.045

@cf/meta/llama-2-7b-chat-fp16 不是,怎么meta的这么喜欢爆英文 $0.56 per M input tokens

@cf/qwen/qwen3-30b-a3b-fp8 喜欢给一堆文法解释,我是文法无用主义者,而且我prompt明明有避免使用语法术语这句话,他却无视了 $0.051

推荐

@cf/meta/llama-3.3-70b-instruct-fp8-fast 挺好用 $0.293

@cf/google/gemma-3-12b-it 挺好用 $0.345

千万不要用

速度好慢,结果乱给,不要用推理模型,不适合咱们场景
@cf/deepseek-ai/deepseek-r1-distill-qwen-32b
@cf/mistral/mistral-7b-instruct-v0.1

问题反馈

如果你遇到任何问题或有功能建议,欢迎到本项目的 GitHub Issues 页面提交。
或者 这个TG频道。

更新

README

Anki 插件:CF worker AI提问

这是一个Anki插件,允许您在卡片复习时一键调用AI(通过Cloudflare Workers或其他API)并将结果自动填入指定字段(需要配合1020366288插件)。

调用方式

卡片模板中添加按钮
例 <div style='font-size: 40px'><button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d4b40; font-size: 14px;float: right">——</button>

功能特性

  • 一键调用:在卡片模板中添加一个按钮,即可快速向AI提问。
  • 高度可配置:支持自定义 API Key、模型、系统提示词、上下文对话等。
  • 智能上下文:支持配置多轮对话作为上下文,让AI的回答更符合你的期望。
  • 无缝体验:优化了与 Edit Field During Review 插件的兼容性,更新解析后无需刷新卡片。
  • 自动创建配置:首次使用时会自动生成配置文件,简化初始设置。

安装与配置

  1. 安装插件与依赖插件:

    • 通过 AnkiWeb 页面下载,或使用代码 [8664763] 安装。
    • 或通过 Github releases 页面下载,并解压至anki插件目录。
    • 通过 AnkiWeb 页面下载,或使用代码 [1020366288] 安装依赖插件Edit Field During Review。
  2. 获取 API Key:

    • 参考下方的 CF AI worker部署说明 部署一个自己的CF AI worker
    • 访问 qwen-free-api部署反代API。
    • PS1. 其他反代AI大概也行
    • PS2. 这些反代项目都被投毒了,需要自己删除有毒的代码构建
  3. 配置插件:

    • 在 Anki 主界面,点击菜单栏的 工具 > AI提问配置。
    • 将你获取的 Authorization 填入 Authorization ,如 Bearer abc123sm 。
    • 根据你的卡片模板,设置 提问字段 (例如:Expression) 和 回答字段 (例如:Edit)。
    • (可选)根据你的需求修改系统提示词和其他参数。
    • 点击 "保存"。
  4. 在卡片模板中添加按钮:

    • 这是必须的步骤!你需要手动在你的卡片模板中添加一个按钮来触发AI。
    • 打开 Anki 的 工具 > 管理笔记类型,选择你使用的笔记类型,然后点击 卡片...。
    • 在“正面模板”或“背面模板”的 HTML 代码中,找到一个合适的位置,粘贴以下代码:
    <button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40; font-size: 14px;">AI提问</button>
    

CF AI worker部署说明

  1. 有一个CF账号,并且有域名,绑定信用卡等前置操作
  2. 登录 Cloudflare Dashboard
  3. 创建新的Worker,如 anki-ai-proxy
  4. 将 CF worker示例.js的内容粘贴进去
  5. 修改第9行的Bearer Token(改成你自己的)
  6. 保存并部署
  7. 测试可用性(可选) 网址改成你的,token改成你的
curl -X POST "https://anki-ai-proxy.abc123sm.workers.dev" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer abc123sm" \
  -d '{
    "messages": [{"role": "user", "content": "こんにちは"}],
    "model": "@cf/ibm-granite/granite-4.0-h-micro"
  }'

部署示例.js

export default {
  async fetch(request, env) {
    // 只允许 POST
    if (request.method !== "POST") {
      return new Response("Method Not Allowed", { status: 405 });
    }

    // Bearer Token 验证
    const EXPECTED_TOKEN = "Bearer abc123sm";

    const auth = request.headers.get("Authorization");
    if (!auth || auth !== EXPECTED_TOKEN) {
      return new Response("Unauthorized", { status: 401 });
    }

    let body;
    try {
      body = await request.json();
    } catch {
      return new Response("Invalid JSON", { status: 400 });
    }

    const messages = body.messages;
    if (!Array.isArray(messages)) {
      return new Response("Missing messages", { status: 400 });
    }

    const model = body.model || "@cf/ibm-granite/granite-4.0-h-micro";

    try {
      // 调用AI模型
      const result = await env.AI.run(model, { messages });
      
      // 调试:打印返回结果
      console.log("使用模型:", model);
      console.log("AI返回结果:", JSON.stringify(result));
      
      // 根据不同的模型返回格式,提取回复内容
      let replyContent;
      
      // ========== 模型1: @cf/ibm-granite/granite-4.0-h-micro ==========
      if (model === "@cf/ibm-granite/granite-4.0-h-micro") {
        // 处理IBM Granite模型的复杂嵌套格式
        if (result.choices && result.choices.length > 0) {
          if (result.choices[0].message && result.choices[0].message.content) {
            const content = result.choices[0].message.content;
            // 如果content是字符串,直接使用
            if (typeof content === 'string') {
              replyContent = content;
            } 
            // 如果content是对象,尝试进一步提取
            else if (typeof content === 'object' && content.choices) {
              replyContent = content.choices[0]?.message?.content || JSON.stringify(content);
            }
          }
        }
        // 方法2: 如果返回的是简单response字段
        else if (result.response) {
          replyContent = result.response;
        }
        // 方法3: 其他格式,直接转换为字符串
        else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      // ========== 模型2: @cf/meta/llama-3.2-1b-instruct ==========
      else if (model === "@cf/meta/llama-3.2-1b-instruct") {
        // 处理Llama模型的简单格式
        if (result.response) {
          replyContent = result.response;
        } 
        // 如果返回的是标准OpenAI格式
        else if (result.choices && result.choices.length > 0) {
          const message = result.choices[0].message;
          if (message && message.content) {
            replyContent = message.content;
          }
        }
        // 其他情况
        else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      // ========== 其他模型(通用处理) ==========
      else {
        // 通用处理逻辑
        if (result.response) {
          replyContent = result.response;
        } else if (result.choices && result.choices.length > 0) {
          const message = result.choices[0].message;
          if (message && message.content) {
            replyContent = message.content;
          }
        } else {
          replyContent = typeof result === 'string' ? result : JSON.stringify(result);
        }
      }
      
      // 返回标准的OpenAI格式
      return new Response(JSON.stringify({
        choices: [{
          message: {
            role: "assistant",
            content: replyContent || "AI未返回有效回复"
          }
        }]
      }), {
        headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*"
        },
      });
    } catch (error) {
      console.error("AI调用失败:", error);
      return new Response(JSON.stringify({
        error: "AI模型调用失败",
        details: error.message
      }), { status: 500 });
    }
  },
};

示例模板

正面模板

{{Audio}}
<div>{{Snapshot}}</div>
<div>{{am-highlighted}}</div>

<script>
function copyReading(button) {
  // 从按钮的anniu属性获取特定字段的内容
  const readingText = button.getAttribute('data-copy-anniu');
  
  // 创建临时textarea元素
  const textarea = document.createElement('textarea');
  textarea.value = readingText;
  document.body.appendChild(textarea);
  
  // copy
  textarea.select();
  document.execCommand('copy');
  
  // delete
  document.body.removeChild(textarea);
  
  // update
  const originalText = button.textContent;
  button.textContent = '搞掂';
  button.classList.add('copied');
}
</script>

背面模板

<button class="copy-btn" onclick="copyReading(this)" data-copy-anniu="{{Expression}}">复制</button>
<div>{{am-highlighted}}</div>
<div>{{Snapshot}}</div>
<button onclick="pycmd('aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d8b40; font-size: 14px;float: right">——</button><div style='font-size: 40px'><button onclick="pycmd('CF_aiGenerate')" style="padding: 10px 1px; background: #3d8b40;color:#3d4b40; font-size: 14px;float: right">——</button>{{edit:Meaning}}</div>

<div style='font-size: 25px; text-align:start'>{{edit:Edit}}</div>

CSS样式

.card {
  font-family: arial;
  font-size: 50px;
  text-align: center;
  color: #CDC8B1;
  background-color: #25390c;##f1e5c9;
}
.card.nightMode {
  font-family: arial;
  font-size: 50px;
  text-align: center;
  color: #8B8878;
  #background-color: #25390c;
}

.expression{
  font-size: 40px;
}
[morph-status=unknown] { color: red; }
[morph-status=learning] { color: #1E90FF; }
[morph-status=known] { color: green; }


.copy-btn {
  padding: 10px 1px;
  background-color: #3d8b40;
  font-size: 18px;     /* 可用 !important增大字体 */
  float: left;
}

.copy-btn.copied {
  background-color: #666;
}

效果预览

效果预览

因为使用的字段不同,所以可以与AI提问共存(一个是 CF_aiGenerate,一个是 aiGenerate) 共存

插件设置参考

CF AI worker

CF AI worker

反代API

反代API

模型

CF 模型价格

每天有免费0.11美元额度,反正对我来说是够够的

  1. worker AI model页面
  2. CF的文档

模型个人使用体验

便宜

@cf/ibm-granite/granite-4.0-h-micro 最便宜,但有些时候给英文 $0.017

@cf/meta/llama-3.2-1b-instruct 也挺便宜,但有些时候给英文,幻觉还多 $0.027

@cf/meta/llama-3.2-3b-instruct 我目前感觉很不错的,推荐 $0.051

@cf/meta/llama-3.1-8b-instruct-fast @cf/meta/llama-3.1-8b-instruct-fp8-fast 8b还会天天爆英文…… $0.045

@cf/meta/llama-2-7b-chat-fp16 不是,怎么meta的这么喜欢爆英文 $0.56 per M input tokens

@cf/qwen/qwen3-30b-a3b-fp8 喜欢给一堆文法解释,我是文法无用主义者,而且我prompt明明有避免使用语法术语这句话,他却无视了 $0.051

推荐

@cf/meta/llama-3.3-70b-instruct-fp8-fast 挺好用 $0.293

@cf/google/gemma-3-12b-it 挺好用 $0.345

千万不要用

速度好慢,结果乱给,不要用推理模型,不适合咱们场景
@cf/deepseek-ai/deepseek-r1-distill-qwen-32b
@cf/mistral/mistral-7b-instruct-v0.1

问题反馈

如果你遇到任何问题或有功能建议,欢迎到本项目的 GitHub Issues 页面提交。
或者 这个TG频道。

更新