本篇文章源于他人创意的启发与深入思考,我投入了大量时间与精力,致力于EdgeOne与HAI之间的协同调试,克服了众多技术奇葩问题。通过不懈的努力,成功地将这两个强大的平台整合在一起,打造出一个还不错的参考案例。这次探索也是我个人首次涉足边缘函数式产品的实践之旅。我希望通过分享这次的经历和成果,能够激
在当今快速发展的数字时代,安全和速度已成为网络服务的基石。EdgeOne,作为腾讯云提供的边缘安全加速平台,以其全球部署的节点和强大的安全防护功能,为用户提供了稳定而高效的网络体验。而HAI(HyperApplicationInventor),腾讯云推出的高性能应用服务,通过其易用的图形化界面和丰富的模型库,使得AI应用开发变得触手可及。本文将探讨EdgeOne与HAI的结合如何为用户提供一个既安全又高效的AI应用开发环境。
不多说了,剩下的内容都已经在官方文档中有详细描述。就我们个人而言,EdgeOne具有以下主要优点,并且我也附上了需要的关键文档地址:
HAI提供了可视化交互界面,支持JupyterLab、WebUI等多种算力连接方式,使得用户即使没有深厚的编程背景也能轻松开发AI应用。这种“有手就能开发”的设计理念,极大地降低了AI技术的应用门槛。支持学术加速,通过线路自动择优,能够大幅提升主流学术资源平台的访问、下载速度。同时,HAI预装了StableDiffusion、ChatGLM等热门模型,用户可以在数分钟内构建自己的大语言模型、AI作画等应用环境。
这个话题不需要详细讨论了,我已经整理了开发中需要了解的主要优点和相关文档,以便大家能够快速入手开发:
现在让我们来探讨一下为何可以采用联动开发的方式。我们的目标是以最为经济实惠的价格部署我们的AI绘画应用。
我们接下来看下我们会用到哪些技术:HTML、Javascript、CSS、Nginx、Python、边缘函数中的各个API、Linux基本命令。
关于创建服务器的步骤,我就不再进行演示了,请直接查看官方教程,相关地址也已经提供。我们将重点演示以下内容:下载/上传模型、通过WEB UI演示AI绘画功能、下载并配置Nginx以监听80端口、启动API接口服务。
这一步我当时使用过如何官方默认的JupyterLab页面上传,速度是真的很可观~我直接放弃了。选择了COS对象存储。我们先去下载好看的模型。这里以https://civitai.com/ 为例。
模型下载到本地之后,去创建COS对象存储服务。
如何创建这么简单的教程,我就不演示了,我们直接看上传和下载。这里创建存储桶的时候,所属地域一定要和你HAI绘画服务器在一起。否则会产生很多额外的花销。谨记~
进入存储桶之后,直接点击页面的上传文件即可,请选择刚才下载的模型文件。上传的过程中不要动浏览器,一旦刷新和关闭浏览器就会前功尽弃。
稍等片刻,然后点击模型文件的详情,进入基本信息页面。在这里,请确保将权限设置为公有读取,否则HAI服务器将无法下载到模型文件。然后,复制临时链接。
我们进入已经创建好的HAI服务器。
进入终端,使用一下几个命令,下载模型文件到模型文件夹。
cd stable-diffusion-webui/models/Stable-diffusion
wget 临时链接粘贴到此处
等待下载完毕。
让我们前往WEB UI页面,尝试一下看看是否成功安装了。
在WEB UI页面上,选择您自己的模型文件,并使用一段神奇的提示词。当然,提示词越好,生成的结果也会越好。如果有任何不清楚的地方,您可以参考您下载的模型附带的教程。这样基本上就没有问题了。接下来,让我们再来看看如何让HAI提供站点服务。
依然是同样的步骤,在JupyterLab中的终端中直接使用以下命令操作:
apt install nginx
进行安装。
service nginx start
启动服务。
当您直接使用IP地址在浏览器中访问后,如果显示以下界面,那就表示安装成功了。
接下来,我们继续修改Nginx的配置文件:
使用以下命令编辑配置文件:
vim /etc/nginx/sites-available/default
然后,在文件中添加以下配置:
# 配置/images路径的访问规则
location /images/ {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Expose-Headers' 'strict-origin-when-cross-origin';
alias /root/stable-diffusion-webui/outputs/star/images/; # 你的静态页面
expires 1d;
}
location /sdapi/ {
# Add CORS headers
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
proxy_pass http://127.0.0.1:7862/sdapi/;
if ($request_method = "OPTIONS"){
return 200;
}
}
这里配置了/images路径的访问规则以及API服务的代理。为什么要配置代理呢?这显然是因为绘画的API服务不支持跨域访问,所以我们添加了一个反向代理。由于我们的请求是POST非简单请求,因此浏览器还会发送一个OPTIONS的预检请求。我也做了相应的处理。以免跨域报错。
修改完成后,使用命令
service nginx reload
来重新加载Nginx的配置。您可以看到我们配置的/images路径对应的文件。这个路径您可以随心配置,只要确保其中包含您自己的图片即可。您可以选择自己维护这些图片,也可以通过程序生成。为了演示,我只简单复制了几张我使用AI绘画出来的图片。
让我们通过Nginx来访问一下图片,以确保可以正常访问。
在浏览器中输入以下地址进行访问:
http://你的IP/images/1.png
接下来,我们继续调试API服务。请启动HAI绘画应用的API服务,使用以下命令:
python launch.py --nowebui --xformers --opt-split-attention --listen --port 7862
然后,在浏览器中输入IP地址和端口号,后面加上/docs路径即可正常访问路径了。
让我们通过工具来测试一下,看看能否通过Nginx正常访问接口。你可以随意选择一个接口路径进行测试。我选择了一个简单的无请求参数的GET请求作为示例。通常情况下,这个请求会带有端口号。
使用调试工具来调用一下Nginx配置的路径,确保一切正常。
如果您还不确定的话,可以通过查看默认的Nginx访问路径来确认。您可以使用以下命令来实时查看日志:
tail -f /var/log/nginx/access.log
这样您就可以确定API是否能够被正确命中。
为了解决Nginx每次关机后无法正常启动的难题,我们采取了一项巧妙的解决方案:将启动命令直接写入API启动服务接口中,从而确保服务能够在每次启动时正确配置Nginx。具体操作如下:首先,我们需要找到项目中的launch.py文件。一旦找到了该文件,我们只需在其中添加几行命令即可。这些命令将确保Nginx在服务器启动时得到正确的配置,并能够顺利启动。这种方法简单而高效,能够有效解决Nginx启动问题,保证服务的稳定性和可靠性。
代码如下:
import subprocess
# 此处省略很多代码~~
def main():
# 使用subprocess.run()执行命令
result = subprocess.run(['service', 'nginx', 'start'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# 检查命令是否执行成功
if result.returncode == 0:
print("Nginx 已成功启动")
else:
print("启动 Nginx 时出错")
print("错误信息:", result.stderr)
# 此处省略很多代码~~
为了验证我们的解决方案的有效性,让我们再次重新启动API服务,观察是否能够成功启动Nginx。
通过以上步骤,我们的HAI高性能服务器已经完成了基本配置。无论进行多少次关机重启,我们的Nginx都会随着API接口一起启动,确保了系统的稳定性和可靠性。现在,让我们继续深入探讨EdgeOne的配置过程。
在配置EdgeOne时,首先需要确保完成无域名站点的配置,你可以直接参考官方文档进行操作。接着,我们需要创建边缘函数来实现相应的缓存处理。考虑到你没有企业版权限,因此无法使用四层加速,但可以通过边缘函数来达到类似的效果。关于边缘函数中代码的具体使用问题,我建议你仔细阅读官方文档,其中包含了详细的操作指南和示例代码,可以帮助你快速上手。你可以点击以下链接查看官方文档: EdgeOne 官方文档
在配置边缘函数时,你可以选择Hello World模板作为起点,然后依次点击下一步进行配置。虽然选择了Hello World模板,但它只是一个起点,我们将在此基础上进行深入的定制,以实现我们所需要的功能。
完成所有配置后,系统会为你生成一个默认的域名。接下来,我们需要编写代码来实现功能。通常情况下,我会额外编写一个test函数,专门用于测试。当然,如果你觉得不需要,也可以忽略。在这次配置中,我们创建了两个边缘函数。这些函数已经经过我封装,通过最小的变动来应对HAI服务器外网IP的变化,确保了系统的稳定性和可靠性。
一个绘画应用的关键之一在于能够提供优质的图片展示功能。毕竟,画作的视觉效果是吸引用户的关键之一。缺少了图片展示功能,这个应用就好比是一本没有插图的画册,缺乏吸引力,难以引起用户的兴趣。
async function fetchJquery(event, request) {
const cache = caches.default;
// 缓存没有命中,回源并缓存
let response = await fetch(request);
// 在响应头添加 Cahe-Control,设置缓存时长 10s
response.headers.append('Cache-Control', 's-maxage=600');
event.waitUntil(cache.put(request, response.clone()));
// 未命中缓存,设置响应头标识
response.headers.append('x-edgefunctions-cache', 'miss');
return response;
}
async function handleEvent(event) {
const urlInfo = new URL(event.request.url);
var url = new URL(event.request.url);
var ip = url.searchParams.get('ip');
// 请求非图片资源
if (!/\.(jpe?g|png)$/.test(urlInfo.pathname)) {
return event.respondWith(new Response('Error thrown 没命中图片URL' + urlInfo.pathname));
}
// 资源地址,也作为缓存键
const request = new Request(ip + urlInfo.pathname);
// 缓存默认实例
const cache = caches.default;
try {
// 获取关联的缓存内容,缓存过,接口底层不主动回源,抛出 504 错误
let response = await cache.match(request);
// 缓存不存在,重新获取远程资源
if (!response) {
return fetchJquery(event, request);
}
// 命中缓存,设置响应头标识
response.headers.append('x-edgefunctions-cache', 'hit');
return response;
} catch (e) {
await cache.delete(request);
// 缓存过期或其他异常,重新获取远程资源
return fetchJquery(event, request);
}
}
addEventListener('fetch', (event) => {
event.respondWith(handleEvent(event));
});
这段代码的主要功能是用于处理网络请求并管理资源的缓存策略,确保快速响应用户请求的同时,减少不必要的网络流量。
fetchJquery
函数:
fetch
函数发起网络请求,获取资源的最新响应。
Cache-Control
,设置资源在服务端缓存中的最长有效时间为600秒。
cache.put
方法将获取的响应克隆一份并存入缓存中,以便后续请求可以直接从缓存中获取。
x-edgefunctions-cache
为
miss
,表示这是一个未命中缓存的请求。
handleEvent
函数:
x-edgefunctions-cache
为
hit
,表示这是一个命中缓存的请求,并返回缓存中的资源。
fetchJquery
函数获取资源。
在访问图片资源时,需要特别注意的是,我采用了路径后面的 IP 参数进行访问。这是因为 HAI 每次重启后外网 IP 都会发生变化,如果每次都要修改每个边缘函数的话,会相当繁琐。为了避免这种情况,我选择通过参数传递的方式来获取图片资源。这样一来,获取图片资源的边缘函数就不需要再进行任何修改了。另外,你还需要对匹配触发规则进行配置,比如我设置的规则是包含 "/images" 的路径才会触发相应的操作。
在浏览器中输入默认域名,并随意添加 "/images/*.png" 即可访问相应图片,前提是该图片存储于我们的服务器上。现在让我们来观察一下效果。值得注意的是,这种方式的命中率并不是很高,所以在刚部署完边缘函数后,需要多刷新几次才能看到效果。
这个边缘函数专门用于处理用户交互。
const html = `
AI绘图
绘图结果
文本描述
`;
async function handleRequest(request) {
return new Response(html, {
headers: {
'content-type': 'text/html; charset=UTF-8',
'x-edgefunctions-test': 'Welcome to use Edge Functions.',
},
});
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
这段代码定义了一个HTML页面,用于展示一个AI绘图应用的用户界面,并包含了与之交互的JavaScript代码。主要功能和组成部分如下:
container
,用于布局两个主要部分:绘图结果展示和文本描述输入。
image-container
,用于展示AI生成的图像。
text-description
和
text-description2
,供用户输入正向描述和反向描述,用于指导AI绘图。
generate-button
,用于触发AI绘图过程。
createImageList
函数,动态生成一个图片列表并展示在页面上。
generate-button
按钮的点击事件,收集用户输入的描述和选择的参数,构造一个AI绘图请求,并发送到服务器。
XMLHttpRequest
对象发送POST请求到指定的服务器地址,处理响应并动态更新页面上的图像容器以展示生成的图像。
我们看一下最终效果:
我已经将 IP 地址单独抽离出来,以确保最小化变动量。如果需要重启,只需更新 IP 地址,然后重新部署即可重新访问。
让我们再次观察一下生成图片的效果。点击生成时,后台接口的响应也都是正常的。
质量确实还有提升空间,我仔细检查了一下,发现问题可能出在模型的限制上。例如,对于宽高比不能是正方形的图像,可以稍微宽一点或高一点。这样生成的图像会更具观赏性。但这些问题都是可以通过调试解决的。总的来说,我们的EdgeOne和HAI的梦幻联动已经取得了阶段性的成果,算是告一段落了。
本篇文章源于他人创意的启发与深入思考,我投入了大量时间与精力,致力于EdgeOne与HAI之间的协同调试,克服了众多技术奇葩问题。通过不懈的努力,成功地将这两个强大的平台整合在一起,打造出一个还不错的参考案例。这次探索也是我个人首次涉足边缘函数式产品的实践之旅。我希望通过分享这次的经历和成果,能够激发更多人对这些前沿技术的兴趣和探索。如果你对我的项目感兴趣,或者从中获得了灵感与帮助,不妨点赞支持,也欢迎关注我,一起交流学习,共同进步。
小猫短剧 官方版 4.0.1.6 62.25 MB
下载
湘ICP备2022002427号-10湘公网安备:43070202000427号
© 2013~2019 haote.com 好特网