# DEMO示例

# 服务场景描述

模型简化服务通过调用 上传文件调用函数查询函数执行结果获取文件下载链接等API完成简化模型的功能,满足产品对于模型简化场景的需求。

服务调用时序图。

# 服务调用流程

# 1、本服务调用依赖以下API:

上传文件

调用函数

查询函数执行结果

获取文件下载链接

# 2、服务调用前置条件:

  • 创建应用,获取appkey、appsecret;

  • 获取服务调用token;

  • 开通服务,scope授权通过;

    以上步骤可参考前置准备

# 3、具体调用步骤

step1:上传文件

此步骤会将待简化模型zip文件上传到gdoc上。

step2:调用函数

此步骤调用简化函数,后端服务会下载zip文件,经简化后,将结果zip并上传到gdoc。

fileId,fileSrc,dCompressionRatio这3个参数是必填的。

**注意:**fileSrc参数是obj在zip文件中的路径。

step3:查询函数执行结果

如果函数为异步执行,则需轮询调用此函数;如果选择阻塞调用,则应确保该模型可在1分钟内简化完。

step4:获取文件下载链接

函数执行完后,会返回结果zip文件在gdoc上的fileId,通过调用此接口获得该fileId的下载链接(默认有效期1小时)。

# 演示代码

# java-demo 示例

使用已封装好的faas-meshsimplify-spring-boot-starter,配置appKey和appSecret,即可开箱使用。

# 添加依赖
<dependency>
    <groupId>com.glodon.digiarch.paas</groupId>
    <artifactId>faas-meshsimplify-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
1
2
3
4
5
# 配置application.yml
meshsimplify:
  appKey: #您创建的应用的appKey
  appSecret: #您创建的应用的appSecret
1
2
3
# 开始使用
package com.example.demo;

import com.glodon.digiarch.faas.autoconfig.meshsimplify.MeshSimplifyClient;
import com.glodon.digiarch.faas.sdk.meshsimplify.model.Parameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.File;

@SpringBootApplication(scanBasePackages = "com.glodon.digiarch.faas.autoconfig.meshsimplify")
public class DemoApplication implements CommandLineRunner {
    @Autowired
    private MeshSimplifyClient meshSimplifyClient;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        //1. 待简化模型文件zip格式
        String zipModelFile = "E:\\mesh-simplify\\ta.zip";
        //2. 参数设置
        Parameter parameter = new Parameter();
        //obj文件参数:obj在zip文件中的路径
        parameter.setFileSrc("ta.obj");
        //压缩率
        parameter.setdCompressionRatio(0.5);
        //3. 调用,返回简化结果的下载链接
        String url = meshSimplifyClient.execute(new File(zipModelFile), parameter, false, 0);
        System.out.println(url);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# python-demo 示例

# meshsimplify-sdk-python.py封装了服务中涉及的接口
# meshsimplify_sdk_python.py
import requests
import base64
import json
import time
import os
import logging
import traceback
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')

logger = logging.getLogger('MeshSimplifyClient')

class MeshSimplifyClient:
    def __init__(self, appKey, appSecret, accountServer = "https://account.glodon.com", apigateServer = "https://apigate.glodon.com"):
        self._accountUrl = accountServer + "/oauth2/token?grant_type=client_credentials"
        self._apigateUrl = apigateServer
        self._fileUrl = self._apigateUrl + '/faas/files'
        self._meshSimplifyUrl = self._apigateUrl + '/meshSimplify/meshSimplify/v1.1' 

        k = appKey + ':' + appSecret
        self._basicAuth = base64.b64encode(k.encode()).decode()
        self._accessToken = None
        self._expiredIn = None
        self._accessTokenStartTime = None

    def _checkToken(self):
        if self._accessToken == None:            
            r = requests.post(self._accountUrl, headers={'Authorization': 'Basic ' + self._basicAuth})
            data = json.loads(r.text)
            logger.info("_checkToken -> %s", data)
            if r.status_code == 200:
                self._accessToken = data['access_token']
                self._expiredIn = data['expires_in']
                self._accessTokenStartTime = time.time()
        return self._accessToken != None

    def upload(self, zipModelFile):
        r"""上传待简化模型zip文件.

        :param zipModelFile: 待简化模型zip文件.
        :return: fileId 上传后的文件id
        :rtype: string
        """
        
        if self._checkToken():
            url = self._fileUrl
            files = {'file': open(zipModelFile, 'rb')}
            r = requests.post(url, headers={'Authorization': 'Bearer ' + self._accessToken}, files=files)
            data = json.loads(r.text)
            logger.info("upload -> %s", data)
            if r.status_code == 200 and data['code'] == 'success':
                return data['data']
            else:
                return None

    def getSignUrl(self, fileId):
        r"""获取文件id的下载链接(默认有效期1小时).

        :param fileId: 文件id.
        :return: url 下载链接
        :rtype: string
        """

        if self._checkToken():
            url = self._fileUrl + '?fileId=' + fileId
            r = requests.get(url, headers={'Authorization': 'Bearer ' + self._accessToken})
            data = json.loads(r.text)
            logger.info("getSignUrl -> %s", data)
            if r.status_code == 200 and data['code'] == 'success':
                return data['data']
            else:
                return None


    def excute(self, param):
        r"""阻塞调用函数,超时默认1分钟。

        :param param: 方法参数.
        :return: 函数结果
        :rtype: json
        """

        if self._checkToken():
            url = self._meshSimplifyUrl + '?blocking=true'
            param = json.dumps(param)
            r = requests.post(url, headers={'Content-Type':'application/json', 'Authorization': 'Bearer ' + self._accessToken}, data=param)
            data = json.loads(r.text)
            logger.info("excute -> %s", data)
            if r.status_code == 200:
                return data
            else:
                return None

    def asyncExcute(self, param):
        r"""异步调用函数。

        :param param: 方法参数.
        :return: json对象,含任务id
        :rtype: json
        """

        if self._checkToken():
            url = self._meshSimplifyUrl
            param = json.dumps(param)
            r = requests.post(url, headers={'Content-Type':'application/json', 'Authorization': 'Bearer ' + self._accessToken}, data=param)
            data = json.loads(r.text)
            logger.info("asyncExcute -> %s", data)
            if r.status_code == 202:
                return data
            else:
                return None

    def getExecuteResult(self, activationId):
        r"""查询函数执行结果

        :param activationId: 任务id.
        :return: 函数结果
        :rtype: json
        """

        if self._checkToken():
            url = self._meshSimplifyUrl + '/' + activationId
            r = requests.get(url, headers={'Content-Type':'application/json', 'Authorization': 'Bearer ' + self._accessToken})
            data = json.loads(r.text)
            logger.info("getExecuteResult -> %s", data)
            if r.status_code == 200:
                return data
            else:
                return None

    def downloadFile(self, url, saveToFile):
        r"""下载url文件到本地文件

        :param url: 文件链接.
        :return: saveToFile 存到本地文件
        :rtype: bool
        """
        r = requests.get(url)
        logger.info("downloadFile -> %s, %s", r.status_code, saveToFile)
        with open(saveToFile, "wb") as infile:
            infile.write(r.content)
            return True
        return False

    def easy_execute(self, zipModelFile, param, blocking, resultFile):
        r"""对函数调用相关api组合的简易封装

        :param zipModelFile: 待简化的模型文件.
        :param param: 函数参数.
        :param blocking: 是否阻塞调用.
        :param zipModelFile: 结果存到本地文件.
        :return: 是否执行成功
        :rtype: bool
        """
        try:
            fileId = self.upload(zipModelFile)
            if fileId != None:
                param['fileId'] = fileId
                result = None
                if blocking:
                    result = self.excute(param)
                else:
                    data = self.asyncExcute(param)
                    if data != None:
                        activationId = data['activationId']
                        while True:
                            result = self.getExecuteResult(activationId)
                            if result == None:
                                time.sleep(3)
                            else:
                                break

                if result != None:
                    fileId = result['response']['result']['fileId']
                    url = self.getSignUrl(fileId)
                    if url != None:
                        return self.downloadFile(url, resultFile)
            return False            
        except Exception as e:
            logger.error('error', exc_info=True)
            raise e

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# 开始使用
from meshsimplify_sdk_python.py import MeshSimplifyClient

app_key = #您创建的应用的appKey
app_secret = #您创建的应用的appSecret

client = MeshSimplifyClient(app_key, app_secret)
# 待简化的模型:zip格式
zipModelFile = r"E:\mesh-simplify\demo\BUG_08.zip" 
# 构造参数:fileSrc参数是obj在zip文件中的路径
param = {'fileSrc': 'BUG_08.obj', 'dCompressionRatio': 0.5}
# 调用,将结果保存到本地文件
client.easy_execute(zipModelFile, param, False, zipModelFile + '-result.zip')
1
2
3
4
5
6
7
8
9
10
11
12

# 简化结果示例

示例模型文件

该模型的简化结果如下图,可以看到设置压缩率为0.5,faces面片减少了50%,但依然保持了很好的整体效果。

  • 在线客服

  • 意见反馈