在当今快速发展的数字时代,安全和速度已成为网络服务的基石。EdgeOne,作为腾讯云提供的边缘安全加速平台,以其全球部署的节点和强大的安全防护功能,为用户提供了稳定而高效的网络体验。而HAI(HyperApplicationInventor),腾讯云推出的高性能应用服务,通过其易用的图形化界面和丰富的模型库,使得AI应用开发变得触手可及。本文将探讨EdgeOne与HAI的结合如何为用户提供一个既安全又高效的AI应用开发环境。

EdgeOne:全球加速与安全防护

  1. DDoS防护:EdgeOne使用Anycast架构在全球建立超过25个清洗中心,能快速检测并清除网络、传输和应用层的DDoS攻击。
  2. WEB攻击防护:EdgeOne拥有广泛的攻击特征库,覆盖主要的安全威胁,能阻止各类Web攻击并防御0day漏洞,通过AI提高检测准确性,减少误报。
  3. 智能CC识别:EdgeOne利用多年经验,通过分析网络流量和多种参数,自动识别并定位攻击源,有效对抗CC攻击。
  4. BOT防护:EdgeOne通过协议、IP和会话特征识别BOT,结合数据分析建立模型,防止恶意爬虫攻击,减少对正常爬虫的误伤。
  5. 攻击溯源:EdgeOne可以捕获并分析异常事件,提取攻击信息,提供监控页面展示攻击详情,帮助用户调整防护策略。
  6. 全天候监测:腾讯安全团队24/7实时监控,主动发现并应对威胁,快速响应安全事件。

不多说了,剩下的内容都已经在官方文档中有详细描述。就我们个人而言,EdgeOne具有以下主要优点,并且我也附上了需要的关键文档地址:

HAI:AI应用的快速开发

HAI提供了可视化交互界面,支持JupyterLab、WebUI等多种算力连接方式,使得用户即使没有深厚的编程背景也能轻松开发AI应用。这种“有手就能开发”的设计理念,极大地降低了AI技术的应用门槛。支持学术加速,通过线路自动择优,能够大幅提升主流学术资源平台的访问、下载速度。同时,HAI预装了StableDiffusion、ChatGLM等热门模型,用户可以在数分钟内构建自己的大语言模型、AI作画等应用环境。

这个话题不需要详细讨论了,我已经整理了开发中需要了解的主要优点和相关文档,以便大家能够快速入手开发:

  1. 快速部署:创建高性能应用服务实例,选择合适的地域、算力方案,并设置实例名称和硬盘空间。官方文档:https://cloud.tencent.com/document/product/1721/101036
  2. 生成API文档:在已部署的Stable Diffusion应用基础上,通过JupyterLab部署API服务。官方文档:https://cloud.tencent.com/document/product/1721/102198
  3. 模型下载地址:https://civitai.com/
  4. 导入外部模型:在腾讯云高性能应用服务HAI上,可以通过三种方式导入外部模型,但是为了花钱少一点,我推荐你选择COS存储。官方文档:https://cloud.tencent.com/document/product/1721/102523#1bb64c7b-0bc8-4a2a-86f0-ad0e71d8f059

联动开发

现在让我们来探讨一下为何可以采用联动开发的方式。我们的目标是以最为经济实惠的价格部署我们的AI绘画应用。

  1. HAI高性能服务器是按照小时收费的,所以我们很多情况下会选择关机,但是一旦重启服务器,外网IP就会变动,导致你的访问路径也就随之变换。但是这一步可以在EdgeOne中使用边缘函数解决。
  2. EdgeOne本身就已经对我们的服务器做了相应的安全防护。
  3. HAI高性能服务器,他是一个Ubuntu20.04环境的虚拟机,也就是说,我们已经有了一个服务器,只不过这个服务器被包装成了绘画AI应用,所以不要浪费掉。用起来

我们接下来看下我们会用到哪些技术:HTML、Javascript、CSS、Nginx、Python、边缘函数中的各个API、Linux基本命令。

准备环境

HAI高性能服务器

关于创建服务器的步骤,我就不再进行演示了,请直接查看官方教程,相关地址也已经提供。我们将重点演示以下内容:下载/上传模型、通过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演示AI绘画

让我们前往WEB UI页面,尝试一下看看是否成功安装了。

在WEB UI页面上,选择您自己的模型文件,并使用一段神奇的提示词。当然,提示词越好,生成的结果也会越好。如果有任何不清楚的地方,您可以参考您下载的模型附带的教程。这样基本上就没有问题了。接下来,让我们再来看看如何让HAI提供站点服务。

Nginx站点配置

依然是同样的步骤,在JupyterLab中的终端中直接使用以下命令操作:

  1. 下载Nginx:使用命令 apt install nginx 进行安装。
  2. 启动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是否能够被正确命中。

启动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时,首先需要确保完成无域名站点的配置,你可以直接参考官方文档进行操作。接着,我们需要创建边缘函数来实现相应的缓存处理。考虑到你没有企业版权限,因此无法使用四层加速,但可以通过边缘函数来达到类似的效果。关于边缘函数中代码的具体使用问题,我建议你仔细阅读官方文档,其中包含了详细的操作指南和示例代码,可以帮助你快速上手。你可以点击以下链接查看官方文档: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));
});

这段代码的主要功能是用于处理网络请求并管理资源的缓存策略,确保快速响应用户请求的同时,减少不必要的网络流量。

  1. fetchJquery 函数:

    • 该函数用于处理当资源未被缓存或缓存过期时的情况。
    • 使用fetch函数发起网络请求,获取资源的最新响应。
    • 在响应头中添加Cache-Control,设置资源在服务端缓存中的最长有效时间为600秒。
    • 使用cache.put方法将获取的响应克隆一份并存入缓存中,以便后续请求可以直接从缓存中获取。
    • 设置响应头x-edgefunctions-cachemiss,表示这是一个未命中缓存的请求。
    • 返回原始响应给请求者。
  2. handleEvent 函数:
    • 该函数用于检查请求的URL是否指向一个图片资源(通过文件扩展名判断)。
    • 如果请求的不是图片资源,将返回一个错误响应。
    • 如果是图片资源,尝试从缓存中获取请求的资源。
    • 如果缓存中存在资源,则设置响应头x-edgefunctions-cachehit,表示这是一个命中缓存的请求,并返回缓存中的资源。
    • 如果缓存中不存在资源或发生异常(如缓存过期),则删除缓存并重新调用fetchJquery函数获取资源。

在访问图片资源时,需要特别注意的是,我采用了路径后面的 IP 参数进行访问。这是因为 HAI 每次重启后外网 IP 都会发生变化,如果每次都要修改每个边缘函数的话,会相当繁琐。为了避免这种情况,我选择通过参数传递的方式来获取图片资源。这样一来,获取图片资源的边缘函数就不需要再进行任何修改了。另外,你还需要对匹配触发规则进行配置,比如我设置的规则是包含 "/images" 的路径才会触发相应的操作。

在浏览器中输入默认域名,并随意添加 "/images/*.png" 即可访问相应图片,前提是该图片存储于我们的服务器上。现在让我们来观察一下效果。值得注意的是,这种方式的命中率并不是很高,所以在刚部署完边缘函数后,需要多刷新几次才能看到效果。

静态网页

这个边缘函数专门用于处理用户交互。

const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI绘图</title>
<style>
body {
font-family: Arial, sans-serif;
} .container {
display: flex;
justify-content: center;
} .box {
margin: 20px;
border: none; /* 移除框的边框 */
padding: 10px;
background-color: #f5f5f5; /* 设置框的背景颜色 */
border-radius: 10px; /* 添加圆角 */
display: flex; /* 使用flex布局 */
flex-direction: column; /* 垂直布局 */
align-items: center; /* 居中对齐 */
text-align: center; /* 文字居中对齐 */
}
.box:nth-child(2) {
align-self: start; /* 右边的box顶部对齐 */
} .box-title {
margin-bottom: 10px;
margin-right: 500px;
border-bottom: 1px solid grey; /* 添加标题底部的分隔线 */
padding-bottom: 5px; /* 添加一些底部间距以增强视觉效果 */
} #image-container {
width: 512px;
height: 512px;
background-color: #eee;
margin: auto; /* 在父元素中水平居中 */
} #text-description {
width: 300px;
height: 100px;
margin-bottom: 10px;
border: 1px solid grey; /* 添加外边框 */
padding: 5px;
resize: none; /* 禁止调整大小 */
font-size: 14px;
outline: none; /* 移除输入框默认的外边框 */
border-radius: 0; /* 移除圆角 */
} #text-description2 {
width: 300px;
height: 100px;
margin-bottom: 10px;
border: 1px solid grey; /* 添加外边框 */
padding: 5px;
resize: none; /* 禁止调整大小 */
font-size: 14px;
outline: none; /* 移除输入框默认的外边框 */
border-radius: 0; /* 移除圆角 */
} #dropdown {
padding: 10px 20px; /* 增大按钮的内边距 */
cursor: pointer;
margin-bottom: 10px;
border: 1px solid grey; /* 添加外边框 */
width: 100%; /* 将宽度设置为100%以与容器对齐 */
align-self: flex-start; /* 按钮左对齐 */
} #dropdown2 {
padding: 10px 20px; /* 增大按钮的内边距 */
cursor: pointer;
margin-bottom: 10px;
border: 1px solid grey; /* 添加外边框 */
width: 100%; /* 将宽度设置为100%以与容器对齐 */
align-self: flex-start; /* 按钮左对齐 */
} #acckey {
padding: 10px 20px; /* 增大按钮的内边距 */
cursor: pointer;
margin-bottom: 10px;
border: 1px solid grey; /* 添加外边框 */
width: 100%; /* 将宽度设置为100%以与容器对齐 */
align-self: stretch; /* 按钮左对齐 */
} #input-container {
flex-grow: 1;
display: flex;
flex-direction: column; /* 垂直布局 */
align-items: center; /* 居中对齐 */
} #text-input {
width: 300px;
height: 30px;
margin-bottom: 10px;
} #generate-button {
padding: 10px 20px; /* 增大按钮的内边距 */
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
width: 100%; /* 将宽度设置为100%以与容器对齐 */
align-self: flex-start; /* 按钮左对齐 */
} @media (max-width: 600px) {
.container {
flex-wrap: wrap; /* 在屏幕宽度不足时换行显示 */
} .box {
width: 100%; /* 让框占满一行 */
margin-bottom: 20px; /* 添加底边距 */
}
}
.image-list {
display: flex; /* 使用flex布局 */
flex-wrap: wrap; /* 允许列表换行 */
justify-content: space-around; /* 间隔均匀分布 */
align-items: center; /* 垂直居中对齐 */
} .image-list img {
max-width: 18%; /* 图片最大宽度占比,根据需要调整 */
margin: 5px; /* 图片之间的间隔 */
object-fit: contain; /* 确保图片等比例缩放 */
}
</style>
</head>
<body>
<div class="container">
<div class="box">
<h2 class="box-title">绘图结果</h2>
<div id="image-container">
</div>
</div>
<div class="box">
<h2 class="box-title">文本描述</h2>
<div id="input-container">
<textarea id="text-description" title="文本描述" placeholder="文本描述。
算法将根据输入的文本智能生成与之相关的图像。建议详细描述画面主体、细节、场景等,文本描述越丰富,生成效果越精美。
不能为空,推荐使用中文。最多传512个字符。"></textarea>
<textarea id="text-description2" title="反向文本描述" placeholder="反向文本描述。
用于一定程度上从反面引导模型生成的走向,减少生成结果中出现描述内容的可能,但不能完全杜绝。
推荐使用中文。最多传512个字符。"></textarea>
<select id="dropdown" title="分辨率">
<option value="768:1024">分辨率(默认768:1024)</option>
<option value="768:768">768:768</option>
<option value="1024:768">1024:768</option>
</select>
<select id="dropdown2" title="绘画风格">
<option value="201">绘画风格(默认日系动漫风格)</option>
</select>
<div style="display: flex; justify-content: flex-start; width: 100%;">
<input id="acckey" type="password" placeholder="访问密钥" style="width: 100%;">
</div>
<button id="generate-button">生成</button>
</div>
</div> </div>
<!-- 图片列表容器 -->
<div class="image-list" id="image-list">
<!-- 图片将被动态插入到这里 -->
</div>
<script>
// 页面加载完成后执行的函数
window.onload = function() {
// 假设您已经有了一个函数来发起请求和处理响应
// 这里我们直接调用这个函数
createImageList();
};
var ip = "http://101.43.51.133";
document.getElementById("generate-button").addEventListener("click", function() {
var Ai_Image_Prompt = document.getElementById("text-description").value;
var Ai_Image_NegativePrompt = document.getElementById("text-description2").value;
var Ai_Image_Size = document.getElementById("dropdown").value;
var Ai_Image_Styles = document.getElementById("dropdown2").value;
var Ai_Image_AccKey = document.getElementById("acckey").value; var data = {
"denoising_strength": 0,
"override_settings": {
"sd_model_checkpoint" :"animagineXLV31_v30.safetensors [1449e5b0b9]"
},
"prompt": Ai_Image_Prompt,
"negative_prompt": Ai_Image_NegativePrompt,
"seed": 0,
"batch_size": 1,
"n_iter": 1,
"num_inference_steps": 28,
"guidance_scale": 7,
"sdxl_style": "(None)",
"quality_tags": "(None)",
"width": 512,
"height": 512,
"sampler": "Euler a"
}; var xhr = new XMLHttpRequest();
xhr.open("POST", ip + "/sdapi/v1/txt2img", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function() {
if(xhr.readyState === 4){
if (xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
var imageContainer = document.getElementById("image-container");
// 创建一个新的img元素
var imgElement = document.createElement("img");
imageContainer.style.backgroundSize = "contain";
// 设置img元素的src属性为base64编码的图片数据
imgElement.src = 'data:image/png;base64,'+response.images[0];
// 设置img元素的alt属性
imgElement.alt = "动态生成的图片"; // 将img元素添加到imageContainer中
imageContainer.appendChild(imgElement);
// 由于img元素是异步加载的,我们需要等待图片加载完成后再进行操作
}else{
alert("请求错误:" + xhr.status);
}
}
};
xhr.onerror = function() {
// 处理网络错误
alert("网络错误");
};
xhr.send(JSON.stringify(data));
});
// 处理图片列表的函数
function createImageList() {
var imageList = document.getElementById("image-list");
imageList.innerHTML = ""; // 清空当前列表
// 使用for循环生成图片元素
for (var i = 1; i <= 5; i++) {
// 创建新的img元素
var img = document.createElement("img");
// 设置图片的src属性为对应的图片文件路径
// 假设所有图片都存放在同一个目录下
img.src = "http://ai-zone-2vjn2f1z4giq-1302107156.eo-edgefunctions.com/images/" + i + ".png?ip="+ip;
img.alt = "Image " + i; // 设置alt属性
img.style.width = '100%'; // 设置图片宽度为100% // 将img元素添加到图片列表容器中
imageList.appendChild(img);
}
}
</script> </body>
</html> `;
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代码。主要功能和组成部分如下:

  1. HTML结构

    • 页面包含一个容器container,用于布局两个主要部分:绘图结果展示和文本描述输入。
    • 绘图结果部分包含一个标题和一个图像容器image-container,用于展示AI生成的图像。
    • 文本描述部分包含两个文本区域text-descriptiontext-description2,供用户输入正向描述和反向描述,用于指导AI绘图。
    • 一个按钮generate-button,用于触发AI绘图过程。
  2. JavaScript逻辑
    • 页面加载完成后,调用createImageList函数,动态生成一个图片列表并展示在页面上。
    • 监听generate-button按钮的点击事件,收集用户输入的描述和选择的参数,构造一个AI绘图请求,并发送到服务器。
    • 使用XMLHttpRequest对象发送POST请求到指定的服务器地址,处理响应并动态更新页面上的图像容器以展示生成的图像。

我们看一下最终效果:

我已经将 IP 地址单独抽离出来,以确保最小化变动量。如果需要重启,只需更新 IP 地址,然后重新部署即可重新访问。

让我们再次观察一下生成图片的效果。点击生成时,后台接口的响应也都是正常的。

质量确实还有提升空间,我仔细检查了一下,发现问题可能出在模型的限制上。例如,对于宽高比不能是正方形的图像,可以稍微宽一点或高一点。这样生成的图像会更具观赏性。但这些问题都是可以通过调试解决的。总的来说,我们的EdgeOne和HAI的梦幻联动已经取得了阶段性的成果,算是告一段落了。

总结

本篇文章源于他人创意的启发与深入思考,我投入了大量时间与精力,致力于EdgeOne与HAI之间的协同调试,克服了众多技术奇葩问题。通过不懈的努力,成功地将这两个强大的平台整合在一起,打造出一个还不错的参考案例。这次探索也是我个人首次涉足边缘函数式产品的实践之旅。我希望通过分享这次的经历和成果,能够激发更多人对这些前沿技术的兴趣和探索。如果你对我的项目感兴趣,或者从中获得了灵感与帮助,不妨点赞支持,也欢迎关注我,一起交流学习,共同进步。

实践指南:EdgeOne与HAI的梦幻联动的更多相关文章

  1. 业务驱动的全景监控体系在阿里的应用 | 阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...

  2. Celery的实践指南

    http://www.cnblogs.com/ToDoToTry/p/5453149.html Celery的实践指南   Celery的实践指南 celery原理: celery实际上是实现了一个典 ...

  3. [CoreOS 转载] CoreOS实践指南(七):Docker容器管理服务

    转载:http://www.csdn.net/article/2015-02-11/2823925 摘要:当Docker还名不见经传的时候,CoreOS创始人Alex就预见了这个项目的价值,并将其做为 ...

  4. [CoreOS 转载] CoreOS实践指南(五):分布式数据存储Etcd(上)

    转载:http://www.csdn.net/article/2015-01-22/2823659 摘要:在“漫步云端:CoreOS实践指南”系列的前几篇,分别介绍了如何架设CoreOS集群,系统服务 ...

  5. [CoreOS 转载] CoreOS实践指南(四):集群的指挥所Fleet

    转载:http://www.csdn.net/article/2015-01-14/2823554/2 摘要:CoreOS是采用了高度精简的系统内核及外围定制的操作系统.ThoughtWorks的软件 ...

  6. OpenGL ES应用开发实践指南:iOS卷

    <OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...

  7. 《赢在用户:Web人物角色创建和应用实践指南》阅读总结

           本书针对创建人物角色的每一个步骤,包括进行定性.定量的用户研究,生成人物角色分类,使人物角色真实可信等进行了十分详细的介绍.而且,在人物角色如何指导总体商业策略.确定信息架构.内容和设计 ...

  8. lua游戏开发实践指南学习笔记1

    本文是依据lua游戏开发实践指南做的一些学习笔记,仅用于继续自己学习的一些知识. Lua基础 1.  语言定义: 在lua语言中,标识符有非常大的灵活性(变量和函数名),只是用户不呢个以数字作为起始符 ...

  9. 《App架构实践指南》

    推荐书籍 <App 架构实践指南>

  10. Python 最佳实践指南 2018 学习笔记

    基础信息 版本 Python 2.7 Python 3.x Python2.7 版本在 2020 年后不再提供支持,建议新手使用 3.x 版本进行学习 实现 CPython:Python的标准实现: ...

随机推荐

  1. 【Azure 应用服务】能否通过 Authentication 模块配置 Azure AD 保护 API 应用?

    问题描述 在App Service Authentication 中配置 Azure AD 注册的应用信息后,根据官方文档,可以让前端应用实现用户 AAD 登录,然后通过前端应用获取的Token,来访 ...

  2. 【Azure 应用服务】App Service For Linux 中安装paping, 用于验证从App Service向外请求的网络连通性

    问题描述 App Service For Linux 中安装paping的操作步骤 解决步骤 1) 登录App Service的Kudu站点,点击Bash 2)使用命令下载paping压缩文件:#wg ...

  3. idea导入spring源码运行缺失cglib和objenesis的jar包的办法【亲测有效】

    idea导入spring源码运行缺失cglib和objenesis的jar包的办法[亲测有效] 亲测有效,网上说的大多废话 上图,操作如下,运行gradle

  4. Kubernetes: kube-controller-manager 源码分析

    0. 前言 在 Kubernetes 架构中,controller manager 是一个永不休止的控制回路组件,其负责控制集群资源的状态.通过监控 kube-apiserver 的资源状态,比较当前 ...

  5. C#版开源免费的Bouncy Castle密码库

    前言 今天大姚给大家分享一款C#版开源.免费的Bouncy Castle密码库:BouncyCastle. 项目介绍 BouncyCastle是一款C#版开源.免费的Bouncy Castle密码库, ...

  6. 创建 nest-websocket 服务 用于mock单点登录开发

    需求 有个单点登录的任务,但是都是现场的服务 api 和 websocket 都在现在 开发本机mock服务 本地搭建环境先模拟一下 资料 NestJS WebSocket 开始使用 https:// ...

  7. gitee 流水线 定时触发 不能用,不能白嫖了

    gitee 流水线 定时触发 不能用,不能白嫖了 白研究半天了,只好回去拿centos服务器 搞定时任务了

  8. 关于编写GUI程序我自己的一些理解

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文发布于 2014-10-12 14:51:31 ...

  9. uniapp中引入Leaflet

    1. 引言 uniapp中自带有map组件,并且自带的map组件有常见的显示地图.绘制点线面的功能 但是,它存在以下问题: 收费,自带的map组件使用的是高德.腾讯的地图,无论使用什么样的功能,即使只 ...

  10. PDF的分割与合并

    1.进行PDF切割 python代码如下: # 20220521 # 1.选择要分割的文件 # 2.选择要保存的位置,分割为多个文件时,可自动用页码命名 # 3.输入要分割的页码,可以是一个范围1-2 ...