summary
Cloudflare Workers AI allows you to run machine learning models on Cloudflare's global network using serverless GPUs. You can integrate these models into your own code via Workers, Pages, or the Cloudflare API. The platform supports a variety of AI tasks, including image classification, text generation, and object detection.
Key features.
Model. A wide selection of open source models for different AI tasks.
Billing. Beginning April 1, 2024, non-test model usage will begin to be billed.
Resources. Access to related products such as Vectorize, R2, D1 and more.
strike (on the keyboard) Visit the Official Big Model Plaza
billing
Free Plan 10,000 Cows per day (Cows are cf's AI currency unit and can be used) Official Calculator Calculated), 10,000 cows available:
- 100-200 conversations
- 500 translations
- 500-second speech-to-text
- 10,000 text categorizations
- 1,500-15,000 embeds
Beginning April 1, 2024, the following models will be billed at $0.011/kcal per day in excess of 10,000 cows per day
- bge-small-en-v1.5
- bge-base-en-v1.5
- bge-large-en-v1.5
- distilbert-sst-2-int8
- llama-2-7b-chat-int8
- llama-2-7b-chat-fp16
- mistral-7b-instruct-v0.1
- m2m100-1.2b
- resnet-50
- whisper
Credit usage can be viewed in the AI tab of the cf panel, please refer to the specific billing rates:Pricing | Cloudflare Workers AI docs
Latest Workers AI Free Plan Limits(We will begin charging for all models under the new pricing structure beginning November 1, 2024.)
Model | Free Layer Size |
---|---|
Text Generation - LLM | 每天 10,000 个 token,适用于任何模型大小 |
embedding | 每天 10,000 个 token,适用于任何模型大小 |
photograph | 250 步之和,最高 1024x1024 分辨率 |
speech-to-text | 每天 10 分钟音频 |
easy get started
Before you start, you need to register your own account and log in
Get AccountID
show (a ticket) panel pageThe string after the last / in the address bar is your AccountID.
Get Token
show (a ticket) token page Create the token, taking care to select Workers AI
OneAPI Settings
dialog model
key: the token to get
base_url: https://api.cloudflare.com/client/v4/accounts/AccountID/ai, replacing AccountID
model::
- @cf/deepseek-ai/deepseek-math-7b-instruct
- @cf/defog/sqlcoder-7b-2
- @cf/fblgit/una-cybertron-7b-v2-awq
- @cf/fblgit/una-cybertron-7b-v2-bf16
- @cf/google/gemma-2b-it-lora
- @cf/google/gemma-7b-it-lora
- @cf/meta-llama/llama-2-7b-chat-hf-lora
- @cf/meta/llama-2-7b-chat-fp16
- @cf/meta/llama-2-7b-chat-int8
- @cf/meta/llama-3-8b-instruct
- @cf/meta/llama-3-8b-instruct-awq
- @cf/microsoft/phi-2
- @cf/mistral/mistral-7b-instruct-v0.1
- @cf/mistral/mistral-7b-instruct-v0.1-vllm
- @cf/mistral/mistral-7b-instruct-v0.2-lora
- @cf/openchat/openchat-3.5-0106
- @cf/qwen/qwen1.5-0.5b-chat
- @cf/qwen/qwen1.5-1.8b-chat
- @cf/qwen/qwen1.5-14b-chat-awq
- @cf/qwen/qwen1.5-7b-chat-awq
- @cf/thebloke/discolm-german-7b-v1-awq
- @cf/tiiuae/falcon-7b-instruct
- @cf/tinyllama/tinyllama-1.1b-chat-v1.0
- @hf/google/gemma-7b-it
- @hf/mistral/mistral-7b-instruct-v0.2
- @hf/nexusflow/starling-lm-7b-beta
- @hf/nousresearch/hermes-2-pro-mistral-7b
- @hf/thebloke/codellama-7b-instruct-awq
- @hf/thebloke/deepseek-coder-6.7b-base-awq
- @hf/thebloke/deepseek-coder-6.7b-instruct-awq
- @hf/thebloke/llama-2-13b-chat-awq
- @hf/thebloke/llamaguard-7b-awq
- @hf/thebloke/mistral-7b-instruct-v0.1-awq
- @hf/thebloke/neural-chat-7b-v3-1-awq
- @hf/thebloke/openhermes-2.5-mistral-7b-awq
- @hf/thebloke/zephyr-7b-beta-awq
POST Example:
curl --request POST \ --url https://api.cloudflare.com/client/v4/accounts/${AccountID}//ai/v1/chat/completions \ --header 'Authorization: Bearer token' \ --header 'Content-Type: application/json' \ --data ' { "model":"@cf/meta/llama-3-8b-instruct", "messages": [ { "role": "user", "content": "wooden spoon in 3 short steps? "content": "how to build a wooden spoon in 3 short steps? give as short as answer as possible" } ] } }] }
embedding model
Exactly the same as the dialog except the model is different and can be placed in a channel with the dialog
key: Token acquired
base_url::https://api.cloudflare.com/client/v4/accounts/AccountID/ai
Replacement of AccountID
model::
- @cf/baai/bge-base-en-v1.5
- @cf/baai/bge-large-en-v1.5
- @cf/baai/bge-small-en-v1.5
Vincennes model
key: Token acquired
base_url: your worker's address, the default address is walled off and must be routed.
model::
- @cf/bytedance/stable-diffusion-xl-lightning
- @cf/lykon/dreamshaper-8-lcm
- @cf/runwayml/stable-diffusion-v1-5-img2img
- @cf/runwayml/stable-diffusion-v1-5-inpainting
- @cf/stabilityai/stable-diffusion-xl-base-1.0
Worker.js code(Note the replacement of AccountID)
addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { if (request.method === "OPTIONS") { return new Response("", { headers: { 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*' }, status: 204 }); } if (/^(https?:\/\/[^\/]*?)\/file\//i.test(request.url)) { if (request.headers.get("if-modified-since")) { return new Response("", { status: 304, headers: { 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*', "Last-Modified": request.headers.get("If-Modified-Since") }}); } const img = await fetch(request.url.replace(/^(https?:\/\/[^\/]*?)\//, "https://telegra.ph/")); return new Response(img.body, { status: img.status, headers: { "content-type": img.headers.get("content-type"), 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*', "Last-Modified": (new Date()).toUTCString(), "Cache-Control": "public, max-age=31536000" }}); } const url = new URL(request.url); const search = url.searchParams; if (!search.get("debug")) { if (url.pathname !== "/v1/chat/completions" || request.method !== "POST") { return new Response("Not Found or Method Not Allowed", { status: 404, headers: { "Content-Type": "application/json", 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*' } }); } } const authHeader = request.headers.get("Authorization") || "Bearer " + search.get("key"); if (!authHeader || !authHeader.startsWith("Bearer ")) { return new Response("Unauthorized: Missing or invalid Authorization header", { status: 401, headers: { "Content-Type": "application/json", 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*' } }); } const apiKey = authHeader.slice(7); let data; try { data = await request.json(); } catch (error) { if (!search.get("debug")) return new Response("Bad Request: Invalid JSON", { status: 400 }); data = { model: search.get("model") || "@cf/stabilityai/stable-diffusion-xl-base-1.0", messages: [{ role: "user", content: search.get("prompt") || "cat" }] }; } if (!data || !data.model || !data.messages || data.messages.length === 0) { return new Response("Bad Request: Missing required fields", { status: 400 }); } const prompt = data.messages[data.messages.length - 1].content; const cloudflareUrl = `https://api.cloudflare.com/client/v4/AccountID/ai/run/${data.model}`; const requestBody = JSON.stringify({ prompt: prompt, num_inference_steps: 20, guidance_scale: 7.5, strength: 1 }); const currentTimestamp = Math.floor(Date.now() / 1000); const uniqueId = `imggen-${currentTimestamp}`; try { const apiResponse = await fetch(cloudflareUrl, { method: 'POST', headers: { 'Authorization': authHeader, 'Content-Type': 'application/json', }, body: requestBody, }); if (!apiResponse.ok) { throw new Error("Request error: " + apiResponse.status); } const imageBlob = await apiResponse.blob(); const formData = new FormData(); formData.append("file", imageBlob, "image.jpg"); const uploadResponse = await fetch("https://telegra.ph/upload", { method: 'POST', body: formData, }); if (!uploadResponse.ok) { throw new Error("Failed to upload image"); } const uploadResult = await uploadResponse.json(); const imageUrl = request.url.match(/^(https?:\/\/[^\/]*?)\//)[1] + uploadResult[0].src; const responsePayload = { id: uniqueId, object: "chat.completion.chunk", created: currentTimestamp, model: data.model, choices: [ { index: 0, delta: { content: `![](${imageUrl})`, }, finish_reason: "stop", }, ], }; const dataString = JSON.stringify(responsePayload); return new Response(`data: ${dataString}\n\n`, { status: 200, headers: { "Content-Type": "text/event-stream", 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*', }, }); } catch (error) { return new Response("Internal Server Error: " + error.message, { status: 500, headers: { "Content-Type": "application/json", 'Access-Control-Allow-Origin': '*', "Access-Control-Allow-Headers": '*', }, }); } }
text-to-speech model
key: Token acquired
base_url: your worker's address
model::
- @cf/openai/whisper
- @cf/openai/whisper-sherpa
- @cf/openai/whisper-tiny-en
POST Example:
Note the replacement of domain.com with your worker address.
curl -X POST https://domain.com/v1/audio/transcriptions \ -H "Authorization: Bearer token" \\ -F file=@C:\Users\Folders\audio.mp3 \ -F model="@cf/openai/whisper"
Worker.js code(Note the replacement of AccountID)
addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const url = new URL(request.url) const { pathname } = url if (request.method === 'POST' && pathname === '/v1/audio/transcriptions') { const formData = await request.formData() const file = formData.get('file') const model = formData.get('model') if (!file || !model) { return new Response('File or model not provided', { status: 400 }) } const apiUrl = `https://api.cloudflare.com/client/v4/accounts/AccountID/ai/run/${model}` const apiResponse = await fetch(apiUrl, { method: 'POST', headers: { 'Authorization': request.headers.get('Authorization'), 'Content-Type': 'application/octet-stream' }, body: file.stream() }) const apiResult = await apiResponse.json() const textResult = apiResult.result.text const formattedResult = JSON.stringify({ text: textResult }) return new Response(formattedResult, { headers: { 'Content-Type': 'application/json' } }) } else { return new Response('Not Found', { status: 404 }) } }
translation model
model::
- @cf/meta/m2m100-1.2b
Supported languages, source_lang and target_lang are in the same range.
- English (en)
- Chinese (zh)
- French (fr)
- German (de)
- Spanish (es)
- Italian (it)
- Japanese (ja)
- Korean (ko)
- Portuguese (pt)
- Russian (ru)
- Dutch (nl)
- Swedish (sv)
- Norwegian (no)
- Danish (da)
- Finnish (fi)
- Polish (pl)
- Turkish (tr)
- Arabic (ar)
- Hebrew (he)
- Indonesian (id)
- Thai (th)
- Vietnamese (vi)
- Hindi (hi)
- Malay (ms)
- Greek (el)
- Czech (cs)
- Slovak (sk)
- Romanian (ro)
- Hungarian (hu)
- Bulgarian (bg)
- Croatian (hr)
- Serbian (sr)
- Ukrainian (uk)
POST Example:
curl --request POST \ --url https://api.cloudflare.com/client/v4/accounts/account_id/ai/run/${model}\ --header 'Authorization: Bearer token' \\ --header 'Content-Type: application/json' \ --data '{ "source_lang": "en", "target_lang": "en", "text": "I love you." }'
Immersion Translation
Immersive Translation Open Beta in Developer Settings and select DeepLX(Beta) Address Input:https://你的worker地址/translate?password=${authKey}
worker.js
addEventListener('fetch', event => event.respondWith(handleRequest(event.request))); const model = '@cf/meta/m2m100-1.2b'; const authKey = 'YOUR_PASSWORD'; const accountId = 'YOUR_ACCOUNT_ID'; const token = 'YOUR_TOKEN'; async function handleRequest(request) { const url = new URL(request.url); if (request.method === 'OPTIONS') return new Response(null, { status: 204, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' } }); if (request.method !== 'POST' || url.pathname !== '/translate' || url.searchParams.get('password') !== authKey) return new Response(request.method !== 'POST' || url.pathname !== '/translate' ? 'Not Found' : 'Unauthorized', { status: request.method !== 'POST' || url.pathname !== '/translate' ? 404 : 401 }); const data = await request.json(); if (!data.text || !data.source_lang || !data.target_lang) return new Response('Bad Request', { status: 400 }); const cloudflareUrl = `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/run/${model}`; const init = { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ source_lang: data.source_lang.toLowerCase(), target_lang: data.target_lang.toLowerCase(), text: data.text }) }; try { const response = await fetch(cloudflareUrl, init); const responseData = await response.json(); return new Response(JSON.stringify({ alternatives: [], code: 200, data: responseData.result.translated_text, id: Math.floor(Math.random() * 10000000000), source_lang: data.source_lang, target_lang: data.target_lang }), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { console.error('Translation failed:', error); return new Response(JSON.stringify({ error: 'Translation failed' }), { headers: { 'Content-Type': 'application/json' }, status: 500 }); } }