NVIDIA 7th SkyHackathon(八)使用 Flask 与 Vue 开发 Web

1.页面效果

Web 采用 flask+vue 开发,效果图如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.后端

import sys
import subprocess
import os
from PIL import Image
from datetime import datetime
from ASR_metrics import utils as metrics

from werkzeug.wrappers import Request, Response
from flask import Flask, render_template, request, jsonify

sys.path.append('/home/nvidia/7th_CV')
sys.path.append('/home/nvidia/7th_ASR')

# ASR 路径
pathASR = "/home/nvidia/7th_ASR"

# 项目路径
pathSky = '/home/nvidia'

app = Flask(__name__, static_folder='')

# 上传路径
uploadPath = 'uploads/'
try_model_1 = None

# 主页
@app.route('/')
def index():
    return render_template('sky7.html', template_folder='templates')

# ------------------ASR------------------
# ASR 模型加载
@app.route('/asr/load')
def asrLoad():
    global try_model_1
    if try_model_1 == None:
        import nemo.collections.asr as nemo_asr
        print('Loading Nemo')
        # 加载模型
        try_model_1 = nemo_asr.models.EncDecCTCModel.restore_from("/home/nvidia/7th_ASR/7th_asr_model.nemo")
        print('Done loading Nemo')
    return 'ok'

# POST 请求上传音频
@app.route('/asr/upload', methods=['POST'])
def asrUpload():
    if request.method == 'POST':
        f = request.files['file']
        if(f.headers.get('Content-Type') != 'audio/wav'):
            return '音频格式有错误', 400
        else:
            fileName = f'{uploadPath}audio.wav'
            f.save(fileName)
            dt = datetime.now()
            ts = str(int(datetime.timestamp(dt)))
            return jsonify(f'/{uploadPath}audio.wav?t={ts}')

# 识别上传的音频
@app.route('/asr/identify', methods=['GET', 'POST'])
def asrIdentify():
    global try_model_1
    if try_model_1 == None:
        return '模型无效,请重新加载', 500
    try:
        asr_result = try_model_1.transcribe(paths2audio_files=["uploads/audio.wav"])
        s1 = request.form.get('defaultText')
        s2 = " ".join(asr_result)#识别结果
        result = {
            "asr_result": asr_result,
            "word_error_rate": metrics.calculate_cer(s1,s2),
            "word_accuracy_rate":1-metrics.calculate_cer(s1,s2)
        }
        return jsonify(result)
    except Exception as e:
        return '无法识别', 400

# ------------------CV------------------

# POST 请求上传图片
@app.route("/cv/upload", methods=['POST'])
def cvUpload():
    if request.method == 'POST':
        f = request.files['file']
        print('image', f, f.filename)

        if not 'image' in f.headers.get('Content-Type'):
            return '图片有错误', 400

        original = f'{uploadPath}original.jpg'

        try:
            # Convert image to jpeg
            im = Image.open(f)
            rgb_im = im.convert('RGB')
            rgb_im.save(original)

            # Add timestamp
            dt = datetime.now()
            ts = str(int(datetime.timestamp(dt)))
            return jsonify(original+'?t='+ts)

        except Exception as e:
            return '有错误', 400

# 检测图片
@app.route("/api/detect/image")
def detectImage():
    cv_results = subprocess.Popen('python3 /home/nvidia/7th_CV/detection_image.py /home/nvidia/uploads/original.jpg', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    print('code', cv_results.returncode)
    cv_results = str(cv_results.stdout.read()).split('\\n')[-2]
    dt = datetime.now()
    ts = str(int(datetime.timestamp(dt)))
    result = {
        "detection_result_image_path": f'/uploads/result.jpg?t={ts}'
    }
    return jsonify(result)

# 获取 FPS,以 Json 格式返回前端
@app.route("/api/detect/fps")
def detectFPS():
    # Code here
    fps_results = subprocess.Popen('python3 /home/nvidia/7th_CV/cv_fps.py', shell = True, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
    fps_results = str(fps_results.stdout.read()).split('\\n')[-2]
    fps_results = fps_results.split(" ")[-1]
    result = {
        "detection_FPS": fps_results,
    }
    return jsonify(result)

# 获取 mAP
@app.route("/api/detect/map")
def detectMAP():
    # Code here
    map_results = subprocess.Popen('python3 /home/nvidia/7th_CV/cv_map.py', shell = True, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
    map_results = str(map_results.stdout.read())
    bytes(map_results, encoding="utf-8").decode()
    map_results = map_results[-9:-3]
    result = {
        "detection_mAP": map_results,
    }
    return jsonify(result)

if __name__ == "__main__":
    app.run(debug=True)

3.前端

3.1 html

<html>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <head>
        <script src="https://unpkg.com/vue@3"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <link rel="stylesheet" href="//unpkg.com/layui@2.6.8/dist/css/layui.css">
        <script src="//unpkg.com/layui@2.6.8/dist/layui.js"></script>
        <link rel="stylesheet" type="text/css" href="/style.css">
    </head>

    <body id="app">
        <!-- 模型加载中 -->
        <div class="loading" v-if="loading!=''">
            <div class="pad">%%loading%%</div>
        </div>
        <h1>7th Sky Hackathon</h1>
        <h5>team:早八睡不醒</h5>
        <div class="content">

            <div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">

                <ul class="layui-tab-title">
                    <li class="layui-this"><i class="layui-icon panel-title layui-icon">&#xe6dc;&nbsp;ASR</i></li>
                    <li><i class="layui-icon panel-title layui-icon">&#xe660;&nbsp;CV</i></li>
                </ul>
                <div class="layui-tab-content">
                    <!-- ASR 开始-->
                    <div class="layui-tab-item layui-show">
                        <div class="layui-anim layui-anim-up">
                            <fieldset class="asr">
                                <legend><span class="panel-title">ASR</span></legend>

                                <div class="layui-container">

                                    <!-- 1 开始 -->
                                    <div class="layui-row">
                                        <div class="layui-col-md4">
                                            1.请加载语音识别模型
                                        </div>
                                        <div class="layui-col-md4">
                                            <button class="layui-btn" @click="loadModel()" v-if="!modelLoaded"><i
                                                    class="layui-icon">&#xe601;&nbsp;加载</i></button>
                                            <div v-if="modelLoaded" class="modelLoaded">模型加载成功</div>
                                        </div>
                                    </div>
                                    <!-- 1 结束 -->

                                    <!-- 2、3 开始 -->
                                    <div class="field file">
                                        <div class="newFileUpload">
                                            <!-- 2 开始 -->
                                            <div class="layui-row">
                                                <div class="layui-col-md4">
                                                    <label for="file">2.请选择音频文件</label>
                                                    <div class="note">&nbsp;&nbsp;&nbsp;仅支持 .wav 和单声道格式</div>
                                                </div>
                                                <div class="layui-col-md4">
                                                    <div class="userdefined-file">
                                                        <input type="text" name="userdefinedFile"
                                                            id="userdefinedFileAudio" value="未选择任何文件" />
                                                        <button type="button">选择</button>
                                                    </div>
                                                    <input type="file" name="file" id="fileAudio"
                                                        @change="handleFileUploadAudio($event)" />
                                                </div>
                                            </div>
                                            <!-- 2 结束 -->
                                        </div>

                                        <!-- 3 开始 -->
                                        <div class="layui-row">
                                            <div class="layui-col-md4"> 3.请上传音频文件</div>
                                            <div class="layui-col-md4">
                                                <button class="layui-btn" @click="submitFile('asr')"><i
                                                        class="layui-icon">&#xe67c;&nbsp;上传</i></button>
                                            </div>
                                        </div>
                                        <!-- 3 结束 -->
                                    </div>
                                    <!-- 2、3 结束 -->

                                    <!-- 4 开始 -->
                                    <div class="layui-row">
                                        <div class="field">
                                            <div class="layui-col-md4">
                                                <label>4.请试听上传语音并输入正确答案</label>
                                            </div>
                                            <div class="layui-col-md4">
                                                <input id="answer" type="text" name="defaultText"
                                                    v-model="defaultText" />
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 4 结束 -->


                                    <div class="field" v-if="asrStatus=='uploaded' || asrStatus=='identified'">
                                        <!-- 试听 开始 -->
                                        <div class="layui-row">
                                            <div class="audio">
                                                <div class="layui-col-md4">&nbsp;&nbsp;&nbsp; 试听 </div>
                                                <div class="layui-col-md4">
                                                    <audio controls :src="audioOriginal"></audio>
                                                </div>
                                            </div>
                                        </div>
                                        <!-- 试听 结束 -->

                                        <!-- 5 开始 -->
                                        <div class="layui-row">
                                            <div class="layui-col-md4">5.识别语音</div>
                                            <div class="layui-col-md4">
                                                <div class="action">
                                                    <button class="layui-btn" @click="identifyAudio()"><i
                                                            class="layui-icon">&#xe615;&nbsp;识别</i></button>
                                                </div>
                                            </div>
                                        </div>
                                        <!-- 5 结束 -->
                                    </div>

                                    <!-- 6 开始 -->
                                    <div class="layui-row">
                                        <div class="field result asr" v-if="asrStatus=='identified'">
                                            <div class="layui-col-md4">6.指标</div>
                                            <div class="layui-col-md4">
                                                <ul>
                                                    <li v-for="(value, key) in asrResult">%%key%%: %%value%%</li>
                                                </ul>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 6 结束 -->
                                </div>

                            </fieldset>
                        </div>
                    </div>
                    <!-- ASR 结束 -->

                    <!-- CV 开始 -->
                    <div class="layui-tab-item">
                        <div class="layui-anim layui-anim-up">
                            <fieldset class="cv">
                                <legend><span class="panel-title">CV</span></legend>

                                <div class="layui-container">

                                    <!-- 1 开始 -->
                                    <div class="field">
                                        <div class="layui-row">
                                            <div class="layui-col-md4">
                                                <p>1. 获取 FPS</p>
                                                <div class="item result">&nbsp;&nbsp;&nbsp; FPS: %%cvFps%%</div>
                                            </div>
                                            <div class="layui-col-md4">
                                                <div class="item action">
                                                    <button @click="getFps()" class="inline layui-btn"><i
                                                            class="layui-icon">&#xe601;&nbsp;获取</i></button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 1 结束 -->

                                    <!-- 2 开始 -->
                                    <div class="field">
                                        <div class="layui-row">
                                            <div class="layui-col-md4">
                                                <p>2. 获取 mAP</p>
                                                <div class="item result">&nbsp;&nbsp;&nbsp; mAP: %%cvMap%%</div>
                                            </div>
                                            <div class="layui-col-md4">
                                                <div class="item">
                                                    <button @click="getMap()" class="inline layui-btn"><i
                                                            class="layui-icon">&#xe601;&nbsp;获取</i></button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- 2 结束 -->

                                    <!-- 3、4 开始 -->
                                    <div class="field file">
                                        <!-- 3 开始 -->
                                        <div class="newFileUpload">
                                            <div class="layui-row">
                                                <div class="layui-col-md4">
                                                    <label for="file">3.请选择图像文件 </label>
                                                    <div class="note">&nbsp;</div>
                                                </div>
                                                <div class="layui-col-md4">
                                                    <div class="userdefined-file">
                                                        <input type="text" name="userdefinedFile"
                                                            id="userdefinedFileImage" value="未选择任何文件" />
                                                        <button type="button">选择</button>
                                                    </div>

                                                    <input type="file" name="file" ref="file" id="fileImage"
                                                        @change="handleFileUploadImage($event)" />
                                                </div>
                                            </div>
                                        </div>
                                        <!-- 3 结束 -->

                                        <!-- 4 开始 -->
                                        <div class="layui-row">
                                            <div class="layui-col-md4">4.请上传图像文件 </div>
                                            <div class="layui-col-md4">
                                                <button @click="submitFile('cv')" class="layui-btn"><i
                                                        class="layui-icon">&#xe67c;&nbsp;上传</i></button>
                                            </div>
                                        </div>
                                        <!-- 4 结束 -->
                                    </div>
                                    <!-- 3、4 结束 -->

                                    <div class="action" v-if="imageOriginal!=''">
                                        <div class="layui-row">
                                            <div class="layui-col-md4">5.识别图片</div>
                                            <div class="layui-col-md4">
                                                <button class="layui-btn" @click="identifyImage()"><i
                                                        class="layui-icon">&#xe615;&nbsp;识别</i></button><br>
                                            </div>
                                        </div>
                                    </div>

                                    <div class="field">
                                        <div class="layui-row">
                                            <div class="image original" v-if="imageOriginal!=''">
                                                <div class="layui-col-md1">
                                                    <div class="label">原图</div>
                                                </div>
                                                <div class="layui-col-md3">
                                                    <image :src="imageOriginal" />
                                                </div>
                                            </div>

                                            <div class="image result cv" v-if="imageResult!=''">
                                                <div class="layui-col-md1">
                                                    <div class="label">结果图</div>
                                                </div>
                                                <div class="layui-col-md3">
                                                    <image :src="imageResult" />
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                </div>
                            </fieldset>
                        </div>
                    </div>
                    <!-- CV 结束 -->
                </div>
            </div>
        </div>
    </body>
    <script>
        const {
            createApp
        } = Vue
        createApp({
            data() {
                return {
                    file: '',
                    defaultText: '请检测出纸箱、瓶子和果皮',
                    modelLoaded: false,
                    imageOriginal: '',
                    imageResult: '',
                    audioOriginal: '',
                    error: '',
                    asrResult: {},
                    cvMap: '',
                    cvFps: '',
                    loading: '',
                    asrStatus: 'pending',
                    cvStatus: 'pending'
                }
            },
            // Avoid conflict with Flask delimiters
            compilerOptions: {
                delimiters: ["%%", "%%"]
            },
            methods: {
                async loadModel() {
                    if (this.loading != '') return showError('在运行中,无法执行')
                    this.loading = '加载模型中,请耐心等待...'
                    this.modelLoaded = false
                    try {
                        var {
                            data,
                            status
                        } = await axios.get('/asr/load')
                        if (status == 200) {
                            this.modelLoaded = true
                        }
                    } catch (err) {
                        showError(err.response.data)
                    }
                    this.loading = ''
                },
                async submitFile(fileType) {
                    let formData = new FormData()
                    formData.append('file', this.file)
                    if (this.file == "") {
                        showError("请选择文件");
                        return false;
                    }

                    statusType = fileType + 'Status'
                    this.loading = '上传中...'
                    try {
                        var {
                            data,
                            status
                        } = await axios.post('/' + fileType + '/upload', formData, {
                            headers: {
                                'Content-Type': 'multipart/form-data'
                            }
                        })
                        if (status == 200) {
                            this[statusType] = 'uploaded'
                            if (fileType == 'cv') {
                                this.imageOriginal = data
                            } else {
                                this.audioOriginal = data
                            }
                        }
                    } catch (err) {
                        showError(err.response.data)
                    }
                    this.loading = ''
                },
                handleFileUploadAudio(event) {
                    document.getElementById("userdefinedFileAudio").value = document.getElementById("fileAudio")
                        .value;
                    this.file = event.target.files[0];
                },
                handleFileUploadImage(event) {
                    document.getElementById("userdefinedFileImage").value = document.getElementById("fileImage")
                        .value;
                    this.file = event.target.files[0];
                },
                async identifyAudio(event) {
                    // if (this.loading != '') return showError('在运行中,无法执行')
                    this.loading = '识别中...'
                    try {
                        let formData = new FormData()
                        formData.append('defaultText', this.defaultText)
                        console.log('t', this.defaultText)
                        var result = await axios.post('/asr/identify', formData)
                        this['asrStatus'] = 'identified'
                        this.asrResult = result.data
                    } catch (err) {
                        if (err.response.status == 500) this.modelLoaded = false
                        showError(err.response.data)
                    }
                    this.loading = ''
                },
                async identifyImage(event) {
                    if (this.loading != '') return showError('在运行中,无法执行')
                    this.loading = '识别中...'
                    this.cvStatus = 'pending'
                    try {
                        var {
                            data
                        } = await axios.get('/api/detect/image')
                        this.imageResult = data['detection_result_image_path']
                    } catch (err) {
                        showError(err.response.data)
                    }
                    this.loading = ''
                },
                async getFps(event) {
                    if (this.loading != '') return showError('在运行中,无法执行')
                    this.loading = '获取 FPS...'
                    try {
                        var {
                            data
                        } = await axios.get('/api/detect/fps')
                        this.cvFps = data['detection_FPS']
                    } catch (err) {
                        showError(err.response.data)
                    }
                    this.loading = ''
                },
                async getMap(event) {
                    // 接口路径: /api/detect/map
                    // 方式: GET
                    if (this.loading != '') return showError('在运行中,无法执行')
                    this.loading = '获取 mAP...'
                    try {
                        var {
                            data
                        } = await axios.get('/api/detect/map')
                        this.cvMap = data['detection_mAP']
                    } catch (err) {
                        showError(err.response.data)
                    }
                    this.loading = ''
                }
            }
        }).mount('#app')

        function showError(msg) {
            layer.msg(msg || '错误')
        }
    </script>
</html>

3.2 CSS

body {
	font-size: 20px;
	margin: 0;
}

.content {
	padding: 10px;
	margin: 40px;
}

fieldset {
	border: 1px solid #ccc;
	padding: 10px;
}

.modelLoaded {
	color: green;
}

.note {
	color: #999;
	margin: 5px 0;
	font-size: 12px;
}

.field {
	margin: 10px 0;
}

.action {
	margin-top: 10px;
}

.loading {
	position: fixed;
	top: 0;
	background: #E8F9D9;
	text-align: center;
	width: 100%;
}

.pad {
	padding: 5px;
}

.inline {
	display: inline-block;
}

.field .item {
	margin: 5px 0;
}

.image {
	display: inline-block;
	margin-right: 10px;
}

.image img {
	max-height: 600px;
}

/* 标题 */
h1,
h5 {
	margin: 40px;
}

/* 队名 */
h5 {
	margin-left: 210px;
}

/* 面板title */
.panel-title {
	font-size: 25px;
}

/* 答案输入框 */
#answer {
	height: 40px;
	width: 200px;
	font-size: 14px;
	display: inline-block;
	vertical-align: middle;
	padding-right: 14px;
	padding-left: 14px;
}

/* 音频文件选择 */
.newFileUpload {
	position: relative;
	height: 40px;
	line-height: 40px;
}

.newFileUpload label {
	display: inline-block;
}

.userdefined-file {
	position: absolute;
	top: 0;
	/* left: 200px; */
	z-index: 2;
	width: 300px;
	height: 40px;
	line-height: 40px;
	font-size: 0;
	/*应对子元素为 inline-block 引起的外边距*/
}

.userdefined-file input[type="text"] {
	display: inline-block;
	vertical-align: middle;
	padding-right: 14px;
	padding-left: 14px;
	width: 220px;
	box-sizing: border-box;
	border: 1px solid #ccc;
	height: 40px;
	line-height: 40px;
	font-size: 14px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.userdefined-file button {
	display: inline-block;
	vertical-align: middle;
	width: 80px;
	text-align: center;
	height: 40px;
	line-height: 40px;
	font-size: 14px;
	background-color: #009688;
	/* background-color: #f54; */
	border: none;
	color: #fff;
	cursor: pointer;
}

.newFileUpload input[type="file"] {
	position: absolute;
	top: 0;
	/* left: 200px; */
	z-index: 3;
	opacity: 0;
	width: 300px;
	height: 40px;
	line-height: 40px;
	cursor: pointer;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值