no message
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
1_image_sdks/text_recognition/ocr_sdk/.idea/
|
||||
1_image_sdks/text_recognition/.idea/
|
||||
1_image_sdks/security/pedestrian_sdk/.idea/
|
||||
.idea/
|
||||
|
@ -1,88 +0,0 @@
|
||||
|
||||
### Download the model and place it in the models directory and unzip it
|
||||
- Link: https://github.com/mymagicpower/AIAS/releases/download/apps/api_platform.zip
|
||||
|
||||
# AI Empowerment Platform
|
||||
|
||||
The AI Empowerment Platform provides interfaces for upper-layer applications in the form of REST APIs.
|
||||
The current CPU version includes the following functions:
|
||||
|
||||
1. Free text recognition (currently requires that the images are upright, that is, without rotation angles. The automatic correction function is being optimized.)
|
||||
2. Face detection (return the detection box coordinates, detection box coordinate order: up, right, down, left)
|
||||
3. Face feature extraction (512-dimensional features)
|
||||
4. Face 1:1 comparison
|
||||
|
||||
### 1. Front-end deployment
|
||||
|
||||
### 1.1 Run directly:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### 1.2 Build the dist installation package:
|
||||
```bash
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
#### 1.3 nginx deployment operation (mac environment is used as an example):
|
||||
```bash
|
||||
cd /usr/local/etc/nginx/
|
||||
vi /usr/local/etc/nginx/nginx.conf
|
||||
# Edit nginx.conf
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /Users/calvin/api-platform/dist/;
|
||||
index index.html index.htm;
|
||||
}
|
||||
......
|
||||
|
||||
# Reload the configuration:
|
||||
sudo nginx -s reload
|
||||
|
||||
# After deploying the application, restart:
|
||||
cd /usr/local/Cellar/nginx/1.19.6/bin
|
||||
|
||||
# Quick stop
|
||||
sudo nginx -s stop
|
||||
|
||||
# Start
|
||||
sudo nginx
|
||||
```
|
||||
|
||||
### 2. Backend deployment
|
||||
|
||||
### 2.1 jar package
|
||||
|
||||
Build jar package
|
||||
|
||||
### 2.2 Running the program
|
||||
```bash
|
||||
# Running the program
|
||||
|
||||
java -jar api-platform-0.1.0.jar
|
||||
```
|
||||
|
||||
## Open the browser
|
||||
|
||||
Enter the address: http://localhost:8080
|
||||
|
||||
#### 1. Free text recognition:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/ocr.png)
|
||||
|
||||
#### 2. Face detection:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_detect.png)
|
||||
|
||||
#### 3. Face feature extraction (512-dimensional features):
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_feature.png)
|
||||
|
||||
#### 4. Face 1:1 comparison:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_comare.png)
|
||||
|
||||
#### 5. Interface documentation:
|
||||
http://127.0.0.1:8089/swagger-ui.html
|
||||
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/swagger.png)
|
@ -1,114 +0,0 @@
|
||||
## 目录:
|
||||
http://aias.top/
|
||||
|
||||
# AI 赋能平台
|
||||
AI赋能平台以REST API形式为上层应用提供接口。
|
||||
当前CPU版包含功能如下:
|
||||
1. 自由文本识别(目前需要图片都是摆正的,即没有旋转角度,自动转正功能在优化中。)
|
||||
2. 人脸检测(返回检测框坐标,检测框坐标顺序:上右下左)
|
||||
3. 人脸特征提取(512维特征)
|
||||
4. 人脸 1:1 比对
|
||||
|
||||
### 1. 前端部署
|
||||
|
||||
#### 1.1 直接运行:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### 1.2 构建dist安装包:
|
||||
```bash
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
#### 1.3 nginx部署运行(mac环境为例):
|
||||
```bash
|
||||
cd /usr/local/etc/nginx/
|
||||
vi /usr/local/etc/nginx/nginx.conf
|
||||
# 编辑nginx.conf
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /Users/calvin/api-platform/dist/;
|
||||
index index.html index.htm;
|
||||
}
|
||||
......
|
||||
|
||||
# 重新加载配置:
|
||||
sudo nginx -s reload
|
||||
|
||||
# 部署应用后,重启:
|
||||
cd /usr/local/Cellar/nginx/1.19.6/bin
|
||||
|
||||
# 快速停止
|
||||
sudo nginx -s stop
|
||||
|
||||
# 启动
|
||||
sudo nginx
|
||||
```
|
||||
|
||||
### 2. 后端部署
|
||||
|
||||
#### 2.1 jar包
|
||||
构建jar包
|
||||
|
||||
#### 2.2 运行程序
|
||||
```bash
|
||||
# 运行程序
|
||||
java -jar api-platform-0.1.0.jar
|
||||
```
|
||||
|
||||
## 打开浏览器
|
||||
|
||||
输入地址: http://localhost:8080
|
||||
|
||||
#### 1. 自由文本识别:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/ocr.png)
|
||||
|
||||
#### 2. 人脸检测:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_detect.png)
|
||||
|
||||
#### 3. 人脸特征提取(512维特征):
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_feature.png)
|
||||
|
||||
#### 4. 人脸 1:1 比对:
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/face_comare.png)
|
||||
|
||||
#### 5. 接口文档:
|
||||
http://127.0.0.1:8089/swagger-ui.html
|
||||
|
||||
![Screenshot](https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/ai_platform/images/swagger.png)
|
||||
|
||||
## 计划开发的功能:
|
||||
```bash
|
||||
1. 车辆检测
|
||||
2. 行人检测
|
||||
3. 视频处理
|
||||
4. 内容自动生成
|
||||
5. 自然语言处理
|
||||
6. ...
|
||||
```
|
||||
|
||||
### 官网:
|
||||
[官网链接](http://www.aias.top/)
|
||||
|
||||
### Git地址:
|
||||
[Github链接](https://github.com/mymagicpower/AIAS)
|
||||
[Gitee链接](https://gitee.com/mymagicpower/AIAS)
|
||||
|
||||
|
||||
|
||||
#### 帮助文档:
|
||||
- http://aias.top/guides.html
|
||||
- 1.性能优化常见问题:
|
||||
- http://aias.top/AIAS/guides/performance.html
|
||||
- 2.引擎配置(包括CPU,GPU在线自动加载,及本地配置):
|
||||
- http://aias.top/AIAS/guides/engine_config.html
|
||||
- 3.模型加载方式(在线自动加载,及本地配置):
|
||||
- http://aias.top/AIAS/guides/load_model.html
|
||||
- 4.Windows环境常见问题:
|
||||
- http://aias.top/AIAS/guides/windows.html
|
||||
|
@ -1,14 +0,0 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
@ -1,6 +0,0 @@
|
||||
# just a flag
|
||||
ENV = 'development'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:8089'
|
||||
|
@ -1,6 +0,0 @@
|
||||
# just a flag
|
||||
ENV = 'production'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:8089'
|
||||
|
@ -1,8 +0,0 @@
|
||||
NODE_ENV = production
|
||||
|
||||
# just a flag
|
||||
ENV = 'staging'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/stage-api'
|
||||
|
@ -1,4 +0,0 @@
|
||||
build/*.js
|
||||
src/assets
|
||||
public
|
||||
dist
|
@ -1,198 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||
|
||||
// add your custom rules here
|
||||
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||
rules: {
|
||||
"vue/max-attributes-per-line": [2, {
|
||||
"singleline": 10,
|
||||
"multiline": {
|
||||
"max": 1,
|
||||
"allowFirstLine": false
|
||||
}
|
||||
}],
|
||||
"vue/singleline-html-element-content-newline": "off",
|
||||
"vue/multiline-html-element-content-newline":"off",
|
||||
"vue/name-property-casing": ["error", "PascalCase"],
|
||||
"vue/no-v-html": "off",
|
||||
'accessor-pairs': 2,
|
||||
'arrow-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'block-spacing': [2, 'always'],
|
||||
'brace-style': [2, '1tbs', {
|
||||
'allowSingleLine': true
|
||||
}],
|
||||
'camelcase': [0, {
|
||||
'properties': 'always'
|
||||
}],
|
||||
'comma-dangle': [2, 'never'],
|
||||
'comma-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'comma-style': [2, 'last'],
|
||||
'constructor-super': 2,
|
||||
'curly': [2, 'multi-line'],
|
||||
'dot-location': [2, 'property'],
|
||||
'eol-last': 2,
|
||||
'eqeqeq': ["error", "always", {"null": "ignore"}],
|
||||
'generator-star-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'handle-callback-err': [2, '^(err|error)$'],
|
||||
'indent': [2, 2, {
|
||||
'SwitchCase': 1
|
||||
}],
|
||||
'jsx-quotes': [2, 'prefer-single'],
|
||||
'key-spacing': [2, {
|
||||
'beforeColon': false,
|
||||
'afterColon': true
|
||||
}],
|
||||
'keyword-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'new-cap': [2, {
|
||||
'newIsCap': true,
|
||||
'capIsNew': false
|
||||
}],
|
||||
'new-parens': 2,
|
||||
'no-array-constructor': 2,
|
||||
'no-caller': 2,
|
||||
'no-console': 'off',
|
||||
'no-class-assign': 2,
|
||||
'no-cond-assign': 2,
|
||||
'no-const-assign': 2,
|
||||
'no-control-regex': 0,
|
||||
'no-delete-var': 2,
|
||||
'no-dupe-args': 2,
|
||||
'no-dupe-class-members': 2,
|
||||
'no-dupe-keys': 2,
|
||||
'no-duplicate-case': 2,
|
||||
'no-empty-character-class': 2,
|
||||
'no-empty-pattern': 2,
|
||||
'no-eval': 2,
|
||||
'no-ex-assign': 2,
|
||||
'no-extend-native': 2,
|
||||
'no-extra-bind': 2,
|
||||
'no-extra-boolean-cast': 2,
|
||||
'no-extra-parens': [2, 'functions'],
|
||||
'no-fallthrough': 2,
|
||||
'no-floating-decimal': 2,
|
||||
'no-func-assign': 2,
|
||||
'no-implied-eval': 2,
|
||||
'no-inner-declarations': [2, 'functions'],
|
||||
'no-invalid-regexp': 2,
|
||||
'no-irregular-whitespace': 2,
|
||||
'no-iterator': 2,
|
||||
'no-label-var': 2,
|
||||
'no-labels': [2, {
|
||||
'allowLoop': false,
|
||||
'allowSwitch': false
|
||||
}],
|
||||
'no-lone-blocks': 2,
|
||||
'no-mixed-spaces-and-tabs': 2,
|
||||
'no-multi-spaces': 2,
|
||||
'no-multi-str': 2,
|
||||
'no-multiple-empty-lines': [2, {
|
||||
'max': 1
|
||||
}],
|
||||
'no-native-reassign': 2,
|
||||
'no-negated-in-lhs': 2,
|
||||
'no-new-object': 2,
|
||||
'no-new-require': 2,
|
||||
'no-new-symbol': 2,
|
||||
'no-new-wrappers': 2,
|
||||
'no-obj-calls': 2,
|
||||
'no-octal': 2,
|
||||
'no-octal-escape': 2,
|
||||
'no-path-concat': 2,
|
||||
'no-proto': 2,
|
||||
'no-redeclare': 2,
|
||||
'no-regex-spaces': 2,
|
||||
'no-return-assign': [2, 'except-parens'],
|
||||
'no-self-assign': 2,
|
||||
'no-self-compare': 2,
|
||||
'no-sequences': 2,
|
||||
'no-shadow-restricted-names': 2,
|
||||
'no-spaced-func': 2,
|
||||
'no-sparse-arrays': 2,
|
||||
'no-this-before-super': 2,
|
||||
'no-throw-literal': 2,
|
||||
'no-trailing-spaces': 2,
|
||||
'no-undef': 2,
|
||||
'no-undef-init': 2,
|
||||
'no-unexpected-multiline': 2,
|
||||
'no-unmodified-loop-condition': 2,
|
||||
'no-unneeded-ternary': [2, {
|
||||
'defaultAssignment': false
|
||||
}],
|
||||
'no-unreachable': 2,
|
||||
'no-unsafe-finally': 2,
|
||||
'no-unused-vars': [2, {
|
||||
'vars': 'all',
|
||||
'args': 'none'
|
||||
}],
|
||||
'no-useless-call': 2,
|
||||
'no-useless-computed-key': 2,
|
||||
'no-useless-constructor': 2,
|
||||
'no-useless-escape': 0,
|
||||
'no-whitespace-before-property': 2,
|
||||
'no-with': 2,
|
||||
'one-var': [2, {
|
||||
'initialized': 'never'
|
||||
}],
|
||||
'operator-linebreak': [2, 'after', {
|
||||
'overrides': {
|
||||
'?': 'before',
|
||||
':': 'before'
|
||||
}
|
||||
}],
|
||||
'padded-blocks': [2, 'never'],
|
||||
'quotes': [2, 'single', {
|
||||
'avoidEscape': true,
|
||||
'allowTemplateLiterals': true
|
||||
}],
|
||||
'semi': [2, 'never'],
|
||||
'semi-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'space-before-blocks': [2, 'always'],
|
||||
'space-before-function-paren': [2, 'never'],
|
||||
'space-in-parens': [2, 'never'],
|
||||
'space-infix-ops': 2,
|
||||
'space-unary-ops': [2, {
|
||||
'words': true,
|
||||
'nonwords': false
|
||||
}],
|
||||
'spaced-comment': [2, 'always', {
|
||||
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||
}],
|
||||
'template-curly-spacing': [2, 'never'],
|
||||
'use-isnan': 2,
|
||||
'valid-typeof': 2,
|
||||
'wrap-iife': [2, 'any'],
|
||||
'yield-star-spacing': [2, 'both'],
|
||||
'yoda': [2, 'never'],
|
||||
'prefer-const': 2,
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'object-curly-spacing': [2, 'always', {
|
||||
objectsInObjects: false
|
||||
}],
|
||||
'array-bracket-spacing': [2, 'never']
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
language: node_js
|
||||
node_js: 10
|
||||
script: npm run test
|
||||
notifications:
|
||||
email: false
|
@ -1,14 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
],
|
||||
'env': {
|
||||
'development': {
|
||||
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
|
||||
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
|
||||
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
|
||||
'plugins': ['dynamic-import-node']
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
const { run } = require('runjs')
|
||||
const chalk = require('chalk')
|
||||
const config = require('../vue.config.js')
|
||||
const rawArgv = process.argv.slice(2)
|
||||
const args = rawArgv.join(' ')
|
||||
|
||||
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
||||
const report = rawArgv.includes('--report')
|
||||
|
||||
run(`vue-cli-service build ${args}`)
|
||||
|
||||
const port = 9526
|
||||
const publicPath = config.publicPath
|
||||
|
||||
var connect = require('connect')
|
||||
var serveStatic = require('serve-static')
|
||||
const app = connect()
|
||||
|
||||
app.use(
|
||||
publicPath,
|
||||
serveStatic('./dist', {
|
||||
index: ['index.html', '/']
|
||||
})
|
||||
)
|
||||
|
||||
app.listen(port, function () {
|
||||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
||||
if (report) {
|
||||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
run(`vue-cli-service build ${args}`)
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||
'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
snapshotSerializers: ['jest-serializer-vue'],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
|
||||
coverageDirectory: '<rootDir>/tests/unit/coverage',
|
||||
// 'collectCoverage': true,
|
||||
'coverageReporters': [
|
||||
'lcov',
|
||||
'text-summary'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
"name": "ocr-ui",
|
||||
"version": "1.0.0",
|
||||
"description": "OCR UI Demo",
|
||||
"author": "Calvin <693544619@qq.com>",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build:prod": "vue-cli-service build",
|
||||
"build:stage": "vue-cli-service build --mode staging",
|
||||
"preview": "node build/index.js --preview",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||
"test:ci": "npm run lint && npm run test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.18.1",
|
||||
"core-js": "3.6.5",
|
||||
"easy-circular-progress": "1.0.4",
|
||||
"echarts": "^4.2.1",
|
||||
"element-ui": "2.13.2",
|
||||
"js-cookie": "2.2.0",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"vertx3-eventbus-client": "^3.9.4",
|
||||
"vue": "2.6.10",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"vue-json-viewer": "^2.2.18",
|
||||
"vue-router": "3.0.6",
|
||||
"vuex": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.4.4",
|
||||
"@vue/cli-plugin-eslint": "4.4.4",
|
||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
||||
"@vue/cli-service": "4.4.4",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"autoprefixer": "9.5.1",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "23.6.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"chalk": "2.4.2",
|
||||
"connect": "3.6.6",
|
||||
"eslint": "6.7.2",
|
||||
"eslint-plugin-vue": "6.2.2",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"runjs": "4.3.2",
|
||||
"sass": "1.26.8",
|
||||
"sass-loader": "8.0.2",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"serve-static": "1.13.2",
|
||||
"vue-template-compiler": "2.6.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.9",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
'plugins': {
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
'autoprefixer': {}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 17 KiB |
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= webpackConfig.name %></title>
|
||||
<script type="text/javascript" src="./ipconfig.js" async></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
@ -1,5 +0,0 @@
|
||||
//参数配置: 域名:端口 或者 IP:端口
|
||||
|
||||
window.g = {
|
||||
Base_URL: 'http://127.0.0.1:8089',
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
@ -1,40 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function faceDetectionForImageUrl(data) {
|
||||
return request({
|
||||
url: '/face/faceDetectionForImageUrl',
|
||||
method: 'get',
|
||||
params: {
|
||||
url: data.url
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function featureForImageUrl(data) {
|
||||
return request({
|
||||
url: '/face/featureForImageUrl',
|
||||
method: 'get',
|
||||
params: {
|
||||
url: data.url
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function compareForImageUrls(data) {
|
||||
return request({
|
||||
url: '/face/compareForImageUrls',
|
||||
method: 'get',
|
||||
params: {
|
||||
url1: data.url1,
|
||||
url2: data.url2
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function compareForImageFiles(data) {
|
||||
return request({
|
||||
url: '/face/compareForImageFiles',
|
||||
method: 'post',// PUT
|
||||
data
|
||||
})
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function infoForImageUrl(data) {
|
||||
return request({
|
||||
url: '/ocr/infoForImageUrl',
|
||||
method: 'get',
|
||||
params: {
|
||||
url: data.url
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function generalInfoForImageUrl(data) {
|
||||
return request({
|
||||
url: '/ocr/generalInfoForImageUrl',
|
||||
method: 'get',
|
||||
params: {
|
||||
url: data.url
|
||||
}
|
||||
})
|
||||
}
|
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 4.7 KiB |
@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
// only show routes with meta.title
|
||||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
||||
const first = matched[0]
|
||||
|
||||
if (!this.isDashboard(first)) {
|
||||
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
|
||||
}
|
||||
|
||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
},
|
||||
isDashboard(route) {
|
||||
const name = route && route.name
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg
|
||||
:class="{'is-active':isActive}"
|
||||
class="hamburger"
|
||||
viewBox="0 0 1024 1024"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="64"
|
||||
height="64"
|
||||
>
|
||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleClick() {
|
||||
this.$emit('toggleClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover!important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<router-view :key="key" />
|
||||
</transition>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppMain',
|
||||
computed: {
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
/*50 = navbar */
|
||||
min-height: calc(100vh - 50px);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,111 +0,0 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Hamburger
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar',
|
||||
'avatar'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 30px;
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.el-icon-caret-bottom {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,26 +0,0 @@
|
||||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
this.fixBugIniOS()
|
||||
},
|
||||
methods: {
|
||||
fixBugIniOS() {
|
||||
const $subMenu = this.$refs.subMenu
|
||||
if ($subMenu) {
|
||||
const handleMouseleave = $subMenu.handleMouseleave
|
||||
$subMenu.handleMouseleave = (e) => {
|
||||
if (this.device === 'mobile') {
|
||||
return
|
||||
}
|
||||
handleMouseleave(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'MenuItem',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
if (icon.includes('el-icon')) {
|
||||
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
||||
} else {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sub-el-icon {
|
||||
color: currentColor;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
</style>
|
@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<component :is="type" v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.to)
|
||||
},
|
||||
type() {
|
||||
if (this.isExternal) {
|
||||
return 'a'
|
||||
}
|
||||
return 'router-link'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(to) {
|
||||
if (this.isExternal) {
|
||||
return {
|
||||
href: to,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
to: to
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
|
||||
<transition name="sidebarLogoFade">
|
||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
||||
<h1 v-else class="sidebar-title">{{ title }} </h1>
|
||||
</router-link>
|
||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
||||
<h1 class="sidebar-title">{{ title }} </h1>
|
||||
</router-link>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SidebarLogo',
|
||||
props: {
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'OCR'
|
||||
// logo: 'https://djl.ai/website/img/djl-middle.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebarLogoFade-enter-active {
|
||||
transition: opacity 1.5s;
|
||||
}
|
||||
|
||||
.sidebarLogoFade-enter,
|
||||
.sidebarLogoFade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: #2b2f3a;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
& .sidebar-logo-link {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
& .sidebar-logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
& .sidebar-title {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapse {
|
||||
.sidebar-logo {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,95 +0,0 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
|
||||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
|
||||
<template slot="title">
|
||||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:is-nest="true"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import path from 'path'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
|
||||
// TODO: refactor with render function
|
||||
this.onlyOneChild = null
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChild(children = [], parent) {
|
||||
const showingChildren = children.filter(item => {
|
||||
if (item.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// Temp set(will be used if only has one showing child)
|
||||
this.onlyOneChild = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
// When there is only one child router, the child router is displayed by default
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
if (showingChildren.length === 0) {
|
||||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (isExternal(this.basePath)) {
|
||||
return this.basePath
|
||||
}
|
||||
return path.resolve(this.basePath, routePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<div :class="{'has-logo':showLogo}">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:unique-opened="false"
|
||||
:active-text-color="variables.menuActiveText"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
>
|
||||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Logo from './Logo'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import variables from '@/styles/variables.scss'
|
||||
|
||||
export default {
|
||||
components: { SidebarItem, Logo },
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
]),
|
||||
routes() {
|
||||
return this.$router.options.routes
|
||||
},
|
||||
activeMenu() {
|
||||
const route = this.$route
|
||||
const { meta, path } = route
|
||||
// if set path, the sidebar will highlight the path you set
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu
|
||||
}
|
||||
return path
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo
|
||||
},
|
||||
variables() {
|
||||
return variables
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,3 +0,0 @@
|
||||
export { default as Navbar } from './Navbar'
|
||||
export { default as Sidebar } from './Sidebar'
|
||||
export { default as AppMain } from './AppMain'
|
@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<div :class="classObj" class="app-wrapper">
|
||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||
<sidebar class="sidebar-container" />
|
||||
<div class="main-container">
|
||||
<div :class="{'fixed-header':fixedHeader}">
|
||||
<navbar />
|
||||
</div>
|
||||
<app-main />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Navbar, Sidebar, AppMain } from './components'
|
||||
import ResizeMixin from './mixin/ResizeHandler'
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
components: {
|
||||
Navbar,
|
||||
Sidebar,
|
||||
AppMain
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
computed: {
|
||||
sidebar() {
|
||||
return this.$store.state.app.sidebar
|
||||
},
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
},
|
||||
fixedHeader() {
|
||||
return this.$store.state.settings.fixedHeader
|
||||
},
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === 'mobile'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/mixin.scss";
|
||||
@import "~@/styles/variables.scss";
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&.mobile.openSidebar{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: calc(100% - #{$sideBarWidth});
|
||||
transition: width 0.28s;
|
||||
}
|
||||
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px)
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -1,45 +0,0 @@
|
||||
import store from '@/store'
|
||||
|
||||
const { body } = document
|
||||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
||||
|
||||
export default {
|
||||
watch: {
|
||||
$route(route) {
|
||||
if (this.device === 'mobile' && this.sidebar.opened) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
mounted() {
|
||||
const isMobile = this.$_isMobile()
|
||||
if (isMobile) {
|
||||
store.dispatch('app/toggleDevice', 'mobile')
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_isMobile() {
|
||||
const rect = body.getBoundingClientRect()
|
||||
return rect.width - 1 < WIDTH
|
||||
},
|
||||
$_resizeHandler() {
|
||||
if (!document.hidden) {
|
||||
const isMobile = this.$_isMobile()
|
||||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
|
||||
|
||||
if (isMobile) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||
|
||||
import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
||||
|
||||
import '@/styles/index.scss' // global css
|
||||
|
||||
import App from './App'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
|
||||
import '@/permission' // permission control
|
||||
|
||||
// set ElementUI lang to EN
|
||||
Vue.use(ElementUI, { locale })
|
||||
// 如果想要中文版 element-ui,按如下方式声明
|
||||
// To use the Chinese version of element-ui, declare as follows
|
||||
// Vue.use(ElementUI)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
})
|
@ -1,27 +0,0 @@
|
||||
import router from './router'
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import getPageTitle from '@/utils/get-page-title'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
// start progress bar
|
||||
NProgress.start()
|
||||
|
||||
// set page title
|
||||
document.title = getPageTitle(to.meta.title)
|
||||
|
||||
if (to.path === '/login') {
|
||||
// if is logged in, redirect to the home page
|
||||
next({ path: '/' })
|
||||
NProgress.done()
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
// finish progress bar
|
||||
NProgress.done()
|
||||
})
|
@ -1,105 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
/* Layout */
|
||||
import Layout from '@/layout'
|
||||
|
||||
/**
|
||||
* Note: sub-menu only appear when route children.length >= 1
|
||||
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
||||
*
|
||||
* hidden: true if set true, item will not show in the sidebar(default is false)
|
||||
* alwaysShow: true if set true, will always show the root menu
|
||||
* if not set alwaysShow, when item has more than one children route,
|
||||
* it will becomes nested mode, otherwise not show the root menu
|
||||
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
|
||||
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
||||
* meta : {
|
||||
roles: ['admin','editor'] control the page roles (you can set multiple roles)
|
||||
title: 'title' the name show in sidebar and breadcrumb (recommend set)
|
||||
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
|
||||
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
|
||||
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* constantRoutes
|
||||
* a base page that does not have permission requirements
|
||||
* all roles can be accessed
|
||||
*/
|
||||
export const constantRoutes = [
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/404'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/ocr/index'),
|
||||
name: 'inference',
|
||||
meta: { title: 'Free Text', icon: 'el-icon-picture' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/detection',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: 'detection',
|
||||
component: () => import('@/views/face/detection'),
|
||||
name: 'detection',
|
||||
meta: { title: 'Face Detection', icon: 'el-icon-picture' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/feature',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: 'feature',
|
||||
component: () => import('@/views/face/feature'),
|
||||
name: 'feature',
|
||||
meta: { title: 'Face Feature', icon: 'el-icon-picture' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/comparison',
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: 'comparison',
|
||||
component: () => import('@/views/face/comparison'),
|
||||
name: 'comparison',
|
||||
meta: { title: 'Face Comparison (1:1)', icon: 'el-icon-picture' }
|
||||
}
|
||||
]
|
||||
},
|
||||
// 404 page must be placed at the end !!!
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
const createRouter = () => new Router({
|
||||
// mode: 'history', // require service support
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes
|
||||
})
|
||||
|
||||
const router = createRouter()
|
||||
|
||||
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
|
||||
export function resetRouter() {
|
||||
const newRouter = createRouter()
|
||||
router.matcher = newRouter.matcher // reset router
|
||||
}
|
||||
|
||||
export default router
|
@ -1,16 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
title: 'OCR UI',
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
* @description Whether fix the header
|
||||
*/
|
||||
fixedHeader: false,
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
* @description Whether show the logo in sidebar
|
||||
*/
|
||||
sidebarLogo: false
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name
|
||||
}
|
||||
export default getters
|
@ -1,17 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import getters from './getters'
|
||||
import app from './modules/app'
|
||||
import settings from './modules/settings'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
app,
|
||||
settings
|
||||
},
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
@ -1,48 +0,0 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const state = {
|
||||
sidebar: {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop'
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
TOGGLE_SIDEBAR: state => {
|
||||
state.sidebar.opened = !state.sidebar.opened
|
||||
state.sidebar.withoutAnimation = false
|
||||
if (state.sidebar.opened) {
|
||||
Cookies.set('sidebarStatus', 1)
|
||||
} else {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
}
|
||||
},
|
||||
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
state.sidebar.opened = false
|
||||
state.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
toggleSideBar({ commit }) {
|
||||
commit('TOGGLE_SIDEBAR')
|
||||
},
|
||||
closeSideBar({ commit }, { withoutAnimation }) {
|
||||
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||
},
|
||||
toggleDevice({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const { showSettings, fixedHeader, sidebarLogo } = defaultSettings
|
||||
|
||||
const state = {
|
||||
showSettings: showSettings,
|
||||
fixedHeader: fixedHeader,
|
||||
sidebarLogo: sidebarLogo
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
CHANGE_SETTING: (state, { key, value }) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (state.hasOwnProperty(key)) {
|
||||
state[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
changeSetting({ commit }, data) {
|
||||
commit('CHANGE_SETTING', data)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
// cover some element-ui styles
|
||||
|
||||
.el-breadcrumb__inner,
|
||||
.el-breadcrumb__inner a {
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.el-upload {
|
||||
input[type="file"] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
// to fixed https://github.com/ElemeFE/element/issues/2461
|
||||
.el-dialog {
|
||||
transform: none;
|
||||
left: 0;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// refine element ui upload
|
||||
.upload-container {
|
||||
.el-upload {
|
||||
width: 100%;
|
||||
|
||||
.el-upload-dragger {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropdown
|
||||
.el-dropdown-menu {
|
||||
a {
|
||||
display: block
|
||||
}
|
||||
}
|
||||
|
||||
// to fix el-date-picker css style
|
||||
.el-range-separator {
|
||||
box-sizing: content-box;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
@import './variables.scss';
|
||||
@import './mixin.scss';
|
||||
@import './transition.scss';
|
||||
@import './element-ui.scss';
|
||||
@import './sidebar.scss';
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
a:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
&:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// main-container global css
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
@mixin clearfix {
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scrollBar {
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin relative {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
#app {
|
||||
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
transition: margin-left .28s;
|
||||
margin-left: $sideBarWidth;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: width 0.28s;
|
||||
width: $sideBarWidth !important;
|
||||
background-color: $menuBg;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
font-size: 0px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
|
||||
// reset element-ui css
|
||||
.horizontal-collapse-transition {
|
||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
||||
}
|
||||
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.el-scrollbar__bar.is-vertical {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.has-logo {
|
||||
.el-scrollbar {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.sub-el-icon {
|
||||
margin-right: 12px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
// menu hover
|
||||
.submenu-title-noDropdown,
|
||||
.el-submenu__title {
|
||||
&:hover {
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
.is-active>.el-submenu__title {
|
||||
color: $subMenuActiveText !important;
|
||||
}
|
||||
|
||||
& .nest-menu .el-submenu>.el-submenu__title,
|
||||
& .el-submenu .el-menu-item {
|
||||
min-width: $sideBarWidth !important;
|
||||
background-color: $subMenuBg !important;
|
||||
|
||||
&:hover {
|
||||
background-color: $subMenuHover !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hideSidebar {
|
||||
.sidebar-container {
|
||||
width: 54px !important;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
margin-left: 54px;
|
||||
}
|
||||
|
||||
.submenu-title-noDropdown {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
|
||||
.el-tooltip {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.sub-el-icon {
|
||||
margin-left: 19px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-submenu {
|
||||
overflow: hidden;
|
||||
|
||||
&>.el-submenu__title {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.sub-el-icon {
|
||||
margin-left: 19px;
|
||||
}
|
||||
|
||||
.el-submenu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse {
|
||||
.el-submenu {
|
||||
&>.el-submenu__title {
|
||||
&>span {
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse .el-menu .el-submenu {
|
||||
min-width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
// mobile responsive
|
||||
.mobile {
|
||||
.main-container {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: transform .28s;
|
||||
width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
&.hideSidebar {
|
||||
.sidebar-container {
|
||||
pointer-events: none;
|
||||
transition-duration: 0.3s;
|
||||
transform: translate3d(-$sideBarWidth, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.withoutAnimation {
|
||||
|
||||
.main-container,
|
||||
.sidebar-container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when menu collapsed
|
||||
.el-menu--vertical {
|
||||
&>.el-menu {
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
.sub-el-icon {
|
||||
margin-right: 12px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.nest-menu .el-submenu>.el-submenu__title,
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// you can use $subMenuHover
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
// the scroll bar appears when the subMenu is too long
|
||||
>.el-menu--popup {
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// global transition css
|
||||
|
||||
/* fade */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.28s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* fade-transform */
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
/* breadcrumb transition */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-leave-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-enter,
|
||||
.breadcrumb-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.breadcrumb-move {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
position: absolute;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// sidebar
|
||||
$menuText:#bfcbd9;
|
||||
$menuActiveText:#409EFF;
|
||||
$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
|
||||
|
||||
$menuBg:#304156;
|
||||
$menuHover:#263445;
|
||||
|
||||
$subMenuBg:#1f2d3d;
|
||||
$subMenuHover:#001528;
|
||||
|
||||
$sideBarWidth: 210px;
|
||||
|
||||
// the :export directive is the magic sauce for webpack
|
||||
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
|
||||
:export {
|
||||
menuText: $menuText;
|
||||
menuActiveText: $menuActiveText;
|
||||
subMenuActiveText: $subMenuActiveText;
|
||||
menuBg: $menuBg;
|
||||
menuHover: $menuHover;
|
||||
subMenuBg: $subMenuBg;
|
||||
subMenuHover: $subMenuHover;
|
||||
sideBarWidth: $sideBarWidth;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const title = defaultSettings.title || 'Vue Admin Template'
|
||||
|
||||
export default function getPageTitle(pageTitle) {
|
||||
if (pageTitle) {
|
||||
return `${pageTitle} - ${title}`
|
||||
}
|
||||
return `${title}`
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/**
|
||||
* Created by PanJiaChen on 16/11/18.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} cFormat
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0 || !time) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if ((typeof time === 'string')) {
|
||||
if ((/^[0-9]+$/.test(time))) {
|
||||
// support "1548221490638"
|
||||
time = parseInt(time)
|
||||
} else {
|
||||
// support safari
|
||||
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
|
||||
time = time.replace(new RegExp(/-/gm), '/')
|
||||
}
|
||||
}
|
||||
|
||||
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
|
||||
const value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
||||
return value.toString().padStart(2, '0')
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} time
|
||||
* @param {string} option
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatTime(time, option) {
|
||||
if (('' + time).length === 10) {
|
||||
time = parseInt(time) * 1000
|
||||
} else {
|
||||
time = +time
|
||||
}
|
||||
const d = new Date(time)
|
||||
const now = Date.now()
|
||||
|
||||
const diff = (now - d) / 1000
|
||||
|
||||
if (diff < 30) {
|
||||
return '刚刚'
|
||||
} else if (diff < 3600) {
|
||||
// less 1 hour
|
||||
return Math.ceil(diff / 60) + '分钟前'
|
||||
} else if (diff < 3600 * 24) {
|
||||
return Math.ceil(diff / 3600) + '小时前'
|
||||
} else if (diff < 3600 * 24 * 2) {
|
||||
return '1天前'
|
||||
}
|
||||
if (option) {
|
||||
return parseTime(time, option)
|
||||
} else {
|
||||
return (
|
||||
d.getMonth() +
|
||||
1 +
|
||||
'月' +
|
||||
d.getDate() +
|
||||
'日' +
|
||||
d.getHours() +
|
||||
'时' +
|
||||
d.getMinutes() +
|
||||
'分'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function param2Obj(url) {
|
||||
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
||||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
const obj = {}
|
||||
const searchArr = search.split('&')
|
||||
searchArr.forEach(v => {
|
||||
const index = v.indexOf('=')
|
||||
if (index !== -1) {
|
||||
const name = v.substring(0, index)
|
||||
const val = v.substring(index + 1, v.length)
|
||||
obj[name] = val
|
||||
}
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
export function debounce(func, wait, immediate) {
|
||||
let timeout, args, context, timestamp, result
|
||||
|
||||
const later = function() {
|
||||
const last = +new Date() - timestamp
|
||||
if (last < wait && last > 0) {
|
||||
timeout = setTimeout(later, wait - last)
|
||||
} else {
|
||||
timeout = null
|
||||
if (!immediate) {
|
||||
result = func.apply(context, args)
|
||||
if (!timeout) context = args = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function(...args) {
|
||||
context = this
|
||||
timestamp = +new Date()
|
||||
const callNow = immediate && !timeout
|
||||
if (!timeout) timeout = setTimeout(later, wait)
|
||||
if (callNow) {
|
||||
result = func.apply(context, args)
|
||||
context = args = null
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import { MessageBox, Message } from 'element-ui'
|
||||
import store from '@/store'
|
||||
// import { BaseURL } from '../../public/config'
|
||||
|
||||
// create an axios instance
|
||||
const baseURL = window.g.Base_URL
|
||||
const service = axios.create({
|
||||
baseURL: baseURL
|
||||
// baseURL: process.env.VUE_APP_BASE_API // url = base url + request url
|
||||
// withCredentials: true, // send cookies when cross-domain requests
|
||||
// timeout: 5000 // request timeout
|
||||
})
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// do something before request is sent
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
console.log(error) // for debug
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
/**
|
||||
* If you want to get http information such as headers or status
|
||||
* Please return response => response
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determine the request status by custom code
|
||||
* Here is just an example
|
||||
* You can also judge the status by HTTP Status Code
|
||||
*/
|
||||
response => {
|
||||
const res = response.data
|
||||
|
||||
// if the custom code is not 20000, it is judged as an error.
|
||||
if (res.code !== 0) {
|
||||
Message({
|
||||
message: res.message || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
|
||||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
||||
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
|
||||
// to re-login
|
||||
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
|
||||
confirmButtonText: 'Re-Login',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
store.dispatch('user/resetToken').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
}
|
||||
return Promise.reject(new Error(res.message || 'Error'))
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error) // for debug
|
||||
Message({
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function validUsername(str) {
|
||||
const valid_map = ['admin', 'editor']
|
||||
return valid_map.indexOf(str.trim()) >= 0
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404">
|
||||
<div class="pic-404">
|
||||
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
|
||||
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
<div class="bullshit__info">All rights reserved
|
||||
<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
|
||||
</div>
|
||||
<div class="bullshit__headline">{{ message }}</div>
|
||||
<div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>
|
||||
<a href="" class="bullshit__return-home">Back to home</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'Page404',
|
||||
computed: {
|
||||
message() {
|
||||
return 'The webmaster said that you can not enter this page...'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wscn-http404-container{
|
||||
transform: translate(-50%,-50%);
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
}
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 600px;
|
||||
overflow: hidden;
|
||||
&__parent {
|
||||
width: 100%;
|
||||
}
|
||||
&__child {
|
||||
position: absolute;
|
||||
&.left {
|
||||
width: 80px;
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
animation-name: cloudLeft;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
&.mid {
|
||||
width: 46px;
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
animation-name: cloudMid;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
&.right {
|
||||
width: 62px;
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
animation-name: cloudRight;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
@keyframes cloudLeft {
|
||||
0% {
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 33px;
|
||||
left: 188px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 81px;
|
||||
left: 92px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 97px;
|
||||
left: 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudMid {
|
||||
0% {
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 40px;
|
||||
left: 360px;
|
||||
opacity: 1;
|
||||
}
|
||||
70% {
|
||||
top: 130px;
|
||||
left: 180px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 160px;
|
||||
left: 120px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudRight {
|
||||
0% {
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 120px;
|
||||
left: 460px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 180px;
|
||||
left: 340px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 200px;
|
||||
left: 300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bullshit {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 300px;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
&__oops {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
color: #1482f0;
|
||||
opacity: 0;
|
||||
margin-bottom: 20px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__headline {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
margin-bottom: 10px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.1s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__info {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
color: grey;
|
||||
opacity: 0;
|
||||
margin-bottom: 30px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__return-home {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background: #1482f0;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
opacity: 0;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,198 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="form" :model="form" label-width="120">
|
||||
<el-form-item label="Image1">
|
||||
<el-input v-model="form.url1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Image2">
|
||||
<el-input v-model="form.url2" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="9">
|
||||
<el-form-item>
|
||||
<img :src="form.url1" width="200px">
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<img :src="form.url2" width="200px">
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result1"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
type="primary"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="onSubmit"
|
||||
>Compare</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-divider />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<div><img :src="form.base64Img1" width="200px" class="avatar"></div>
|
||||
<div><img :src="form.base64Img2" width="200px" class="avatar"></div>
|
||||
<el-form-item label="Local Image">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
name="imageFiles"
|
||||
class="upload"
|
||||
:on-preview="handlePreview"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="beforeUpload"
|
||||
:file-list="fileList"
|
||||
:http-request="uploadFile"
|
||||
::limit="2"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">Select</el-button>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
style="margin-left: 10px;"
|
||||
type="success"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="submitUpload"
|
||||
>Upload</el-button>
|
||||
<div slot="tip" class="el-upload__tip">Image format: JPG(JPEG), PNG</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result2"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { compareForImageUrls, compareForImageFiles } from '@/api/face'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
export default {
|
||||
name: 'Feature',
|
||||
components: {
|
||||
JsonViewer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreenLoading: false,
|
||||
file: [],
|
||||
fileList: [], // upload file list
|
||||
form: {
|
||||
url1: 'https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/face_sdk/images/kana1.jpg',
|
||||
url2: 'https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/face_sdk/images/kana2.jpg',
|
||||
result1: '',
|
||||
result2: '',
|
||||
base64Img: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
return window.g.Base_URL + '/face/compareForImageFiles'
|
||||
// return `${process.env.VUE_APP_BASE_API}/inference/infoForImageFile`
|
||||
},
|
||||
uploadFile(param) {
|
||||
this.file.push(param.file)
|
||||
},
|
||||
submitUpload() {
|
||||
// this.$refs.upload.submit()
|
||||
if (this.fileList.length !== 2) {
|
||||
this.$message({
|
||||
message: 'Please select 2 images',
|
||||
type: 'warning'
|
||||
})
|
||||
} else {
|
||||
this.fullscreenLoading = true
|
||||
const formData = new FormData() // new formData
|
||||
this.$refs.upload.submit()
|
||||
this.file.forEach(function(file) {
|
||||
formData.append('imageFiles', file, file.name)
|
||||
// upData.append('file', this.file);
|
||||
})
|
||||
compareForImageFiles(formData).then(response => {
|
||||
this.form.base64Img1 = response.data.base64Img1
|
||||
this.form.base64Img2 = response.data.base64Img2
|
||||
this.form.result2 = response.data.result
|
||||
this.fullscreenLoading = false
|
||||
this.fileList = []
|
||||
})
|
||||
}
|
||||
},
|
||||
// 移除 - remove
|
||||
handleRemove(file, fileList) {
|
||||
this.fileList = fileList
|
||||
// return this.$confirm(`Confirm remove ${ file.name }?`);
|
||||
},
|
||||
|
||||
// 选取文件超过数量提示 - file number
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.warning(`only 2 files permitted`)
|
||||
},
|
||||
// 监控上传文件列表 - monitor file list
|
||||
handleChange(file, fileList) {
|
||||
const existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
|
||||
if (existFile) {
|
||||
this.$message.error('file existing!')
|
||||
fileList.pop()
|
||||
}
|
||||
this.fileList = fileList
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file)
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const pass = file.type === 'image/jpg' || 'image/jpeg' || 'image/png'
|
||||
if (!pass) {
|
||||
this.$message.error('Image format should be JPG(JPEG) or PNG!')
|
||||
}
|
||||
return pass
|
||||
},
|
||||
onSubmit() {
|
||||
this.fullscreenLoading = true
|
||||
compareForImageUrls(this.form).then(response => {
|
||||
this.fullscreenLoading = false
|
||||
this.form.result1 = response.data.result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-input {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.input-with-select .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.line {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="form" :model="form" label-width="120">
|
||||
<el-form-item label="Online Image">
|
||||
<el-input v-model="form.url" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="9">
|
||||
<el-form-item>
|
||||
<img :src="form.url" width="400px">
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result1"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
type="primary"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="onSubmit"
|
||||
>Detect</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-divider />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<div><img :src="form.base64Img" width="400px" class="avatar"></div>
|
||||
<el-form-item label="Local Image">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
name="imageFile"
|
||||
class="upload"
|
||||
:action="upload()"
|
||||
:on-preview="handlePreview"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
::limit="1"
|
||||
:show-file-list="false"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">Select</el-button>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
style="margin-left: 10px;"
|
||||
type="success"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="submitUpload"
|
||||
>Upload</el-button>
|
||||
<div slot="tip" class="el-upload__tip">Image format: JPG(JPEG), PNG</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result2"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { faceDetectionForImageUrl } from '@/api/face'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
export default {
|
||||
name: 'InferenceDetail',
|
||||
components: {
|
||||
JsonViewer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreenLoading: false,
|
||||
form: {
|
||||
url: 'https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/face_sdk/images/beauty.jpg',
|
||||
result1: '',
|
||||
result2: '',
|
||||
base64Img: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
return window.g.Base_URL + '/face/faceDetectionForImageFile'
|
||||
// return `${process.env.VUE_APP_BASE_API}/inference/infoForImageFile`
|
||||
},
|
||||
submitUpload() {
|
||||
this.fullscreenLoading = true
|
||||
this.$refs.upload.submit()
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
console.log(file, fileList)
|
||||
},
|
||||
handleChange(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handleSuccess(file) {
|
||||
this.form.base64Img = file.data.base64Img
|
||||
this.form.result2 = file.data.result
|
||||
this.fullscreenLoading = false
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const pass = file.type === 'image/jpg' || 'image/jpeg' || 'image/png'
|
||||
if (!pass) {
|
||||
this.$message.error('Image format should be JPG(JPEG) or PNG!')
|
||||
}
|
||||
return pass
|
||||
},
|
||||
onSubmit() {
|
||||
this.fullscreenLoading = true
|
||||
faceDetectionForImageUrl(this.form).then(response => {
|
||||
this.fullscreenLoading = false
|
||||
this.form.result1 = response.data.result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-input {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.input-with-select .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.line {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="form" :model="form" label-width="120">
|
||||
<el-form-item label="Online Image">
|
||||
<el-input v-model="form.url" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="9">
|
||||
<el-form-item>
|
||||
<img :src="form.url" width="400px">
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result1"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
type="primary"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="onSubmit"
|
||||
>Extract</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-divider />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<div><img :src="form.base64Img" width="400px" class="avatar"></div>
|
||||
<el-form-item label="Local Image">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
name="imageFile"
|
||||
class="upload"
|
||||
:action="upload()"
|
||||
:on-preview="handlePreview"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
::limit="1"
|
||||
:show-file-list="false"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">Select</el-button>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
style="margin-left: 10px;"
|
||||
type="success"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="submitUpload"
|
||||
>Upload</el-button>
|
||||
<div slot="tip" class="el-upload__tip">Image format: JPG(JPEG), PNG</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result2"
|
||||
:expand-depth="4"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { featureForImageUrl } from '@/api/face'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
export default {
|
||||
name: 'Feature',
|
||||
components: {
|
||||
JsonViewer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreenLoading: false,
|
||||
form: {
|
||||
url: 'https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/face_sdk/images/kana1.jpg',
|
||||
result1: '',
|
||||
result2: '',
|
||||
base64Img: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
return window.g.Base_URL + '/face/featureForImageFile'
|
||||
// return `${process.env.VUE_APP_BASE_API}/inference/infoForImageFile`
|
||||
},
|
||||
submitUpload() {
|
||||
this.fullscreenLoading = true
|
||||
this.$refs.upload.submit()
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
console.log(file, fileList)
|
||||
},
|
||||
handleChange(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handleSuccess(file) {
|
||||
this.form.base64Img = file.data.base64Img
|
||||
this.form.result2 = file.data.result
|
||||
this.fullscreenLoading = false
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const pass = file.type === 'image/jpg' || 'image/jpeg' || 'image/png'
|
||||
if (!pass) {
|
||||
this.$message.error('Image format should be JPG(JPEG) or PNG!')
|
||||
}
|
||||
return pass
|
||||
},
|
||||
onSubmit() {
|
||||
this.fullscreenLoading = true
|
||||
featureForImageUrl(this.form).then(response => {
|
||||
this.fullscreenLoading = false
|
||||
this.form.result1 = response.data.result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-input {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.input-with-select .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.line {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="form" :model="form" label-width="120">
|
||||
<el-form-item label="Online Image">
|
||||
<el-input v-model="form.url" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="9">
|
||||
<el-form-item>
|
||||
<img :src="form.url" width="400px">
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result1"
|
||||
:expand-depth="3"
|
||||
copyable
|
||||
width="400px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
type="primary"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="onSubmit"
|
||||
>Submit</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-divider />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="9">
|
||||
<div><img :src="form.base64Img" width="400px" class="avatar"></div>
|
||||
<el-form-item label="Local Image">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
name="imageFile"
|
||||
class="upload"
|
||||
:action="upload()"
|
||||
:on-preview="handlePreview"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
::limit="1"
|
||||
:show-file-list="false"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">Select</el-button>
|
||||
<el-button
|
||||
v-loading.fullscreen.lock="fullscreenLoading"
|
||||
style="margin-left: 10px;"
|
||||
type="success"
|
||||
size="small"
|
||||
element-loading-text="loading"
|
||||
@click="submitUpload"
|
||||
>Upload</el-button>
|
||||
<div slot="tip" class="el-upload__tip">Image format: JPG(JPEG), PNG</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="">
|
||||
<json-viewer
|
||||
:value="form.result2"
|
||||
:expand-depth="3"
|
||||
copyable
|
||||
width="500px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { generalInfoForImageUrl } from '@/api/ocr'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
export default {
|
||||
name: 'InferenceDetail',
|
||||
components: {
|
||||
JsonViewer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreenLoading: false,
|
||||
form: {
|
||||
url: 'https://aias-home.oss-cn-beijing.aliyuncs.com/AIAS/OCR/images/freetxt.png',
|
||||
result1: '',
|
||||
result2: '',
|
||||
base64Img: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
return window.g.Base_URL + '/ocr/generalInfoForImageFile'
|
||||
// return `${process.env.VUE_APP_BASE_API}/inference/generalInfoForImageFile`
|
||||
},
|
||||
submitUpload() {
|
||||
this.fullscreenLoading = true
|
||||
this.$refs.upload.submit()
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
console.log(file, fileList)
|
||||
},
|
||||
handleChange(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file)
|
||||
},
|
||||
handleSuccess(file) {
|
||||
this.form.base64Img = file.data.base64Img
|
||||
this.form.result2 = file.data.result
|
||||
this.fullscreenLoading = false
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const pass = file.type === 'image/jpg' || 'image/jpeg' || 'image/png'
|
||||
if (!pass) {
|
||||
this.$message.error('Image format should be JPG(JPEG) or PNG!')
|
||||
}
|
||||
return pass
|
||||
},
|
||||
onSubmit() {
|
||||
this.fullscreenLoading = true
|
||||
generalInfoForImageUrl(this.form).then(response => {
|
||||
this.fullscreenLoading = false
|
||||
this.form.result1 = response.data.result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-input {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.input-with-select .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.line {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
jest: true
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
import { mount, createLocalVue } from '@vue/test-utils'
|
||||
import VueRouter from 'vue-router'
|
||||
import ElementUI from 'element-ui'
|
||||
import Breadcrumb from '@/components/Breadcrumb/index.vue'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
localVue.use(VueRouter)
|
||||
localVue.use(ElementUI)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
children: [{
|
||||
path: 'dashboard',
|
||||
name: 'dashboard'
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/menu',
|
||||
name: 'menu',
|
||||
children: [{
|
||||
path: 'menu1',
|
||||
name: 'menu1',
|
||||
meta: { title: 'menu1' },
|
||||
children: [{
|
||||
path: 'menu1-1',
|
||||
name: 'menu1-1',
|
||||
meta: { title: 'menu1-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2',
|
||||
name: 'menu1-2',
|
||||
redirect: 'noredirect',
|
||||
meta: { title: 'menu1-2' },
|
||||
children: [{
|
||||
path: 'menu1-2-1',
|
||||
name: 'menu1-2-1',
|
||||
meta: { title: 'menu1-2-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2-2',
|
||||
name: 'menu1-2-2'
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
|
||||
const router = new VueRouter({
|
||||
routes
|
||||
})
|
||||
|
||||
describe('Breadcrumb.vue', () => {
|
||||
const wrapper = mount(Breadcrumb, {
|
||||
localVue,
|
||||
router
|
||||
})
|
||||
it('dashboard', () => {
|
||||
router.push('/dashboard')
|
||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
||||
expect(len).toBe(1)
|
||||
})
|
||||
it('normal route', () => {
|
||||
router.push('/menu/menu1')
|
||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
||||
expect(len).toBe(2)
|
||||
})
|
||||
it('nested route', () => {
|
||||
router.push('/menu/menu1/menu1-2/menu1-2-1')
|
||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
||||
expect(len).toBe(4)
|
||||
})
|
||||
it('no meta.title', () => {
|
||||
router.push('/menu/menu1/menu1-2/menu1-2-2')
|
||||
const len = wrapper.findAll('.el-breadcrumb__inner').length
|
||||
expect(len).toBe(3)
|
||||
})
|
||||
// it('click link', () => {
|
||||
// router.push('/menu/menu1/menu1-2/menu1-2-2')
|
||||
// const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
||||
// const second = breadcrumbArray.at(1)
|
||||
// console.log(breadcrumbArray)
|
||||
// const href = second.find('a').attributes().href
|
||||
// expect(href).toBe('#/menu/menu1')
|
||||
// })
|
||||
// it('noRedirect', () => {
|
||||
// router.push('/menu/menu1/menu1-2/menu1-2-1')
|
||||
// const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
||||
// const redirectBreadcrumb = breadcrumbArray.at(2)
|
||||
// expect(redirectBreadcrumb.contains('a')).toBe(false)
|
||||
// })
|
||||
it('last breadcrumb', () => {
|
||||
router.push('/menu/menu1/menu1-2/menu1-2-1')
|
||||
const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
|
||||
const redirectBreadcrumb = breadcrumbArray.at(3)
|
||||
expect(redirectBreadcrumb.contains('a')).toBe(false)
|
||||
})
|
||||
})
|
@ -1,18 +0,0 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import Hamburger from '@/components/Hamburger/index.vue'
|
||||
describe('Hamburger.vue', () => {
|
||||
it('toggle click', () => {
|
||||
const wrapper = shallowMount(Hamburger)
|
||||
const mockFn = jest.fn()
|
||||
wrapper.vm.$on('toggleClick', mockFn)
|
||||
wrapper.find('.hamburger').trigger('click')
|
||||
expect(mockFn).toBeCalled()
|
||||
})
|
||||
it('prop isActive', () => {
|
||||
const wrapper = shallowMount(Hamburger)
|
||||
wrapper.setProps({ isActive: true })
|
||||
expect(wrapper.contains('.is-active')).toBe(true)
|
||||
wrapper.setProps({ isActive: false })
|
||||
expect(wrapper.contains('.is-active')).toBe(false)
|
||||
})
|
||||
})
|
@ -1,22 +0,0 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
||||
describe('SvgIcon.vue', () => {
|
||||
it('iconClass', () => {
|
||||
const wrapper = shallowMount(SvgIcon, {
|
||||
propsData: {
|
||||
iconClass: 'test'
|
||||
}
|
||||
})
|
||||
expect(wrapper.find('use').attributes().href).toBe('#icon-test')
|
||||
})
|
||||
it('className', () => {
|
||||
const wrapper = shallowMount(SvgIcon, {
|
||||
propsData: {
|
||||
iconClass: 'test'
|
||||
}
|
||||
})
|
||||
expect(wrapper.classes().length).toBe(1)
|
||||
wrapper.setProps({ className: 'test' })
|
||||
expect(wrapper.classes().includes('test')).toBe(true)
|
||||
})
|
||||
})
|
@ -1,30 +0,0 @@
|
||||
import { formatTime } from '@/utils/index.js'
|
||||
|
||||
describe('Utils:formatTime', () => {
|
||||
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
|
||||
const retrofit = 5 * 1000
|
||||
|
||||
it('ten digits timestamp', () => {
|
||||
expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
|
||||
})
|
||||
it('test now', () => {
|
||||
expect(formatTime(+new Date() - 1)).toBe('刚刚')
|
||||
})
|
||||
it('less two minute', () => {
|
||||
expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
|
||||
})
|
||||
it('less two hour', () => {
|
||||
expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
|
||||
})
|
||||
it('less one day', () => {
|
||||
expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
|
||||
})
|
||||
it('more than one day', () => {
|
||||
expect(formatTime(d)).toBe('7月13日17时54分')
|
||||
})
|
||||
it('format', () => {
|
||||
expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
|
||||
expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
|
||||
expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
|
||||
})
|
||||
})
|
@ -1,14 +0,0 @@
|
||||
import { param2Obj } from '@/utils/index.js'
|
||||
describe('Utils:param2Obj', () => {
|
||||
const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
|
||||
|
||||
it('param2Obj test', () => {
|
||||
expect(param2Obj(url)).toEqual({
|
||||
name: 'bill',
|
||||
age: '29',
|
||||
sex: '1',
|
||||
field: window.btoa('test'),
|
||||
key: '测试'
|
||||
})
|
||||
})
|
||||
})
|
@ -1,35 +0,0 @@
|
||||
import { parseTime } from '@/utils/index.js'
|
||||
|
||||
describe('Utils:parseTime', () => {
|
||||
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
|
||||
it('timestamp', () => {
|
||||
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
it('timestamp string', () => {
|
||||
expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
it('ten digits timestamp', () => {
|
||||
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
it('new Date', () => {
|
||||
expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
it('format', () => {
|
||||
expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
|
||||
expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
|
||||
expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
|
||||
})
|
||||
it('get the day of the week', () => {
|
||||
expect(parseTime(d, '{a}')).toBe('五') // 星期五
|
||||
})
|
||||
it('get the day of the week', () => {
|
||||
expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
|
||||
})
|
||||
it('empty argument', () => {
|
||||
expect(parseTime()).toBeNull()
|
||||
})
|
||||
|
||||
it('null', () => {
|
||||
expect(parseTime(null)).toBeNull()
|
||||
})
|
||||
})
|
@ -1,17 +0,0 @@
|
||||
import { validUsername, isExternal } from '@/utils/validate.js'
|
||||
|
||||
describe('Utils:validate', () => {
|
||||
it('validUsername', () => {
|
||||
expect(validUsername('admin')).toBe(true)
|
||||
expect(validUsername('editor')).toBe(true)
|
||||
expect(validUsername('xxxx')).toBe(false)
|
||||
})
|
||||
it('isExternal', () => {
|
||||
expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
|
||||
expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
|
||||
expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)
|
||||
expect(isExternal('/dashboard')).toBe(false)
|
||||
expect(isExternal('./dashboard')).toBe(false)
|
||||
expect(isExternal('dashboard')).toBe(false)
|
||||
})
|
||||
})
|
@ -1,121 +0,0 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const defaultSettings = require('./src/settings.js')
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
const name = defaultSettings.title || 'vue Admin Template' // page title
|
||||
|
||||
// If your port is set to 80,
|
||||
// use administrator privileges to execute the command line.
|
||||
// For example, Mac: sudo npm run
|
||||
// You can change the port by the following methods:
|
||||
// port = 8090 npm run dev OR npm run dev --port = 8090
|
||||
const port = process.env.port || process.env.npm_config_port || 8090 // dev port
|
||||
|
||||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
||||
module.exports = {
|
||||
/**
|
||||
* You will need to set publicPath if you plan to deploy your site under a sub path,
|
||||
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
||||
* then publicPath should be set to "/bar/".
|
||||
* In most cases please use '/' !!!
|
||||
* Detail: https://cli.vuejs.org/config/#publicpath
|
||||
*/
|
||||
publicPath: '/',
|
||||
outputDir: 'dist',
|
||||
assetsDir: 'static',
|
||||
lintOnSave: process.env.NODE_ENV === 'development',
|
||||
productionSourceMap: false,
|
||||
devServer: {
|
||||
port: port,
|
||||
open: true,
|
||||
overlay: {
|
||||
warnings: false,
|
||||
errors: true
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: process.env.VUE_APP_BASE_API,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': 'api'
|
||||
}
|
||||
},
|
||||
'/auth': {
|
||||
target: process.env.VUE_APP_BASE_API,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/auth': 'auth'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
configureWebpack: {
|
||||
// provide the app's title in webpack's name field, so that
|
||||
// it can be accessed in index.html to inject the correct title.
|
||||
name: name,
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve('src')
|
||||
}
|
||||
}
|
||||
},
|
||||
chainWebpack(config) {
|
||||
// it can improve the speed of the first screen, it is recommended to turn on preload
|
||||
config.plugin('preload').tap(() => [
|
||||
{
|
||||
rel: 'preload',
|
||||
// to ignore runtime.js
|
||||
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
|
||||
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
|
||||
include: 'initial'
|
||||
}
|
||||
])
|
||||
|
||||
// when there are many pages, it will cause too many meaningless requests
|
||||
config.plugins.delete('prefetch')
|
||||
|
||||
config
|
||||
.when(process.env.NODE_ENV !== 'development',
|
||||
config => {
|
||||
config
|
||||
.plugin('ScriptExtHtmlWebpackPlugin')
|
||||
.after('html')
|
||||
.use('script-ext-html-webpack-plugin', [{
|
||||
// `runtime` must same as runtimeChunk name. default is `runtime`
|
||||
inline: /runtime\..*\.js$/
|
||||
}])
|
||||
.end()
|
||||
config
|
||||
.optimization.splitChunks({
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
libs: {
|
||||
name: 'chunk-libs',
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: 10,
|
||||
chunks: 'initial' // only package third parties that are initially dependent
|
||||
},
|
||||
elementUI: {
|
||||
name: 'chunk-elementUI', // split elementUI into a single package
|
||||
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
|
||||
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
|
||||
},
|
||||
commons: {
|
||||
name: 'chunk-commons',
|
||||
test: resolve('src/components'), // can customize your rules
|
||||
minChunks: 3, // minimum common number
|
||||
priority: 5,
|
||||
reuseExistingChunk: true
|
||||
}
|
||||
}
|
||||
})
|
||||
// https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
|
||||
config.optimization.runtimeChunk('single')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="CheckStyle-IDEA-Module">
|
||||
<option name="configuration">
|
||||
<map />
|
||||
</option>
|
||||
</component>
|
||||
<component name="FacetManager">
|
||||
<facet type="Spring" name="Spring">
|
||||
<configuration />
|
||||
</facet>
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<webroots />
|
||||
<sourceRoots>
|
||||
<root url="file://$MODULE_DIR$/src/main/java" />
|
||||
<root url="file://$MODULE_DIR$/src/main/resources" />
|
||||
</sourceRoots>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.9.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.26" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.26" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.26" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.17.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.1.9.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.11.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.23.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.9.16" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.9.16" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.1.2.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.10.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.28" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.8.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl:api:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.21" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl:basicdataset:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-csv:1.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl:model-zoo:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-engine:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.mxnet:mxnet-native-auto:1.8.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-engine:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-native-auto:2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.paddlepaddle:paddlepaddle-model-zoo:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.pytorch:pytorch-engine:0.14.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: ai.djl.pytorch:pytorch-native-auto:1.9.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.http-client:google-http-client:1.19.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:1.3.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.12" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.70" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:guava:20.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.2.0.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.9.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.21" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.21" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
|
||||
</component>
|
||||
</module>
|
Before Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 122 KiB |
@ -1,60 +0,0 @@
|
||||
|
||||
#### Common Model Loading Methods
|
||||
|
||||
|
||||
1. How to load a model online via URL?
|
||||
```text
|
||||
# Use optModelUrls to load a model via URL
|
||||
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelUrls("https://aias-home.oss-cn-beijing.aliyuncs.com/models/ocr_models/ch_ppocr_mobile_v2.0_det_infer.zip")
|
||||
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
```
|
||||
|
||||
2. How to load a model locally?
|
||||
```text
|
||||
# Use optModelPath to load a model from a zipped file
|
||||
Path modelPath = Paths.get("src/test/resources/ch_ppocr_mobile_v2.0_det_infer.zip");
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelPath(modelPath)
|
||||
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
|
||||
# Use optModelPath to load a model from a local directory
|
||||
Path modelPath = Paths.get("src/test/resources/ch_ppocr_mobile_v2.0_det_infer/");
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelPath(modelPath)
|
||||
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
```
|
||||
|
||||
3. How to load a model packed into a JAR file?
|
||||
```text
|
||||
# Use optModelUrls to load a model
|
||||
# Assuming the model is located in the JAR file at:
|
||||
# BOOT-INF/classes/ch_ppocr_mobile_v2.0_det_infer.zip
|
||||
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelUrls("jar:///ch_ppocr_mobile_v2.0_det_infer.zip")
|
||||
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
```
|
||||
|
||||
|
286
7_engine_hub/api_platform/api-platform/mvnw
vendored
@ -1,286 +0,0 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
161
7_engine_hub/api_platform/api-platform/mvnw.cmd
vendored
@ -1,161 +0,0 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
@ -1,177 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.9.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>aias</groupId>
|
||||
<artifactId>api-platform</artifactId>
|
||||
<version>0.17.0</version>
|
||||
<description>AIAS API Platform Project</description>
|
||||
|
||||
<properties>
|
||||
<jna.version>5.6.0</jna.version>
|
||||
<djl.version>0.17.0</djl.version>
|
||||
<fastjson.version>1.2.70</fastjson.version>
|
||||
<swagger.version>2.9.2</swagger.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- apache commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>basicdataset</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.mxnet</groupId>
|
||||
<artifactId>mxnet-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.mxnet</groupId>
|
||||
<artifactId>mxnet-native-auto</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>${jna.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.paddlepaddle</groupId>
|
||||
<artifactId>paddlepaddle-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.paddlepaddle</groupId>
|
||||
<artifactId>paddlepaddle-model-zoo</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>${djl.version}</version>
|
||||
</dependency>
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<!-- Swagger UI -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>me.aias.MainApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,3 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: me.aias.MainApplication
|
||||
|
@ -1,13 +0,0 @@
|
||||
package me.aias;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MainApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MainApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
package me.aias.config;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* WebMvcConfigurer
|
||||
*
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class ConfigurerAdapter implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 文件配置
|
||||
* file configuration
|
||||
*/
|
||||
private final FileProperties properties;
|
||||
|
||||
public ConfigurerAdapter(FileProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOrigin("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
// 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
|
||||
// When using fastjson serialization, @JsonIgnore will be invalid. You can replace it with @JSONField(serialize = false)
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
List<MediaType> supportMediaTypeList = new ArrayList<>();
|
||||
supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
||||
converter.setFastJsonConfig(config);
|
||||
converter.setSupportedMediaTypes(supportMediaTypeList);
|
||||
converter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
converters.add(converter);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package me.aias.config;
|
||||
|
||||
import lombok.Data;
|
||||
import me.aias.utils.Constants;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "file")
|
||||
public class FileProperties {
|
||||
|
||||
/**
|
||||
* File size limitation
|
||||
*/
|
||||
private Long maxSize;
|
||||
|
||||
private ElPath mac;
|
||||
|
||||
private ElPath linux;
|
||||
|
||||
private ElPath windows;
|
||||
|
||||
public ElPath getPath() {
|
||||
String os = System.getProperty("os.name");
|
||||
if (os.toLowerCase().startsWith(Constants.WIN)) {
|
||||
return windows;
|
||||
} else if (os.toLowerCase().startsWith(Constants.MAC)) {
|
||||
return mac;
|
||||
}
|
||||
return linux;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ElPath {
|
||||
|
||||
private String path;
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package me.aias.config;
|
||||
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import me.aias.infer.face.FaceDetectionModel;
|
||||
import me.aias.infer.face.FaceFeatureModel;
|
||||
import me.aias.infer.ocr.RecognitionModel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Configuration
|
||||
public class ModelConfiguration {
|
||||
//Face Model
|
||||
@Value("${model.face.det}")
|
||||
private String faceDet;
|
||||
@Value("${model.face.feature}")
|
||||
private String feature;
|
||||
@Value("${model.face.topK}")
|
||||
private int topK;
|
||||
@Value("${model.face.confThresh}")
|
||||
private float confThresh;
|
||||
@Value("${model.face.nmsThresh}")
|
||||
private float nmsThresh;
|
||||
|
||||
//OCR Model
|
||||
@Value("${model.type}")
|
||||
private String type;
|
||||
// mobile model
|
||||
@Value("${model.mobile.det}")
|
||||
private String mobileDet;
|
||||
@Value("${model.mobile.rec}")
|
||||
private String mobileRec;
|
||||
// light model
|
||||
@Value("${model.light.det}")
|
||||
private String lightDet;
|
||||
@Value("${model.light.rec}")
|
||||
private String lightRec;
|
||||
// server model
|
||||
@Value("${model.server.det}")
|
||||
private String serverDet;
|
||||
@Value("${model.server.rec}")
|
||||
private String serverRec;
|
||||
|
||||
@Bean
|
||||
public RecognitionModel recognitionModel() throws IOException, ModelNotFoundException, MalformedModelException {
|
||||
RecognitionModel recognitionModel = new RecognitionModel();
|
||||
if (StringUtils.isEmpty(type) || type.toLowerCase().equals("mobile")) {
|
||||
recognitionModel.init(mobileDet, mobileRec);
|
||||
} else if (type.toLowerCase().equals("light")) {
|
||||
recognitionModel.init(lightDet, lightRec);
|
||||
} else if (type.toLowerCase().equals("server")) {
|
||||
recognitionModel.init(serverDet, serverRec);
|
||||
} else {
|
||||
recognitionModel.init(mobileDet, mobileRec);
|
||||
}
|
||||
return recognitionModel;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FaceDetectionModel faceDetectionModel() throws IOException, ModelNotFoundException, MalformedModelException {
|
||||
FaceDetectionModel faceDetectionModel = new FaceDetectionModel();
|
||||
faceDetectionModel.init(faceDet, topK, confThresh, nmsThresh);
|
||||
return faceDetectionModel;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FaceFeatureModel faceFeatureModel() throws IOException, ModelNotFoundException, MalformedModelException {
|
||||
FaceFeatureModel faceFeatureModel = new FaceFeatureModel();
|
||||
faceFeatureModel.init(feature);
|
||||
return faceFeatureModel;
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.aias.config;
|
||||
|
||||
import com.fasterxml.classmate.TypeResolver;
|
||||
import com.google.common.base.Predicates;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.schema.AlternateTypeRule;
|
||||
import springfox.documentation.schema.AlternateTypeRuleConvention;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static springfox.documentation.schema.AlternateTypeRules.newRule;
|
||||
|
||||
/**
|
||||
* api docs page /doc.html
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
|
||||
@Value("${swagger.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public Docket createRestApi() {
|
||||
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable(enabled)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.paths(Predicates.not(PathSelectors.regex("/error.*")))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.description("")
|
||||
.title("API Documentation")
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Pageable转换展示在swagger中
|
||||
* Convert Pageable to be displayed in Swagger
|
||||
*/
|
||||
@Configuration
|
||||
class SwaggerDataConfig {
|
||||
|
||||
@Bean
|
||||
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
|
||||
return new AlternateTypeRuleConvention() {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlternateTypeRule> rules() {
|
||||
return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ApiModel
|
||||
@Data
|
||||
private static class Page {
|
||||
@ApiModelProperty("Page number (0..N)")
|
||||
private Integer page;
|
||||
|
||||
@ApiModelProperty("Number of items per page")
|
||||
private Integer size;
|
||||
|
||||
@ApiModelProperty("Sorting criteria in the format: property[,asc|desc]. Default sort order is ascending. Supports multiple sort conditions, e.g.: id,asc")
|
||||
private List<String> sort;
|
||||
}
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
package me.aias.controller;
|
||||
|
||||
import ai.djl.ModelException;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import me.aias.domain.DataBean;
|
||||
import me.aias.domain.ResultBean;
|
||||
import me.aias.service.FaceService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Api(tags = "人脸识别 - Face Recognition")
|
||||
@RestController
|
||||
@RequestMapping("/face")
|
||||
public class FaceController {
|
||||
private Logger logger = LoggerFactory.getLogger(FaceController.class);
|
||||
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
|
||||
@ApiOperation(value = "人脸检测-URL - Face Detection - URL")
|
||||
@GetMapping(value = "/faceDetectionForImageUrl")
|
||||
public ResultBean generalInfoForImageUrl(@RequestParam(value = "url") String url) throws IOException {
|
||||
Image image = ImageFactory.getInstance().fromUrl(url);
|
||||
List<DataBean> dataList = faceService.detect(image);
|
||||
return ResultBean.success().add("result", dataList);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "人脸检测-图片 - Face Detection - Image")
|
||||
@PostMapping("/faceDetectionForImageFile")
|
||||
public ResultBean generalInfoForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
|
||||
InputStream fis = null;
|
||||
try {
|
||||
InputStream inputStream = imageFile.getInputStream();
|
||||
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
|
||||
|
||||
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
|
||||
List<DataBean> dataList = faceService.detect(image);
|
||||
|
||||
return ResultBean.success().add("result", dataList)
|
||||
.add("base64Img", "data:image/jpeg;base64," + base64Img);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("errors", e.getMessage());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "人脸特征提取-URL - Face Feature Extraction - URL")
|
||||
@GetMapping(value = "/featureForImageUrl")
|
||||
public ResultBean featureForImageUrl(@RequestParam(value = "url") String url) throws IOException {
|
||||
Image image = ImageFactory.getInstance().fromUrl(url);
|
||||
float[] feature = faceService.feature(image);
|
||||
return ResultBean.success().add("result", feature);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "人脸特征提取-图片 - Face Feature Extraction - Image")
|
||||
@PostMapping("/featureForImageFile")
|
||||
public ResultBean featureForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
|
||||
InputStream fis = null;
|
||||
try {
|
||||
InputStream inputStream = imageFile.getInputStream();
|
||||
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
|
||||
|
||||
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
|
||||
float[] feature = faceService.feature(image);
|
||||
|
||||
return ResultBean.success().add("result", feature)
|
||||
.add("base64Img", "data:image/jpeg;base64," + base64Img);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("errors", e.getMessage());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "人脸比对(1:1)-URL - Face Comparison (1:1) - URL")
|
||||
@GetMapping(value = "/compareForImageUrls")
|
||||
public ResultBean compareForImageUrls(@RequestParam(value = "url1") String url1, @RequestParam(value = "url2") String url2) throws IOException, ModelException, TranslateException {
|
||||
Image image1 = ImageFactory.getInstance().fromUrl(url1);
|
||||
Image image2 = ImageFactory.getInstance().fromUrl(url2);
|
||||
String result = faceService.compare(image1, image2);
|
||||
return ResultBean.success().add("result", result);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "人脸比对(1:1)-图片 - Face Comparison (1:1) - Image")
|
||||
@PostMapping("/compareForImageFiles")
|
||||
public ResultBean compareForImageFiles(@RequestParam(value = "imageFiles") MultipartFile[] imageFiles) {
|
||||
InputStream fis = null;
|
||||
try {
|
||||
InputStream inputStream1 = imageFiles[0].getInputStream();
|
||||
String base64Img1 = Base64.encodeBase64String(imageFiles[0].getBytes());
|
||||
Image image1 = ImageFactory.getInstance().fromInputStream(inputStream1);
|
||||
|
||||
InputStream inputStream2 = imageFiles[1].getInputStream();
|
||||
String base64Img2 = Base64.encodeBase64String(imageFiles[1].getBytes());
|
||||
Image image2 = ImageFactory.getInstance().fromInputStream(inputStream2);
|
||||
|
||||
String result = faceService.compare(image1, image2);
|
||||
|
||||
return ResultBean.success().add("result", result)
|
||||
.add("base64Img1", "data:image/jpeg;base64," + base64Img1).add("base64Img2", "data:image/jpeg;base64," + base64Img2);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("errors", e.getMessage());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
package me.aias.controller;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import me.aias.service.OcrService;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import me.aias.domain.DataBean;
|
||||
import me.aias.domain.ResultBean;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
@Api(tags = "文字识别 - Text Recognition")
|
||||
@RestController
|
||||
@RequestMapping("/ocr")
|
||||
public class OcrController {
|
||||
private Logger logger = LoggerFactory.getLogger(OcrController.class);
|
||||
|
||||
@Autowired
|
||||
private OcrService inferService;
|
||||
|
||||
@ApiOperation(value = "通用文字识别-URL - General Text Recognition - URL")
|
||||
@GetMapping(value = "/generalInfoForImageUrl")
|
||||
public ResultBean generalInfoForImageUrl(@RequestParam(value = "url") String url) throws IOException {
|
||||
Image image = ImageFactory.getInstance().fromUrl(url);
|
||||
List<DataBean> dataList = inferService.getGeneralInfo(image);
|
||||
return ResultBean.success().add("result", dataList);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "通用文字识别-图片 - General Text Recognition - Image")
|
||||
@PostMapping("/generalInfoForImageFile")
|
||||
public ResultBean generalInfoForImageFile(@RequestParam(value = "imageFile") MultipartFile imageFile) {
|
||||
InputStream fis = null;
|
||||
try {
|
||||
InputStream inputStream = imageFile.getInputStream();
|
||||
String base64Img = Base64.encodeBase64String(imageFile.getBytes());
|
||||
|
||||
Image image = ImageFactory.getInstance().fromInputStream(inputStream);
|
||||
List<DataBean> dataList = inferService.getGeneralInfo(image);
|
||||
|
||||
return ResultBean.success().add("result", dataList)
|
||||
.add("base64Img", "data:image/jpeg;base64," + base64Img);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
return ResultBean.failure().add("errors", e.getMessage());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package me.aias.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DataBean {
|
||||
private String value;
|
||||
private List<Point> points;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package me.aias.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Point {
|
||||
private int x;
|
||||
private int y;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package me.aias.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ResultBean<T> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int code;
|
||||
private String value;
|
||||
private Map<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public static ResultBean success() {
|
||||
ResultBean rb = new ResultBean();
|
||||
rb.setCode(0);
|
||||
rb.setValue("Success");
|
||||
return rb;
|
||||
}
|
||||
|
||||
public static ResultBean failure() {
|
||||
ResultBean msg = new ResultBean();
|
||||
msg.setCode(-1);
|
||||
msg.setValue("Failure");
|
||||
return msg;
|
||||
}
|
||||
|
||||
public ResultBean() {
|
||||
|
||||
}
|
||||
|
||||
public ResultBean add(String key, Object value) {
|
||||
this.getData().put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package me.aias.infer.face;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ModelZoo;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 20, 2021
|
||||
*/
|
||||
public final class FaceDetectionModel {
|
||||
|
||||
private ZooModel<Image, DetectedObjects> model;
|
||||
private Predictor<Image, DetectedObjects> predictor;
|
||||
|
||||
public void init(String layoutUri, int topK, double confThresh, double nmsThresh) throws MalformedModelException, ModelNotFoundException, IOException {
|
||||
this.model = ModelZoo.loadModel(detectCriteria(layoutUri, topK, confThresh, nmsThresh));
|
||||
this.predictor = model.newPredictor();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.model.close();
|
||||
this.predictor.close();
|
||||
}
|
||||
|
||||
public DetectedObjects predict(Image image) throws TranslateException {
|
||||
return predictor.predict(image);
|
||||
}
|
||||
|
||||
private Criteria<Image, DetectedObjects> detectCriteria(String layoutUri, int topK, double confThresh, double nmsThresh) {
|
||||
double[] variance = {0.1f, 0.2f};
|
||||
|
||||
int[][] scales = {{10, 16, 24}, {32, 48}, {64, 96}, {128, 192, 256}};
|
||||
int[] steps = {8, 16, 32, 64};
|
||||
|
||||
FaceDetectionTranslator translator =
|
||||
new FaceDetectionTranslator(confThresh, nmsThresh, variance, topK, scales, steps);
|
||||
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelPath(Paths.get(layoutUri))
|
||||
.optTranslator(translator)
|
||||
.optEngine("PyTorch") // Use PyTorch engine
|
||||
.optDevice(Device.cpu())
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
package me.aias.infer.face;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.*;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDArrays;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.ndarray.types.DataType;
|
||||
import ai.djl.ndarray.types.Shape;
|
||||
import ai.djl.translate.Batchifier;
|
||||
import ai.djl.translate.Translator;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
public class FaceDetectionTranslator implements Translator<Image, DetectedObjects> {
|
||||
|
||||
private double confThresh;
|
||||
private double nmsThresh;
|
||||
private int topK;
|
||||
private double[] variance;
|
||||
private int[][] scales;
|
||||
private int[] steps;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public FaceDetectionTranslator(
|
||||
double confThresh,
|
||||
double nmsThresh,
|
||||
double[] variance,
|
||||
int topK,
|
||||
int[][] scales,
|
||||
int[] steps) {
|
||||
this.confThresh = confThresh;
|
||||
this.nmsThresh = nmsThresh;
|
||||
this.variance = variance;
|
||||
this.topK = topK;
|
||||
this.scales = scales;
|
||||
this.steps = steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Image input) {
|
||||
width = input.getWidth();
|
||||
height = input.getHeight();
|
||||
NDArray array = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
|
||||
array = array.transpose(2, 0, 1).flip(0); // HWC -> CHW RGB -> BGR
|
||||
// The network by default takes float32
|
||||
if (!array.getDataType().equals(DataType.FLOAT32)) {
|
||||
array = array.toType(DataType.FLOAT32, false);
|
||||
}
|
||||
NDArray mean =
|
||||
ctx.getNDManager().create(new float[]{104f, 117f, 123f}, new Shape(3, 1, 1));
|
||||
array = array.sub(mean);
|
||||
return new NDList(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public DetectedObjects processOutput(TranslatorContext ctx, NDList list) {
|
||||
NDManager manager = ctx.getNDManager();
|
||||
double scaleXY = variance[0];
|
||||
double scaleWH = variance[1];
|
||||
|
||||
NDArray prob = list.get(1).get(":, 1:");
|
||||
prob =
|
||||
NDArrays.stack(
|
||||
new NDList(
|
||||
prob.argMax(1).toType(DataType.FLOAT32, false),
|
||||
prob.max(new int[]{1})));
|
||||
|
||||
NDArray boxRecover = boxRecover(manager, width, height, scales, steps);
|
||||
NDArray boundingBoxes = list.get(0);
|
||||
NDArray bbWH = boundingBoxes.get(":, 2:").mul(scaleWH).exp().mul(boxRecover.get(":, 2:"));
|
||||
NDArray bbXY =
|
||||
boundingBoxes
|
||||
.get(":, :2")
|
||||
.mul(scaleXY)
|
||||
.mul(boxRecover.get(":, 2:"))
|
||||
.add(boxRecover.get(":, :2"))
|
||||
.sub(bbWH.mul(0.5f));
|
||||
|
||||
boundingBoxes = NDArrays.concat(new NDList(bbXY, bbWH), 1);
|
||||
|
||||
NDArray landms = list.get(2);
|
||||
landms = decodeLandm(landms, boxRecover, scaleXY);
|
||||
|
||||
// filter the result below the threshold
|
||||
NDArray cutOff = prob.get(1).gt(confThresh);
|
||||
boundingBoxes = boundingBoxes.transpose().booleanMask(cutOff, 1).transpose();
|
||||
landms = landms.transpose().booleanMask(cutOff, 1).transpose();
|
||||
prob = prob.booleanMask(cutOff, 1);
|
||||
|
||||
// start categorical filtering
|
||||
long[] order = prob.get(1).argSort().get(":" + topK).toLongArray();
|
||||
prob = prob.transpose();
|
||||
List<String> retNames = new ArrayList<>();
|
||||
List<Double> retProbs = new ArrayList<>();
|
||||
List<BoundingBox> retBB = new ArrayList<>();
|
||||
|
||||
Map<Integer, List<BoundingBox>> recorder = new ConcurrentHashMap<>();
|
||||
|
||||
for (int i = order.length - 1; i >= 0; i--) {
|
||||
long currMaxLoc = order[i];
|
||||
float[] classProb = prob.get(currMaxLoc).toFloatArray();
|
||||
int classId = (int) classProb[0];
|
||||
double probability = classProb[1];
|
||||
|
||||
double[] boxArr = boundingBoxes.get(currMaxLoc).toDoubleArray();
|
||||
double[] landmsArr = landms.get(currMaxLoc).toDoubleArray();
|
||||
Rectangle rect = new Rectangle(boxArr[0], boxArr[1], boxArr[2], boxArr[3]);
|
||||
List<BoundingBox> boxes = recorder.getOrDefault(classId, new ArrayList<>());
|
||||
boolean belowIoU = true;
|
||||
for (BoundingBox box : boxes) {
|
||||
if (box.getIoU(rect) > nmsThresh) {
|
||||
belowIoU = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (belowIoU) {
|
||||
List<Point> keyPoints = new ArrayList<>();
|
||||
for (int j = 0; j < 5; j++) { // 5 face landmarks
|
||||
double x = landmsArr[j * 2];
|
||||
double y = landmsArr[j * 2 + 1];
|
||||
keyPoints.add(new Point(x * width, y * height));
|
||||
}
|
||||
Landmark landmark =
|
||||
new Landmark(boxArr[0], boxArr[1], boxArr[2], boxArr[3], keyPoints);
|
||||
|
||||
boxes.add(landmark);
|
||||
recorder.put(classId, boxes);
|
||||
String className = "Face"; // classes.get(classId)
|
||||
retNames.add(className);
|
||||
retProbs.add(probability);
|
||||
retBB.add(landmark);
|
||||
}
|
||||
}
|
||||
|
||||
return new DetectedObjects(retNames, retProbs, retBB);
|
||||
}
|
||||
|
||||
private NDArray boxRecover(
|
||||
NDManager manager, int width, int height, int[][] scales, int[] steps) {
|
||||
int[][] aspectRatio = new int[steps.length][2];
|
||||
for (int i = 0; i < steps.length; i++) {
|
||||
int wRatio = (int) Math.ceil((float) width / steps[i]);
|
||||
int hRatio = (int) Math.ceil((float) height / steps[i]);
|
||||
aspectRatio[i] = new int[]{hRatio, wRatio};
|
||||
}
|
||||
|
||||
List<double[]> defaultBoxes = new ArrayList<>();
|
||||
|
||||
for (int idx = 0; idx < steps.length; idx++) {
|
||||
int[] scale = scales[idx];
|
||||
for (int h = 0; h < aspectRatio[idx][0]; h++) {
|
||||
for (int w = 0; w < aspectRatio[idx][1]; w++) {
|
||||
for (int i : scale) {
|
||||
double skx = i * 1.0 / width;
|
||||
double sky = i * 1.0 / height;
|
||||
double cx = (w + 0.5) * steps[idx] / width;
|
||||
double cy = (h + 0.5) * steps[idx] / height;
|
||||
defaultBoxes.add(new double[]{cx, cy, skx, sky});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double[][] boxes = new double[defaultBoxes.size()][defaultBoxes.get(0).length];
|
||||
for (int i = 0; i < defaultBoxes.size(); i++) {
|
||||
boxes[i] = defaultBoxes.get(i);
|
||||
}
|
||||
return manager.create(boxes).clip(0.0, 1.0);
|
||||
}
|
||||
|
||||
// decode face landmarks, 5 points per face
|
||||
private NDArray decodeLandm(NDArray pre, NDArray priors, double scaleXY) {
|
||||
NDArray point1 =
|
||||
pre.get(":, :2").mul(scaleXY).mul(priors.get(":, 2:")).add(priors.get(":, :2"));
|
||||
NDArray point2 =
|
||||
pre.get(":, 2:4").mul(scaleXY).mul(priors.get(":, 2:")).add(priors.get(":, :2"));
|
||||
NDArray point3 =
|
||||
pre.get(":, 4:6").mul(scaleXY).mul(priors.get(":, 2:")).add(priors.get(":, :2"));
|
||||
NDArray point4 =
|
||||
pre.get(":, 6:8").mul(scaleXY).mul(priors.get(":, 2:")).add(priors.get(":, :2"));
|
||||
NDArray point5 =
|
||||
pre.get(":, 8:10").mul(scaleXY).mul(priors.get(":, 2:")).add(priors.get(":, :2"));
|
||||
return NDArrays.concat(new NDList(point1, point2, point3, point4, point5), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Batchifier getBatchifier() {
|
||||
return Batchifier.STACK;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package me.aias.infer.face;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ModelZoo;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 20, 2021
|
||||
*/
|
||||
public final class FaceFeatureModel {
|
||||
|
||||
private ZooModel<Image, float[]> model;
|
||||
private Predictor<Image, float[]> predictor;
|
||||
|
||||
public void init(String modelUri) throws MalformedModelException, ModelNotFoundException, IOException {
|
||||
this.model = ModelZoo.loadModel(detectCriteria(modelUri));
|
||||
this.predictor = model.newPredictor();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.model.close();
|
||||
this.predictor.close();
|
||||
}
|
||||
|
||||
public float[] predict(Image image) throws TranslateException {
|
||||
return predictor.predict(image);
|
||||
}
|
||||
|
||||
private Criteria<Image, float[]> detectCriteria(String layoutUri) {
|
||||
Criteria<Image, float[]> criteria =
|
||||
Criteria.builder()
|
||||
.setTypes(Image.class, float[].class)
|
||||
.optModelName("face_feature") // specify model file prefix
|
||||
.optModelPath(Paths.get(layoutUri))
|
||||
.optTranslator(new FaceFeatureTranslator())
|
||||
.optEngine("PyTorch") // Use PyTorch engine
|
||||
.optDevice(Device.cpu())
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package me.aias.infer.face;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.transform.Normalize;
|
||||
import ai.djl.modality.cv.transform.ToTensor;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.translate.Batchifier;
|
||||
import ai.djl.translate.Pipeline;
|
||||
import ai.djl.translate.Translator;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
public final class FaceFeatureTranslator implements Translator<Image, float[]> {
|
||||
|
||||
public FaceFeatureTranslator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Image input) {
|
||||
NDArray array = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
|
||||
Pipeline pipeline = new Pipeline();
|
||||
pipeline
|
||||
// .add(new Resize(160))
|
||||
.add(new ToTensor())
|
||||
.add(
|
||||
new Normalize(
|
||||
new float[]{127.5f / 255.0f, 127.5f / 255.0f, 127.5f / 255.0f},
|
||||
new float[]{128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f}));
|
||||
|
||||
return pipeline.transform(new NDList(array));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] processOutput(TranslatorContext ctx, NDList list) {
|
||||
NDList result = new NDList();
|
||||
long numOutputs = list.singletonOrThrow().getShape().get(0);
|
||||
for (int i = 0; i < numOutputs; i++) {
|
||||
result.add(list.singletonOrThrow().get(i));
|
||||
}
|
||||
float[][] embeddings = result.stream().map(NDArray::toFloatArray).toArray(float[][]::new);
|
||||
float[] feature = new float[embeddings.length];
|
||||
for (int i = 0; i < embeddings.length; i++) {
|
||||
feature[i] = embeddings[i][0];
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batchifier getBatchifier() {
|
||||
return Batchifier.STACK;
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package me.aias.infer.ocr;
|
||||
|
||||
import ai.djl.Model;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.util.NDImageUtils;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDList;
|
||||
import ai.djl.translate.Batchifier;
|
||||
import ai.djl.translate.Translator;
|
||||
import ai.djl.translate.TranslatorContext;
|
||||
import ai.djl.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
public class PpWordRecognitionTranslator implements Translator<Image, String> {
|
||||
|
||||
private List<String> table;
|
||||
|
||||
@Override
|
||||
public void prepare(TranslatorContext ctx) throws IOException {
|
||||
Model model = ctx.getModel();
|
||||
// ppocr_keys_v1.txt
|
||||
try (InputStream is = model.getArtifact("ppocr_keys_v1.txt").openStream()) {
|
||||
table = Utils.readLines(is, true);
|
||||
table.add(0, "blank");
|
||||
table.add("");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String processOutput(TranslatorContext ctx, NDList list) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
NDArray tokens = list.singletonOrThrow();
|
||||
long[] indices = tokens.get(0).argMax(1).toLongArray();
|
||||
int lastIdx = 0;
|
||||
for (int i = 0; i < indices.length; i++) {
|
||||
if (indices[i] > 0 && !(i > 0 && indices[i] == lastIdx)) {
|
||||
sb.append(table.get((int) indices[i]));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NDList processInput(TranslatorContext ctx, Image input) {
|
||||
NDArray img = input.toNDArray(ctx.getNDManager(), Image.Flag.COLOR);
|
||||
// int[] hw = resize32(input.getHeight(), input.getWidth());
|
||||
|
||||
int h = input.getHeight();
|
||||
int w = input.getWidth();
|
||||
float ratio = (float) w / (float) h;
|
||||
int resized_w = (int) (Math.ceil(32 * ratio));
|
||||
|
||||
// img = NDImageUtils.resize(img, hw[1], hw[0]);
|
||||
img = NDImageUtils.resize(img, resized_w, 32);
|
||||
|
||||
img = NDImageUtils.toTensor(img).sub(0.5f).div(0.5f);
|
||||
|
||||
img = img.expandDims(0);
|
||||
return new NDList(img);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batchifier getBatchifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private int[] resize32(double h, double w) {
|
||||
double h32Ratio = h / 32d;
|
||||
double w32 = w / h32Ratio;
|
||||
int w32Ratio = (int) Math.round(w32 / 32d);
|
||||
return new int[]{32, w32Ratio * 32}; // height: 32 (fixed), width: 32 * N
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
package me.aias.infer.ocr;
|
||||
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.modality.cv.output.BoundingBox;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.modality.cv.output.Rectangle;
|
||||
import ai.djl.modality.cv.util.NDImageUtils;
|
||||
import ai.djl.ndarray.NDArray;
|
||||
import ai.djl.ndarray.NDManager;
|
||||
import ai.djl.paddlepaddle.zoo.cv.objectdetection.PpWordDetectionTranslator;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ModelZoo;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Oct 19, 2021
|
||||
*/
|
||||
public final class RecognitionModel {
|
||||
private ZooModel<Image, DetectedObjects> detectionModel;
|
||||
private ZooModel<Image, String> recognitionModel;
|
||||
private Predictor<Image, String> recognizer;
|
||||
private Predictor<Image, DetectedObjects> detector;
|
||||
|
||||
public void init(String detUri, String recUri) throws MalformedModelException, ModelNotFoundException, IOException {
|
||||
this.detectionModel = ModelZoo.loadModel(detectCriteria(detUri));
|
||||
this.recognitionModel = ModelZoo.loadModel(recognizeCriteria(recUri));
|
||||
this.recognizer = recognitionModel.newPredictor();
|
||||
this.detector = detectionModel.newPredictor();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.detectionModel.close();
|
||||
this.recognitionModel.close();
|
||||
this.recognizer.close();
|
||||
this.detector.close();
|
||||
}
|
||||
|
||||
public String predictSingleLineText(Image image)
|
||||
throws TranslateException {
|
||||
String text = recognizer.predict(image);
|
||||
return text;
|
||||
}
|
||||
|
||||
public DetectedObjects predict(Image image)
|
||||
throws TranslateException {
|
||||
DetectedObjects detections = detector.predict(image);
|
||||
List<DetectedObjects.DetectedObject> boxes = detections.items();
|
||||
List<String> names = new ArrayList<>();
|
||||
List<Double> prob = new ArrayList<>();
|
||||
List<BoundingBox> rect = new ArrayList<>();
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
Image subImg = getSubImage(image, boxes.get(i).getBoundingBox());
|
||||
if (subImg.getHeight() * 1.0 / subImg.getWidth() > 1.5) {
|
||||
subImg = rotateImg(subImg);
|
||||
}
|
||||
String name = recognizer.predict(subImg);
|
||||
System.out.println(name);
|
||||
names.add(name);
|
||||
prob.add(-1.0);
|
||||
rect.add(boxes.get(i).getBoundingBox());
|
||||
}
|
||||
DetectedObjects detectedObjects = new DetectedObjects(names, prob, rect);
|
||||
return detectedObjects;
|
||||
}
|
||||
|
||||
private Criteria<Image, DetectedObjects> detectCriteria(String detUri) {
|
||||
Criteria<Image, DetectedObjects> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optModelPath(Paths.get(detUri))
|
||||
.optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
|
||||
return criteria;
|
||||
}
|
||||
|
||||
private Criteria<Image, String> recognizeCriteria(String recUri) {
|
||||
Criteria<Image, String> criteria =
|
||||
Criteria.builder()
|
||||
.optEngine("PaddlePaddle")
|
||||
.setTypes(Image.class, String.class)
|
||||
.optModelPath(Paths.get(recUri))
|
||||
.optProgress(new ProgressBar())
|
||||
.optTranslator(new PpWordRecognitionTranslator())
|
||||
.build();
|
||||
|
||||
return criteria;
|
||||
}
|
||||
|
||||
private Image getSubImage(Image img, BoundingBox box) {
|
||||
Rectangle rect = box.getBounds();
|
||||
double[] extended = extendRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
int[] recovered = {
|
||||
(int) (extended[0] * width),
|
||||
(int) (extended[1] * height),
|
||||
(int) (extended[2] * width),
|
||||
(int) (extended[3] * height)
|
||||
};
|
||||
return img.getSubImage(recovered[0], recovered[1], recovered[2], recovered[3]);
|
||||
}
|
||||
|
||||
private double[] extendRect(double xmin, double ymin, double width, double height) {
|
||||
double centerx = xmin + width / 2;
|
||||
double centery = ymin + height / 2;
|
||||
if (width > height) {
|
||||
width += height * 2.0;
|
||||
height *= 3.0;
|
||||
} else {
|
||||
height += width * 2.0;
|
||||
width *= 3.0;
|
||||
}
|
||||
double newX = centerx - width / 2 < 0 ? 0 : centerx - width / 2;
|
||||
double newY = centery - height / 2 < 0 ? 0 : centery - height / 2;
|
||||
double newWidth = newX + width > 1 ? 1 - newX : width;
|
||||
double newHeight = newY + height > 1 ? 1 - newY : height;
|
||||
return new double[]{newX, newY, newWidth, newHeight};
|
||||
}
|
||||
|
||||
private Image rotateImg(Image image) {
|
||||
try (NDManager manager = NDManager.newBaseManager()) {
|
||||
NDArray rotated = NDImageUtils.rotate90(image.toNDArray(manager), 1);
|
||||
return ImageFactory.getInstance().fromNDArray(rotated);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package me.aias.service;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import me.aias.domain.DataBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Jun 12, 2021
|
||||
*/
|
||||
public interface FaceService {
|
||||
List<DataBean> detect(Image image);
|
||||
|
||||
float[] feature(Image image);
|
||||
|
||||
String compare(Image img1, Image img2) throws TranslateException;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package me.aias.service;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import me.aias.domain.DataBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Calvin
|
||||
* @date Jun 12, 2021
|
||||
*/
|
||||
public interface OcrService {
|
||||
List<DataBean> getGeneralInfo(Image image);
|
||||
}
|