案例
先看下效果吧 AI 图片生成
初步准备
要开始这个项目,首先需要:
调试
当获取了 Account ID 和 Token 之后,就可以开始调试了。
curl -X POST \
https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/ai/run/@cf/meta/llama-2-7b-chat-int8 \
-H "Authorization: Bearer {API_TOKEN}" \
-d '{ "prompt": "Where did the phrase Hello World come from" }'
当正确返回如下类似的字段,说明准备工作已经做好了。
{
"result": {
"response": "Hello, World first appeared in 1974 at Bell Labs when Brian Kernighan included it in the C programming language example. It became widely used as a basic test program due to simplicity and clarity. It represents an inviting greeting from a program to the world."
},
"success": true,
"errors": [],
"messages": []
}
创建 Worker
- 将如下脚本上传到 Cloudflare Worker或者使用模板创建
- 在Worker设置中(Settings -> Variables),配置 ACCOUNT_ID 和 BEARER_TOKEN。
- 测试 Worker:点击 Quick Edit,直接利用 Cloudflare 的内置功能进行接口调试[2][3]。
- 配置自己的 Custom Domains,以便访问更方便。
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
// 主要的请求处理函数
async function handleRequest(request) {
// 处理 CORS 预检请求
if (request.method === "OPTIONS") {
return handleCors();
}
return handleChatGPTRequest(request);
}
// 处理 CORS 预检请求的函数
function handleCors() {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS"
}
});
}
async function handleChatGPTRequest(request) {
const url = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/ai/run/@cf/stabilityai/stable-diffusion-xl-base-1.0 `;
const headers = {
"Authorization": `Bearer ${BEARER_TOKEN}`,
"Content-Type": "application/json"
};
const newRequest = new Request(url, {
method: "POST",
headers: headers,
body: request.body
});
const response = await fetch(newRequest);
const newResponse = new Response(response.body, response);
newResponse.headers.set("Access-Control-Allow-Origin", "*");
return newResponse;
}
发布
至此服务已经做好,剩下的就是简单的前端 html 页面了。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, viewport-fit=cover" />
<title>AI 图片生成</title>
</head>
<link rel="stylesheet" href="https://res.suning.cn/public/v5/common/2.0.0/channel.css">
<style>
</style>
<body style="margin: 20px auto;">
<div class="header" id="chatBox">
<p class="loading hide ">图片生成中,小水管服务器生成较慢,请喝口水耐心等待。。。</p>
</div>
<style>
.header{
text-align: center;
}
footer{
position: fixed;
bottom: 0;
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
color: #999;
font-size: 12px;
background-color: #f2f2f2;
z-index: 9999;
}
.inputbox {
position: fixed;
bottom: 30px;
left: 0;
right: 0;
width: 90%;
max-width: 1000px;
margin: 0 auto;
display: flex;
align-items: center;
border: 1px solid rgba(0,0,0,.3);
padding-right: 12px;
background: #fff;
border-radius: 8px
}
.inputbox input{
flex-grow: 1;
height: 44px;
max-height: 100px;
border: 0;
outline: none;
padding: 12px 15px;
background: transparent;
font-size: 16px;
width: 100%;
font-weight: 700;
color: #000000b3
}
.btn-send {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 32px;
border-radius: 6px;
color: #0009;
background: rgba(0,0,0,.1)
}
.btn-send:hover {
cursor: pointer;
opacity: .85
}
img.list{
margin: 10px 0;
}
.loading{text-align: center;width:70%;font-size: 16px;position: fixed;top: 50%;left: 50%;transform: translate(-50%,-50%);background: #fff;padding: 10px;border-radius: 5px;}
</style>
<div class="inputbox">
<input type="text" placeholder="需要输入英文,示例:a cat in a box">
<div data-v-eddecc8f="" class="btn-send" id="submit-btn">
<div data-v-eddecc8f="" class="send-view" style="display: flex;"><img data-v-eddecc8f=""
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAxCAYAAABznEEcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFLElEQVR4nNWZWWyVZRCGHzltXUBwA+tWq+KGcUNFQiQmhmCsxL1oXCBq4AKjgnHXCy40NkGNvUADIdEAMbVyIRo1UiVGjSwRk3okiFi0KooVbVxYCqU1k7wnGf/829nbNzmB83e+75+Zb+ad+ebA8MSRwBxgA/ANwwyXAkuBv4FBfdYzDDAamAtscor7z2yGMC4BlgD/RChvnz+BIxhiOBp4AMhKyQFgb4jy6/Xv8wwhTAWWO4V3KvY/liEHnQGLJGvPxldb8aMU619JOVOqA2gGbgJ+0vNP3P9bgONk7PtDIdb3SLFfpdzpwAnAKnca9wPrnAGGx/T9ukorfjzwIPB1iNdrgUN0Kn8pfJYrVDZK/mntY3LbgG4gUwnFRwDTgHagT8rskEcbndyZwFr9/TutGQd0yqD5TrZJck+WW/l6HXlXiNdrnFyt5PYBB4BWYKROLSsDLJw83pFDTKasXt8v5X+W108NkZ8CbJbcl8oTwynAtzL8nsCaBqAfeL3Uyp8ob34vhfqd1zMR1bdVSu7W2pxcg8KpP6IKP6d3GB2X1OsHtLEl20J5MgozgB8l/17ghBqB7TLgzpC1dWKrzUrugnGSPNctRfpkyLSEjevFNrbmD7GQx9kKvT7VhzDcofXzClE847zer422ypixCWvNsFnALq1rV6HyOEeM1QdcH7PXZ+qhLBxTY7zCI3f8+1J6PYczgA+11sJkeojMRUCPit70mL0u0D6L0yhep4TsEL3Zwi3yetCDUaiR/F5Hm6NC5CbqhHbLMXF4Rbqcn+T1F4DfJWwbvyoazAeXuz5okxQNw2SgV9X5ioQ9R+sC9GnSy3v04h4lzpg8lR8VoM1HAkXNY6qU6pUxSZgn3W5PErzVncIbYpO0uNaxVYeauChcBfwrhsoVtyRkgd+AQ9NeRpYoF3rVrFk9iMI4R5u9os24hL9aCWynfWFKA67U/s+mlP/fwq2ujzcKDKLZnVy7DIpDkxJ9Z1JyBtCmEPXNYmocLnrdr5cvFHNZqKxx3eiNKfaaIXq2O8OEPHSoV+1YTZGYqOZsULOdPSp4L0XQZhC3iWZ/UN3IB0/pvddQAhjLPCxvWsWclHLdXTK4K6KLTeoSurU2Li/zxsvyTBT3e9yrWLbcOrmAd92gdxlVlxQTxFw2gYjDXBmwRW16IfhAJ5/UmyWiTh7x/LxWxczoOAzzZWhnCsaK6x4Oir6LNmB1yAXkZj17KGTNAtduHFvEuxdpnzTVPJUBiwMFrEbzn20hCfeLY7G4ljqJ2neJEYsy4O0IA4LUZwUshzF6llVLMajJnU2w88FsrZ1TjAFvaZOlMS3EWBXAd92zSVq3QPnSIpkBVfTTUuqwQS3MyHIakMMKKXiWvs8KKUwNSs4BVd7WhO74Yu1hhbQgtCWEUBCTJW93EMMz+h5Wle1O8rlr9e/TvCmIZTI4rFdLhTVihXymCF+43wZWKXyixoq270w3TAsmv4WgUfdHVBh3uyTM6pOEWhXD3CVsnU4qR89G4RXFYWrHO3UKdhppcQzwonJlQDe9HRFhVjJYmDwaQpkt7oePvC8uyqE3ZcgTlNmAlRENWaObRVnXWihsn6KmemkNWBmRuLnqHtWiN6utPpcqIJPCAMN5+vEv7O8zdSnarjyoKDJuCNAWM36Jwy3uVpe2YlOOC1DcCcQhdwJdqtxVwQpV70IMuKyaBowoUfLZROS1ahiQcUlcqCFT8hiKlQXLXA4UMl1oUghZ4aoaNsqQQn8XflzT8Kol8X8x75k5b0tu7gAAAABJRU5ErkJggg=="
style="width: 20px;"></div>
</div>
</div>
</div>
<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<footer>
<span class="hide" id="busuanzi_container_site_pv">本站总访问量 <span id="busuanzi_value_site_pv"></span> 次</span> ·
<span>基于 stable-diffusion-xl-base-1.0 模型</span>
</footer>
<script>
var flag = true;
function clean(msg) {
if (!msg) {
alert("内容不能为空!")
return;
}
if (!flag) {
console.log('不要重复请求!');
return
}
flag = false;
document.querySelector(".loading").classList.remove("hide");
fetch(
`https://ai.1953615.xyz/`,
{
method: "POST",
mode: "cors",
body: JSON.stringify({
"cfg_scale": 7,
"clip_guidance_preset": "FAST_BLUE",
"height": 512,
"width": 512,
"sampler": "K_DPM_2_ANCESTRAL",
"samples": 1,
"steps": 30,
"prompt": msg || "a cat in a room",
})
},
).then(response => response.blob()).then((d) => {
flag = true;
let img = new Image();
img.src = URL.createObjectURL(d);
img.className = "list"
img.onload = () => {
document.querySelector("#chatBox").appendChild(img);
document.querySelector(".loading").classList.add("hide");
}
img.onerror = () => {
alert("服务拥堵,请稍后再试。。")
}
}).catch((error) => {
console.error("There has been a problem with your fetch operation:", error);
alert("服务拥堵,请稍后再试。")
document.querySelector(".loading").classList.remove("hide");
})
}
document.querySelector("#submit-btn").addEventListener("click", function (params) {
clean(document.querySelector("input").value)
});
</script>
</body>
</html>
Worker 的服务是跨域的,现在只要把页面发布到自己的服务器上就可以在线访问使用了。
TIPS:服务目前免费不代表以后免费
参考
- [1] 点击左侧 Workers and Pages,在页面右上方就有 Account ID