Turn Your Photo into a Comic Avatar with Serverless AI – Step‑by‑Step Guide

This tutorial shows how to use the AnimeGAN v2 model to convert personal photos into comic‑style avatars, expose the AI service via a Python Bottle API on a Serverless platform, configure deployment with Serverless Devs, and integrate the backend into a WeChat mini‑program for end‑users.

Alibaba Cloud Native
Alibaba Cloud Native
Alibaba Cloud Native
Turn Your Photo into a Comic Avatar with Serverless AI – Step‑by‑Step Guide

Background

The author wanted a cartoon‑style avatar but lacked the tools to create one manually, so they decided to leverage an AI model (AnimeGAN v2) and deploy it using a Serverless architecture for broader accessibility.

Backend Service

The backend uses the popular AnimeGAN v2 filter library to transform images. A Python Bottle application loads several pre‑trained models from a local directory and provides an HTTP endpoint /images/comic_style that accepts a POST request with a base64‑encoded image and a style identifier.

from PIL import Image
import io
import torch
import base64
import bottle
import random
import json

cacheDir = '/tmp/'
modelDir = './model/bryandlee_animegan2-pytorch_main'
getModel = lambda modelName: torch.hub.load(modelDir, "generator", pretrained=modelName, source='local')
models = {
    'celeba_distill': getModel('celeba_distill'),
    'face_paint_512_v1': getModel('face_paint_512_v1'),
    'face_paint_512_v2': getModel('face_paint_512_v2'),
    'paprika': getModel('paprika')
}
randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num))
face2paint = torch.hub.load(modelDir, "face2paint", size=512, source='local')

@bottle.route('/images/comic_style', method='POST')
def getComicStyle():
    result = {}
    try:
        postData = json.loads(bottle.request.body.read().decode("utf-8"))
        style = postData.get("style", 'celeba_distill')
        image = postData.get("image")
        localName = randomStr(10)
        imagePath = cacheDir + localName
        with open(imagePath, 'wb') as f:
            f.write(base64.b64decode(image))
        model = models[style]
        imgAttr = Image.open(imagePath).convert("RGB")
        outAttr = face2paint(model, imgAttr)
        img_buffer = io.BytesIO()
        outAttr.save(img_buffer, format='JPEG')
        byte_data = img_buffer.getvalue()
        img_buffer.close()
        result["photo"] = 'data:image/jpg;base64, %s' % base64.b64encode(byte_data).decode()
    except Exception as e:
        print("ERROR: ", e)
        result["error"] = True
    return result

app = bottle.default_app()
if __name__ == "__main__":
    bottle.run(host='localhost', port=8099)

Key Serverless adaptations:

Models are loaded during instance initialization to reduce cold‑start latency.

Only the /tmp directory is writable, so uploaded images are cached there.

Even though Function Compute is stateless, temporary files are given random names to avoid clashes.

Binary uploads are not universally supported, so the API uses base64‑encoded payloads.

Style List Endpoint

An additional endpoint /system/styles returns a JSON map of available styles, each with a preview image URL, allowing the front‑end to display options.

@bottle.route('/system/styles', method='GET')
def styles():
    return {
      "AI动漫风": {
        'color': 'red',
        'detailList': {
          "风格1": {
            'uri': "images/comic_style",
            'name': 'celeba_distill',
            'color': 'orange',
            'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773808708_20220320105649389392.png'
          },
          "风格2": {
            'uri': "images/comic_style",
            'name': 'face_paint_512_v1',
            'color': 'blue',
            'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773875279_20220320105756071508.png'
          },
          "风格3": {
            'uri': "images/comic_style",
            'name': 'face_paint_512_v2',
            'color': 'pink',
            'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773926924_20220320105847286510.png'
          },
          "风格4": {
            'uri': "images/comic_style",
            'name': 'paprika',
            'color': 'cyan',
            'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773976277_20220320105936594662.png'
          }
        }
      }
    }

Serverless Deployment with Serverless Devs

The service is packaged using Serverless Devs. The s.yaml file defines global variables, NAS configuration, VPC settings, and a function component named image_server with 3 GB memory and a 300 s timeout. It also sets up an HTTP trigger and a custom domain ( avatar.aialbum.net).

edition: 1.0.0
name: start-ai
access: "default"
vars:
  region: cn-hangzhou
  service:
    name: ai
    nasConfig:
      userId: 10003
      groupId: 10003
      mountPoints:
        - serverAddr: 0fe764bf9d-kci94.cn-hangzhou.nas.aliyuncs.com
          nasDir: /python3
          fcDir: /mnt/python3
    vpcConfig:
      vpcId: vpc-bp1rmyncqxoagiyqnbcxk
      securityGroupId: sg-bp1dpxwusntfryekord6
      vswitchIds:
        - vsw-bp1wqgi5lptlmk8nk5yi0
services:
  image:
    component: fc
    props:
      region: ${vars.region}
      service: ${vars.service}
      function:
        name: image_server
        description: 图片处理服务
        runtime: python3
        codeUri: ./
        ossBucket: temp-code-cn-hangzhou
        handler: index.app
        memorySize: 3072
        timeout: 300
        environmentVariables:
          PYTHONUSERBASE: /mnt/python3/python
        triggers:
          - name: httpTrigger
            type: http
            config:
              authType: anonymous
              methods:
                - GET
                - POST
                - PUT
        customDomains:
          - domainName: avatar.aialbum.net
            protocol: HTTP
            routeConfigs:
              - path: /*

Deployment steps:

Install dependencies inside a Docker container: s build --use-docker Deploy the service: s deploy Create the NAS directory and upload the Python dependencies: s nas command mkdir /mnt/python3/python then

s nas upload -r 本地依赖路径 /mnt/python3/python

WeChat Mini‑Program Frontend

The mini‑program uses the ColorUI framework and consists of a single page. The layout (WXML) provides image upload, style selection, and a button to trigger the AI conversion. The JavaScript (index.js) handles page state, fetches the style list from /system/styles, uploads the selected image as base64, calls /images/comic_style, and displays the result.

// index.js
const app = getApp()
Page({
  data: {
    styleList: {},
    currentStyle: "动漫风",
    currentSubStyle: "v1模型",
    userChosePhoho: undefined,
    resultPhoto: undefined,
    previewStyle: undefined,
    getPhotoStatus: false
  },
  onLoad() {
    wx.showLoading({title: '加载中'})
    app.doRequest(`system/styles`, {}, {method: "GET"}).then(result => {
      wx.hideLoading()
      this.setData({
        styleList: result,
        currentStyle: Object.keys(result)[0],
        currentSubStyle: Object.keys(result[Object.keys(result)[0]].detailList)[0]
      })
    })
  },
  // ... (event handlers for style change, photo selection, request, etc.)
})

A unified request helper abstracts wx.request to simplify GET/POST calls.

// unified request
doRequest: async function (uri, data, option) {
  return new Promise((resolve, reject) => {
    wx.request({
      url: this.url + uri,
      data: data,
      header: {"Content-Type": 'application/json'},
      method: option && option.method ? option.method : "POST",
      success: res => resolve(res.data),
      fail: () => reject(null)
    })
  })
}

Additional Notes

The mini‑program requires HTTPS endpoints; certificate configuration is omitted for brevity.

Separate backend functions for style listing and image processing keep memory usage low and reduce cost.

Large model files (>800 MB) cannot be uploaded directly; they are mounted via NAS.

After deployment, users can open the mini‑program, choose a photo, pick a cartoon style, and receive a generated comic‑style avatar.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ServerlessPythonAIDeploymentWeChat Mini ProgramAnimeGAN
Alibaba Cloud Native
Written by

Alibaba Cloud Native

We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.