demo:
0.前言
Cloudflare公司推出了workers-ai,可以免费在 Cloudflare 的全球网络上运行由无服务器 GPU 提供支持的机器学习模型。
Workers AI 可以 Cloudflare 网络上使用自己的代码运行机器学习模型,也就是说,只要写一个js代码,就可以免费调用cloudflare提供的大模型。这可以为我们节省大量的GPU支出成本。
当前worker ai提供的模型涵盖了文本分类、文本生成(GPT)、语音识别、图像分类、翻译、文生图等一系列领域,而且调用十分方便。
虽然免费用户每天有限额,但个人使用还是很够的~
1.前序准备
首先你需要有一个域名,并连接到cloudflare账户上。如果没有域名的话,阿里云之类的服务商都有新人1元域名活动,一块钱就能拥有一个属于自己的网址也是蛮爽的。
而且cloudflare还提供了一系列 白嫖免费计划,可以零成本(仅域名支出)就能搭建整套的个人网站。
在添加域名的时候,选择Free计划
即可。
2.创建项目
2.1 创建worker
在右侧的菜单里,选择 Workers 和 Pages
,随后点击创建
按钮。
在下一页中点击创建Worker
,随便起个名,点击部署即可
点击右上角的编辑代码
,把自带的演示代码全部删掉,将下方代码复制粘贴进去
worker.js:
import HTML from './index.html';
export default {
async fetch(request, env) {
const originalHost = request.headers.get("host");
// 设置CORS头部
const corsHeaders = {
'Access-Control-Allow-Origin': '*', // 允许任何源
'Access-Control-Allow-Methods': 'GET, POST', // 允许的请求方法
'Access-Control-Allow-Headers': 'Content-Type' // 允许的请求头
};
// 预检请求
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: corsHeaders
});
}
// 检查请求方法
if (request.method === 'POST') {
// 处理 POST 请求,用于 AI 绘画功能
const data = await request.json();
let model = '@cf/lykon/dreamshaper-8-lcm';
if ('prompt' in data && 'model' in data) {
switch(data.model) {
case 'dreamshaper-8-lcm':
model = '@cf/lykon/dreamshaper-8-lcm';
break;
case 'stable-diffusion-xl-base-1.0':
model = '@cf/stabilityai/stable-diffusion-xl-base-1.0';
break;
case 'stable-diffusion-xl-lightning':
model = '@cf/bytedance/stable-diffusion-xl-lightning';
break;
default:
break;
}
const inputs = {
prompt: data.prompt,
};
const response = await env.AI.run(model, inputs);
return new Response(response, {
headers: {
...corsHeaders,
'content-type': 'image/png;base64',
},
});
} else {
return new Response('Missing prompt or model', { status: 400, headers: corsHeaders });
}
} else {
// 处理 GET 请求,返回html页面
return new Response(HTML.replace(/{{host}}/g, originalHost), {
status: 200,
headers: {
...corsHeaders, // 合并CORS头部
"content-type": "text/html"
}
});
}
}
};
然后点击左上角的Explorer,选择New File,新建一个名为index.html
的文件(如图所示)
切换到此index.html文件,将以下代码粘贴进去:
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>AI绘画</title>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
display: flex;
flex-direction: column; /* 内容垂直排列 */
}
.box {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to right, #e6f5ff, #ffe6f5);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.card {
position: absolute;
inset: 2% auto;
max-width: 80%;
width: 90%;
backdrop-filter: blur(21px) saturate(180%);
-webkit-backdrop-filter: blur(21px) saturate(180%);
background-color: rgba(255, 255, 255, 0.53);
border-radius: 10px;
border: 1px solid rgba(209, 213, 219, 0.3);
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1rem;
left: 50%;
transform: translateX(-50%);
text-align: center;
overflow: hidden;
}
h1 {
font-size: 2.5em;
margin-bottom: 1rem;
}
img {
width: 100%;
max-width: 400px;
height: auto;
margin-bottom: 1rem;
}
select, input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 1rem;
border: 1px solid #ccc;
border-radius: 5px;
line-height: 3.5;
background-color: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(30px) saturate(180%);
border-radius: 5px;
padding: 10px;
outline: none;
transition: background-color 0.3s ease;
}
select, input[type="text"]:focus {
background-color: rgba(255, 255, 255, 99.9);
}
button.submit-btn {
background: linear-gradient(to bottom, #ade8f4, #6cb3e3);
border-radius: 5px;
color: white;
padding: 10px 20px;
font-family: Arial, sans-serif;
cursor: pointer;
border: none;
transition: all 0.3s ease;
}
button.random-btn {
background: white; /* 白色背景 */
color: #007BFF; /* 蓝色文字 */
border-radius: 5px;
padding: 5px 40px;
font-family: Arial, sans-serif;
cursor: pointer;
border: 1px solid #007BFF; /* 添加蓝色边框 */
transition: all 0.3s ease;
}
button.submit-btn:hover {
opacity: 0.6;
}
@media screen and (max-width: 600px) {
.card {
inset: 10% auto;
max-width: 100%;
width: 90%;
left: 0%;
transform: none;
/* 保持原有的模糊效果和其他样式 */
backdrop-filter: blur(21px) saturate(180%);
-webkit-backdrop-filter: blur(21px) saturate(180%);
background-color: rgba(255, 255, 255, 0.53);
border-radius: 10px;
border: 1px solid rgba(209, 213, 219, 0.3);
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
}
select, input[type="text"] {
width: 90%;
padding: 10px;
margin-bottom: 1rem;
border: 1px solid #ccc;
border-radius: 5px;
line-height: 7;
background-color: rgba(255, 255, 255, 0.1); /* 更改背景颜色以匹配磨砂效果 */
backdrop-filter: blur(30px) saturate(180%); /* 增加模糊量以获得更重的磨砂效果 */
border-radius: 5px; /* 可选:增加边框圆角美化 */
padding: 10px; /* 输入框内边距,根据需要调整 */
outline: none; /* 移除焦点时的轮廓 */
transition: background-color 0.3s ease; /* 平滑的背景色过渡效果 */
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
const submitButton = document.getElementById('submitButton');
submitButton.addEventListener('click', async function (event) {
event.preventDefault();
submitButton.disabled = true;
submitButton.textContent = '正在生成...';
const model = document.getElementById('model').value;
const prompt = document.getElementById('prompt').value;
// 检查prompt是否为空
if (prompt === '') {
alert('请输入描述词');
submitButton.textContent = '提交';
submitButton.disabled = false;
return;
}
const blobToBase64 = (blob) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
});
// 获取域名
const currentDomain = window.location.origin;
try {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort();
}, 30000); // 30秒超时
const response = await fetch(`${currentDomain}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'model': model,
'prompt': prompt
}),
signal: signal
});
if (!response.ok) {
throw new Error(`请求失败:${response.status} ${response.statusText}`);
}
// 读取响应的文本数据
// 将响应体转换为Blob
const blob = await response.blob();
// 将Blob转换为Base64编码的字符串
const Image = await blobToBase64(blob);
console.log('Base64 Image:', Image);
// const base64Image = await response.text();
document.getElementById('aiImage').src = `${Image}`;
} catch (error) {
if (error.name === 'AbortError') {
alert('服务器连接超时,请稍后重试。');
} else {
console.error('Error:', error);
alert('生成过程中发生错误,请重试。');
}
} finally {
submitButton.textContent = '提交';
submitButton.disabled = false;
}
});
document.getElementById('randomButton').addEventListener('click', function () {
// 提供的随机描述词
var prompts = ['1girl,solo,cute,in glass,atmosphere_X,best quality,beautiful,extremely detailed,masterpiece,very aesthetic',
'a girl,,nahida,light,full body,symbol eye, nahida,1girl,fair_skin,in summer,day,in a meadow,sky,cirrus_fibratus,intense shadows,blonde hair,pleated_dress,collared_shirt,blue eyes,long hair,fang,smile',
'((best quality)), ((masterpiece)),A Chinese couple in Hanfu embracing on an arch bridge, a sky full of rose petals, a romantic atmosphere, a huge moon, colorful clouds, clouds, ethereal, reflections of water, a mirage, a breeze,(Chinese ink style)',
'simple background, flower, signature, no humans, sparkle, leaf, plant, white flower, black background, still life, embroidery',
' 1 girl,(orange light effect),hair ornament,jewelry,looking at viewer,flower,floating hair,water,underwater,air bubble,submerged, 80sDBA style',
'masterpiece,best quality,high quality,loli,1girl, solo, long hair, looking at viewer, blush, bangs, thighhighs, dress, ribbon, brown eyes, very long hair, closed mouth, standing, full body, yellow eyes, white hair, short sleeves, outdoors, sky,no shoes, day, puffy sleeves, looking back, cloud, from behind, white dress, white thighhighs, red ribbon, tree, blue sky, puffy short sleeves, petals, cherry blossoms, skirt hold,',
' 1 girl,Clothes in the shape of snowflake,render,technology, (best quality) (masterpiece), (highly in detailed), 4K,Official art, unit 8 k wallpaper, ultra detailed, masterpiece, best quality, extremely detailed,CG,low saturation, as style, line art',
' best quality,masterpiece,sculpture,wonderland,,chinese fairy tales,an old man,boiling tea,drink tea,a painting of history floating and curved in the background,mountain,white cloud,chinese style courtyard,pavilion,chinese tea mountains,, Chinese architecture, trees,,white hair ,',
' 1girl, absurdres, arrow_(symbol), ata-zhubo, bicycle, billboard, black_eyes, black_footwear, black_hair, blue_sky, bridge, building, car, cardigan, city, cityscape, commentary_request, crosswalk, day, fire_hydrant, folding_bicycle, grey_cardigan, highres, lamppost, loafers, motor_vehicle, necktie, original, overpass, power_lines, railing, red_necktie, red_skirt, road, road_sign, scenery, school_uniform, shoes, short_hair, sign, skirt, sky, solo, stairs, standing, street, traffic_cone, traffic_light, truck, utility_pole, vending_machine',
'1girl, solo, elf, golden eyes, glowing eyes, slit_pupils, silver hair, green gradient hair, long hair, blunt bangs, brown capelet, frilled shirt, long sleeves, green brooch, pouch, belt, brown gloves, upper body, (chibi:0.4), (close-up), (broken:1.3), half-closed eye, expressionless, from side, depth of field, fallen leaves, side light, gingko, tree, masterpiece,bestquality, line art,',
'flower, outdoors, sky, tree, no humans, window, bird, building, scenery, house,oil painting style',
];
var randomIndex = Math.floor(Math.random() * prompts.length);
document.getElementById('prompt').value = prompts[randomIndex];
});
});
</script>
</head>
<body>
<div class="box">
<div class="card">
<h1>AI绘画</h1>
<img id="aiImage"
src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAIAAAB7GkOtAAADEUlEQVR4nO3BgQAAAADDoPlTX+EAVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBvArQAAVkUTe8AAAAASUVORK5CYII="
alt="AI生成的图片"> <!-- 默认是黑色的图片占位符 -->
<select id="model">
<option value="dreamshaper-8-lcm">DreamShaper 8 LCM(容易出黑图)</option>
<option value="stable-diffusion-xl-base-1.0" selected>Stable Diffusion XL Base 1.0(效果好,速度较慢)</option>
<option value="stable-diffusion-xl-lightning">Stable Diffusion XL Lightning(效果一般,速度较快)</option>
</select>
<input type="text" id="prompt" placeholder="请输入描述词...">
<button type="button" class="random-btn" id="randomButton">随机提示词</button>
<button type="button" class="submit-btn" id="submitButton">提交</button>
</div>
</div>
</body>
</html>
这里给定了几个随机的提示词,点击“随机提示词”按钮即可填充,可以根据需要增添。每个提示词我都生成了几张示例图(见最后)。
之后点击右上角的部署
按钮,并点击“保存并部署”,即可保存此Worker。
2.2 绑定AI
返回到worker页面,选择设置--变量,向下滑找到"AI绑定"一项。选择“添加绑定”,
选择“添加绑定”,名称写AI
即可。随后点击部署按钮。
2.3 绑定自己的域名
默认的workers.dev域名由于网络原因在国内无法使用,所以需要绑定一个自己的域名。
返回worker页面,点击“设置”,选择“添加自定义域”,填入一个刚才绑定在cloudflare的域名,二级域名可以随便写,比如:xxx.domain.com,这里的domain.com就是刚才绑定在cloudflare的域名,xxx可以随意更改。
输入后即可点击“添加自定义域”。cloudflare会自动完成解析的工作。
随后点击下方的“添加路由”,路由输入框填写与刚才相同的内容(xxx.domain.com),区域选择此主域名
稍等片刻,等待证书初始化完成,点击此链接即可访问刚才部署的页面。
黑色图片是占位符;输入描述之后点击提交,稍后即可生成图片。
3.随机提示词
以下是部分我使用的提示词,可以修改html页面var prompts
部分,每一行是一个提示词,格式如下:
var prompts = [
'提示词1',
'提示词2',
'提示词3',
];
部分提示词及生成的图如下,均使用Stable Diffusion XL Base 1.0生成。
1girl,solo,cute,in glass,atmosphere_X,best quality,beautiful,extremely detailed,masterpiece,very aesthetic
a girl,,nahida,light,full body,symbol eye, nahida,1girl,fair_skin,in summer,day,in a meadow,sky,cirrus_fibratus,intense shadows,blonde hair,pleated_dress,collared_shirt,blue eyes,long hair,fang,smile
((best quality)), ((masterpiece)),A Chinese couple in Hanfu embracing on an arch bridge, a sky full of rose petals, a romantic atmosphere, a huge moon, colorful clouds, clouds, ethereal, reflections of water, a mirage, a breeze,(Chinese ink style)
simple background, flower, signature, no humans, sparkle, leaf, plant, white flower, black background, still life, embroidery
1 girl,(orange light effect),hair ornament,jewelry,looking at viewer,flower,floating hair,water,underwater,air bubble,submerged, 80sDBA style
masterpiece,best quality,high quality,loli,1girl, solo, long hair, looking at viewer, blush, bangs, thighhighs, dress, ribbon, brown eyes, very long hair, closed mouth, standing, full body, yellow eyes, white hair, short sleeves, outdoors, sky,no shoes, day, puffy sleeves, looking back, cloud, from behind, white dress, white thighhighs, red ribbon, tree, blue sky, puffy short sleeves, petals, cherry blossoms, skirt hold,
(ps:效果不太好,AI还是无法理解什么是手)
1 girl,Clothes in the shape of snowflake,render,technology, (best quality) (masterpiece), (highly in detailed), 4K,Official art, unit 8 k wallpaper, ultra detailed, masterpiece, best quality, extremely detailed,CG,low saturation, as style, line art
best quality,masterpiece,sculpture,wonderland,,chinese fairy tales,an old man,boiling tea,drink tea,a painting of history floating and curved in the background,mountain,white cloud,chinese style courtyard,pavilion,chinese tea mountains,, Chinese architecture, trees,,white hair ,
1girl, absurdres, arrow_(symbol), ata-zhubo, bicycle, billboard, black_eyes, black_footwear, black_hair, blue_sky, bridge, building, car, cardigan, city, cityscape, commentary_request, crosswalk, day, fire_hydrant, folding_bicycle, grey_cardigan, highres, lamppost, loafers, motor_vehicle, necktie, original, overpass, power_lines, railing, red_necktie, red_skirt, road, road_sign, scenery, school_uniform, shoes, short_hair, sign, skirt, sky, solo, stairs, standing, street, traffic_cone, traffic_light, truck, utility_pole, vending_machine
(ps:AI还是没法把控细节,或者是这个模型的原因...?)
1girl, solo, elf, golden eyes, glowing eyes, slit_pupils, silver hair, green gradient hair, long hair, blunt bangs, brown capelet, frilled shirt, long sleeves, green brooch, pouch, belt, brown gloves, upper body, (chibi:0.4), (close-up), (broken:1.3), half-closed eye, expressionless, from side, depth of field, fallen leaves, side light, gingko, tree, masterpiece,bestquality, line art,
flower, outdoors, sky, tree, no humans, window, bird, building, scenery, house,oil painting style
4.结论
选项全部默认,绘图大概在10s左右一张图,倒是可以接受。如果想一次生成多张图片,可以使用程序给api发请求,worker理论上并发没限制。
AI还是对手部优化不是很理想,涉及到手部的基本都是畸形种,可能是我的模型选取问题...?,而且AI绘画没有图层概念,主体和背景都是交融在一起的,只能期望后续发展了。
不错不错,我喜欢看
想想你的文章写的特别好https://www.ea55.com/
文章的确不错啊https://www.cscnn.com/