久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

如何用Serverless優雅地實現圖片藝術化應用

164次閱讀
沒有評論

共計 11955 個字符,預計需要花費 30 分鐘才能閱讀完成。

這期內容當中丸趣 TV 小編將會給大家帶來有關如何用 Serverless 優雅地實現圖片藝術化應用,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

如何從零開始搭建一個基于騰訊云 Serverless 的圖片藝術化應用。

項目看點概覽:

前端 react(Next.js)、后端 node(koa2)

全面使用 ts 進行開發,極致開發體驗(后端運行時 ts 的方案,雖然性能差點,不過勝在無需編譯,適合寫 demo)

突破云函數代碼 500mb 限制(提供解決方案)

TensorFlow2 + Serverless 擴展想象力邊際

高性能,輕松應對萬級高并發,實現高可用(自信的表情,反正是平臺干的活)

秒級部署,十秒部署上線

開發周期短(本文就能帶你完成開發)

如何用 Serverless 優雅地實現圖片藝術化應用

本項目部署借助了 Serverless component,因此當前開發環境需先全局安裝 Serverless 命令行工具

npm install -g serverless

需求與架構

本應用的整體需求很簡單:圖片上傳與展示。

模塊概覽

如何用 Serverless 優雅地實現圖片藝術化應用

上傳圖片

如何用 Serverless 優雅地實現圖片藝術化應用

瀏覽圖片

如何用 Serverless 優雅地實現圖片藝術化應用

用對象存儲提供存儲服務

在開發之前,我們先創建一個 oss 用于提供圖片存儲(可以使用你已有的對象存儲)

mkdir oss

在新建的 oss 目錄下添加 serverless.yml

component: cos
name: xart-oss
app: xart
stage: dev
inputs:
 src:
 src: ./
 exclude:
 - .env #  防止密鑰被上傳
 bucket: ${name} #  存儲桶名稱,如若不添加  AppId  后綴,則系統會自動添加,后綴為大寫(xart-oss- 你的 appid) website: false
 targetDir: /
 protocol: https
 region: ap-guangzhou #  配置區域,盡量配置在和服務同區域內,速度更快
 acl:
 permissions: public-read #  讀寫配置為,私有寫,共有讀

執行 sls deploy 幾秒后,你應該就能看到如下提示,表示新建對象存儲成功。

如何用 Serverless 優雅地實現圖片藝術化應用

這里,我們看到 url https://art-oss- appid .cos.ap-guangzhou.myqcloud.com,可以發現默認的命名規則是 https:// 名字 -appid .cos. 地域 .myqcloud.com

簡單記錄一下,在后面服務中會用到,忘記了也不要緊,看看 .env 內 TENCENT_APP_ID 字段(部署后會自動生成 .env)

實現后端服務

新建一個目錄并初始化

mkdir art-api   cd art-api   npm init

安裝依賴(期望獲取 ts 類型提示,請自行安裝 @types)

npm i koa @koa/router @koa/cors koa-body typescript ts-node cos-nodejs-sdk-v5 axios dotenv

配置 tsconfig.json

{
  compilerOptions : {
  target :  es2018 ,
  module :  commonjs ,
  lib : [es2018 ,  esnext.asynciterable],
  experimentalDecorators : true,
  emitDecoratorMetadata : true,
  esModuleInterop : true
 }
}

入口文件 sls.js

require(ts-node).register({ transpileOnly: true }); //  載入  ts  運行時環境,配置忽略類型錯誤
module.exports = require(./app.ts  //  直接引入業務邏輯,下面我會和你一起實現

補充兩個實用知識點:

node -r

在入口文件中引入 require(ts-node).register({transpileOnly: true}) 實際等同于 node -r ts-node/register/transpile-only

所以 node -r 就是在執行之前載入一些特定模塊,利用這個能力,能快速實現對一些功能的支持

比如 node -r esm main.js 通過 esm 模塊就能在無需 babel、webpack 的情況下快速 import 與 export 進行模塊加載與導出

ts 加載路徑

如果不希望用 ../../../../../ 來加載模塊,那么

在 tsconfig.json 中配置 baseUrl: .

ts-node -r tsconfig-paths/register main.ts 或 require(tsconfig-paths).register()

import utils from src/utils 即可愉快地從項目根路徑加載模塊

下面來實現具體邏輯:

app.ts

require(dotenv).config(); //  載入  .env  環境變量,可以將一些密鑰配置在環境變量中,并通過  .gitignore  阻止提交
import Koa from  koa 
import Router from  @koa/router 
import koaBody from  koa-body 
import cors from  @koa/cors 
import util from  util 
import COS from  cos-nodejs-sdk-v5 
import axios from  axios 
const app = new Koa();
const router = new Router();
var cos = new COS({
 SecretId: process.env.SecretId //  你的 id,
 SecretKey: process.env.SecretKey //  你的 key,
const cosInfo = {
 Bucket:  xart-oss- 你的 appid , //  部署 oss 后獲取
 Region:  ap-guangzhou ,
const putObjectSync = util.promisify(cos.putObject.bind(cos));
const getBucketSync = util.promisify(cos.getBucket.bind(cos));
router.get(/hello , async (ctx) =  {
 ctx.body =  hello world! 
router.get(/api/images , async (ctx) =  {
 const files = await getBucketSync({
 ...cosInfo,
 Prefix:  result ,
 });
 const cosURL = `https://${cosInfo.Bucket}.cos.${cosInfo.Region}.myqcloud.com`;
 ctx.body = files.Contents.map((it) =  { const [timestamp, size] = it.Key.split(.jpg)[0].split( __ 
 const [width, height] = size.split( _ 
 return { url: `${cosURL}/${it.Key}`,
 width,
 height,
 timestamp: Number(timestamp),
 name: it.Key,
 };
 })
 .filter(Boolean)
 .sort((a, b) =  b.timestamp - a.timestamp);
router.post(/api/images/upload , async (ctx) =  { const { imgBase64, style } = JSON.parse(ctx.request.body)
 const buf = Buffer.from(imgBase64.replace(/^data:image\/\w+;base64,/, ),  base64 )
 //  調用預先提供 tensorflow 服務加工圖片,后面替換成你自己的服務
 const { data } = await axios.post( https://service-edtflvxk-1254074572.gz.apigw.tencentcs.com/release/ , { imgBase64: buf.toString( base64),
 style
 })
 if (data.success) {
 const afterImg = await putObjectSync({
 ...cosInfo,
 Key: `result/${Date.now()}__400_200.jpg`,
 Body: Buffer.from(data.data,  base64),
 });
 ctx.body = {
 success: true,
 data:  https://  + afterImg.Location
 }
 }
app.use(cors());
app.use(koaBody({
 formLimit:  10mb ,
 jsonLimit:  10mb ,
 textLimit:  10mb 
app.use(router.routes()).use(router.allowedMethods());
const port = 8080;
app.listen(port, () =  { console.log( listen in http://localhost:%s , port);
module.exports = app;

在代碼里可以看到,在圖片上傳采用了 base64 的形式。這里需要注意,通過 api 網關觸發 scf 的時候,網關無法透傳 binary,具體上傳規則可以參閱官方文檔:

如何用 Serverless 優雅地實現圖片藝術化應用

再補充一個知識點:實際我們訪問的是 api 網關,然后觸發云函數,來獲得請求返回結果,所以 debug 時需要關注全鏈路

如何用 Serverless 優雅地實現圖片藝術化應用

回歸正題,接著配置環境變量 .env

NODE_ENV=development
#  配置  oss  上傳所需密鑰,需要自行配置,配好了也別告訴我:)#  密鑰查看地址:https://console.cloud.tencent.com/cam/capi
SecretId=xxxx
SecretKey=xxxx

以上,server 部分就開發完成了,我們可以通過在本地執行 node sls.js 來驗證一下,應該可以看到服務啟動的提示了。

listen in http://localhost:8080

來簡單配置一下 serverless.yml,把服務部署到線上,后面再進一步使用 layer 進行優化

component: koa #  這里填寫對應的  component
app: art
name: art-api
stage: dev
inputs:
 src:
 src: ./
 exclude:
 - .env
 functionName: ${name}
 region: ap-guangzhou
 runtime: Nodejs10.15
 functionConf:
 timeout: 60 #  超時時間配置的稍微久一點
 environment:
 variables: #  配置環境變量,同時也可以直接在 scf 控制臺配置
 NODE_ENV: production
 apigatewayConf:
 enableCORS: true
 protocols:
 - https
 - http
 environment: release

之后執行部署命令 sls deploy

等待數十秒,應該會得到如下的輸出結果(如果是第一次執行,需要平臺方授權)

如何用 Serverless 優雅地實現圖片藝術化應用

其中 url 就是當前服務部署在線上的地址,我們可以試著訪問一下看看,是否看到了預設的 hello world。

到這里,server 基本上已經部署完成了。如果代碼有改動,那就修改后再次執行 sls deploy。官方為代碼小于 10M 的項目提供了在線編輯的能力。

但是,隨著項目復雜度的增加,deploy 上傳會變慢。所以,讓我們再優化一下。

新建 layer 目錄

mkdir layer

在 layer 目錄下添加 serverless.yml

component: layer
app: art
name: art-api-layer
stage: dev
inputs:
 region: ap-guangzhou
 name: ${name}
 src: ../node_modules #  將  node_modules  打包上傳
 runtimes:
 - Nodejs10.15 #  注意配置為相同環境

回到項目根目錄,調整一下根目錄的 serverless.yml

component: koa #  這里填寫對應的  component
app: art
name: art-api
stage: dev
inputs:
 src:
 src: ./
 exclude:
 - .env
 - node_modules/** # deploy  時排除  node_modules
 functionName: ${name}
 region: ap-guangzhou
 runtime: Nodejs10.15
 functionConf:
 timeout: 60 #  超時時間配置的稍微久一點
 environment:
 variables: #  配置環境變量,同時也可以直接在  scf  控制臺配置
 NODE_ENV: production
 apigatewayConf:
 enableCORS: true
 protocols:
 - https
 - http
 environment: release
 layers:
 - name: ${output:${stage}:${app}:${name}-layer.name} #  配置對應的  layer
 version: ${output:${stage}:${app}:${name}-layer.version} #  配置對應的  layer  版本

接著執行命令 sls deploy –target=./layer 部署 layer,然后這次部署看看速度應該已經在 10s 左右了

sls deploy

關于 layer 和云函數,補充兩個知識點:

layer 的加載與訪問

layer 會在函數運行時,將內容解壓到 /opt 目錄下,如果存在多個 layer,那么會按時間循序進行解壓。如果需要訪問 layer 內的文件,可以直接通過 /opt/xxx 訪問。如果是訪問 node_module 則可以直接 import,因為 scf 的 NODE_PATH 環境變量默認已包含 /opt/node_modules 路徑。

配額

云函數 scf 針對每個用戶帳號,均有一定的配額限制:

如何用 Serverless 優雅地實現圖片藝術化應用

其中需要重點關注的就是單個函數代碼體積 500mb 的上限。在實際操作中,云函數雖然提供了 500mb。但也存在著一個 deploy 解壓上限。

關于繞過配額問題:

如果超的不多,那么使用 npm install –production 就能解決問題

如果超的太多,那就通過掛載 cfs 文件系統來進行規避,我會在下面部署 tensorflow 算法模型服務章節里面,展開聊聊如何把 800mb tensorflow 的包 + 模型部署到 SCF 上

實現前端 SSR 服務

下面將使用 next.js 來構建一個前端 SSR 服務。

新建目錄并初始化項目:

mkdir art-front   cd art-front   npm init

安裝依賴:

npm install next react react-dom typescript @types/node swr antd @ant-design/icons dayjs

增加 ts 支持(next.js 跑起來會自動配置):

touch tsconfig.json

打開 package.json 文件并添加 scripts 配置段:

scripts : {
  dev :  next ,
  build :  next build ,
  start :  next start 
}

編寫前端業務邏輯(文中僅展示主要邏輯,源碼在 GitHub 獲取)

pages/_app.tsx

import React from  react 
import  antd/dist/antd.css 
import { SWRConfig } from  swr 
export default function MyApp({ Component, pageProps }) {
 return (
  SWRConfig
 value={{
 refreshInterval: 2000,
 fetcher: (...args) =  fetch(args[0], args[1]).then((res) =  res.json()),
 }}
  
  Component {...pageProps} / 
  /SWRConfig 
 );
}

pages/index.tsx 完整代碼

import React from  react 
import { Card, Upload, message, Radio, Spin, Divider } from  antd 
import { InboxOutlined } from  @ant-design/icons 
import dayjs from  dayjs 
import useSWR from  swr 
let origin =  http://localhost:8080 
if (process.env.NODE_ENV ===  production) {
 //  使用你自己的部署的 art-api 服務地址
 origin =  https://service-5yyo7qco-1254074572.gz.apigw.tencentcs.com/release  
//  略...
export default function Index() { const { data } = useSWR(`${origin}/api/images`);
 const [img, setImg] = React.useState( const [loading, setLoading] = React.useState(false);
 const uploadImg = React.useCallback((file, style) =  { const reader = new FileReader();
 reader.readAsDataURL(file);
 reader.onload = async () =  {
 const res = await fetch( `${origin}/api/images/upload`, {
 method:  POST ,
 body: JSON.stringify({
 imgBase64: reader.result,
 style
 }),
 mode:  cors 
 }
 ).then((res) =  res.json());
 if (res.success) { setImg(res.data);
 } else { message.error(res.message);
 }
 setLoading(false);
 }
 }, []);
 const [artStyle, setStyle] = React.useState(STYLE_MODE.cube);
 return (
  Dragger
  >

使用 npm run dev 把前端跑起來看看,看到以下提示就是成功了

ready - started server on http://localhost:3000

接著配置 serverless.yml(如果有需要可以參考前文,使用 layer 優化部署體驗)

component: nextjs
app: art
name: art-front
stage: dev
inputs:
 src:
 dist: ./
 hook: npm run build
 exclude:
 - .env
 region: ap-guangzhou
 functionName: ${name}
 runtime: Nodejs12.16
 staticConf:
 cosConf:
 bucket: art-front #  將前端靜態資源部署到 oss,減少 scf 的調用頻次
 apigatewayConf:
 enableCORS: true
 protocols:
 - https
 - http
 environment: release
 # customDomains: #  如果需要,可以自己配置自定義域名
 # - domain: xxxxx 
 # certificateId: xxxxx #  證書  ID
 # #  這里將  API  網關的  release  環境映射到根路徑
 # isDefaultMapping: false
 # pathMappingSet:
 # - path: /
 # environment: release
 # protocols:
 # - https
 functionConf:
 timeout: 60
 memorySize: 128
 environment:
 variables:
 apiUrl: ${output:${stage}:${app}:art-api.apigw.url} #  此處可以將 api 通過環境變量注入

由于我們額外配置了 oss,所以需要額外配置一下 next.config.js

const isProd = process.env.NODE_ENV ===  production 
const STATIC_URL =
  https://art-front- 你的 appid .cos.ap-guangzhou.myqcloud.com/ 
module.exports = { assetPrefix: isProd ? STATIC_URL :  ,};

提供 Tensorflow 2.x 算法模型服務

在上面的例子中,我們使用的 Tensorflow,暫時還是調用我預先提供的接口。

接著讓我們會把它替換成我們自己的服務。

基礎信息

tensoflow2.3

model

scf 在 python 環境下,默認提供了 tensorflow1.9 依賴包,使用 python 可以用較低的成本直接上手。

問題所在

但如果你想使用 2.x 版本,或不熟悉 python,想用 node 來跑 tensorflow,那么就會遇到代碼包大小的限制的問題。

Python 中 Tensorflow 2.3 包體積 800mb 左右

node 中 tfjs-node2.3 安裝后,同樣會超過 400mb(tfjs core 版本,非常小,不過速度太慢)

怎么解決 —— 文件存儲服務!

先看看 CFS 文檔的介紹

如何用 Serverless 優雅地實現圖片藝術化應用

掛載后,就可以正常使用了,騰訊云提供了一個簡單例子。

var fs = requiret( fs 
exports.main_handler = async (event, context) =  { await fs.promises.writeFile( /mnt/myfolder/filel.txt , JSON.stringify(event)); 
 return event;
};

既然能正常讀寫,那么就能夠正常的載入 npm 包,可以看到我直接加載了 /mnt 目錄下的包,同時 model 也放在 /mnt 下

 tf = require( /mnt/nodelib/node_modules/@tensorflow/tfjs-node 
 jpeg = require( /mnt/nodelib/node_modules/jpeg-js 
 images = require( /mnt/nodelib/node_modules/images 
 loadModel = async () =  tf.node.loadSavedModel( /mnt/model

如果你使用 Python,那么可能會遇到一個問題,那就是 scf 默認環境下提供了 tensorflow 1.9 的依賴包,所以需要使用 insert,提高 /mnt 目錄下包的優先級

sys.path.insert(0,  ./mnt/xxx)

上面提供了解決方案,那么具體開發中可能會感覺很麻煩,因為 csf 必須和 scf 配置在同一個子網內,無法掛載到本地進行操作。

所以,在實際部署過程中,可以在對應網絡下,購置一臺按需計費的 ecs 云服務器實例。然后將硬盤掛載后,直接進行操作,最后在云函數成功部署后,銷毀實例:)

sudo yum install nfs-utils
mkdir  待掛載目標目錄 
sudo mount -t nfs -o vers=4.0,noresvport  掛載點 IP :/  待掛載目錄

具體業務代碼如下:

const fs = require( fs 
let tf, jpeg, loadModel, images;
if (process.env.NODE_ENV !==  production) {
 tf = require( @tensorflow/tfjs-node 
 jpeg = require( jpeg-js 
 images = require( images 
 loadModel = async () =  tf.node.loadSavedModel( ./model} else { tf = require( /mnt/nodelib/node_modules/@tensorflow/tfjs-node 
 jpeg = require( /mnt/nodelib/node_modules/jpeg-js 
 images = require( /mnt/nodelib/node_modules/images 
 loadModel = async () =  tf.node.loadSavedModel( /mnt/model
exports.main_handler = async (event) =  { const { imgBase64, style } = JSON.parse(event.body)
 if (!imgBase64 || !style) { return { success: false, message:  需要提供完整的參數 imgBase64、style  };
 }
 time = Date.now();
 console.log( 解析圖片 -- 
 const styleImg = tf.node.decodeJpeg(fs.readFileSync(`./imgs/style_${style}.jpeg`));
 const contentImg = tf.node.decodeJpeg( images(Buffer.from(imgBase64,  base64)).size(400).encode(jpg , { operation: 50 }) //  壓縮圖片尺寸
 );
 const a = styleImg.toFloat().div(tf.scalar(255)).expandDims();
 const b = contentImg.toFloat().div(tf.scalar(255)).expandDims();
 console.log(-- 解析圖片  %s ms , Date.now() - time);

 console.log( 載入模型 --  const model = await loadModel();  console.log(-- 載入模型  %s ms , Date.now() - time);
 console.log( 執行模型 --  const stylized = tf.tidy(() =  { const x = model.predict([b, a])[0];  return x.squeeze();  });  console.log(-- 執行模型  %s ms , Date.now() - time);  time = Date.now();  const imgData = await tf.browser.toPixels(stylized);  var rawImageData = { data: Buffer.from(imgData),  width: stylized.shape[1],  height: stylized.shape[0],  };  const result = images(jpeg.encode(rawImageData, 50).data)  .draw( images( ./imgs/logo.png),  Math.random() * rawImageData.width * 0.9,  Math.random() * rawImageData.height * 0.9  )  .encode(jpg , { operation: 50 });  return { success: true, data: result.toString( base64) }; };

上述就是丸趣 TV 小編為大家分享的如何用 Serverless 優雅地實現圖片藝術化應用了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注丸趣 TV 行業資訊頻道。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計11955字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 昭通市| 厦门市| 达州市| 邛崃市| 石景山区| 梁山县| 临沭县| 延吉市| 安吉县| 肥城市| 进贤县| 江华| 金川县| 金乡县| 深水埗区| 彭州市| 旬邑县| 望江县| 南江县| 八宿县| 阿克| 秭归县| 苍溪县| 高尔夫| 商水县| 青海省| 永兴县| 雷波县| 青河县| 枣强县| 托克逊县| 尖扎县| 岑巩县| 四川省| 高唐县| 沧州市| 西昌市| 阳东县| 辽中县| 米林县| 黑河市|