@@ -719,6 +719,10 @@ var ( | |||||
GPUCombatDataSetName string | GPUCombatDataSetName string | ||||
GPUCombatDataSetUUID string | GPUCombatDataSetUUID string | ||||
}{} | }{} | ||||
ModelApp = struct { | |||||
DesensitizationUrl string | |||||
}{} | |||||
) | ) | ||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin. | // DateLang transforms standard language locale name to corresponding value in datetime plugin. | ||||
@@ -1540,6 +1544,7 @@ func NewContext() { | |||||
getModelartsCDConfig() | getModelartsCDConfig() | ||||
getModelConvertConfig() | getModelConvertConfig() | ||||
getModelSafetyConfig() | getModelSafetyConfig() | ||||
getModelAppConfig() | |||||
} | } | ||||
func getModelSafetyConfig() { | func getModelSafetyConfig() { | ||||
@@ -1573,6 +1578,12 @@ func getModelConvertConfig() { | |||||
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | ||||
} | } | ||||
func getModelAppConfig() { | |||||
sec := Cfg.Section("model_app") | |||||
ModelApp.DesensitizationUrl = sec.Key("desensitization_url").MustString("") | |||||
} | |||||
func getModelartsCDConfig() { | func getModelartsCDConfig() { | ||||
sec := Cfg.Section("modelarts-cd") | sec := Cfg.Section("modelarts-cd") | ||||
@@ -3272,3 +3272,9 @@ no_data = No Data | |||||
untargetted = Untargetted | untargetted = Untargetted | ||||
targetted = targetted | targetted = targetted | ||||
new_model_security_evaluation_tips = Model Security Evaluation just used for image classification | new_model_security_evaluation_tips = Model Security Evaluation just used for image classification | ||||
[model_app] | |||||
get_file_fail= Can not get the image content, please try again later. | |||||
content_type_unsupported=Allowed image type is jpg, jpeg or png. | |||||
process_image_fail=Fail to process image, please try again later. | |||||
@@ -3291,3 +3291,9 @@ no_data = 无数据 | |||||
untargetted = 非定向 | untargetted = 非定向 | ||||
targetted = 定向 | targetted = 定向 | ||||
new_model_security_evaluation_tips = 模型安全评测只适用于图像分类 | new_model_security_evaluation_tips = 模型安全评测只适用于图像分类 | ||||
[model_app] | |||||
get_file_fail= 获取上传文件失败,请稍后再试。 | |||||
content_type_unsupported=请上传jpg、jpeg或png图片。 | |||||
process_image_fail=图片处理失败,请稍后再试。 | |||||
@@ -0,0 +1,78 @@ | |||||
package modelapp | |||||
import ( | |||||
"bytes" | |||||
"code.gitea.io/gitea/models" | |||||
"crypto/tls" | |||||
"image" | |||||
"image/png" | |||||
"net/http" | |||||
"strconv" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
"code.gitea.io/gitea/modules/base" | |||||
"code.gitea.io/gitea/modules/context" | |||||
"github.com/go-resty/resty/v2" | |||||
) | |||||
var restyClient *resty.Client | |||||
var tplExploreUpload base.TplName = "model/tuomin/upload" | |||||
var uploadUrl = "/extension/tuomin/upload" | |||||
var allowedContentType = []string{"image/jpeg", "image/jpg", "image/png"} | |||||
func ProcessImageUI(ctx *context.Context) { | |||||
ctx.HTML(200, tplExploreUpload) | |||||
} | |||||
func ProcessImage(ctx *context.Context) { | |||||
file, header, err := ctx.GetFile("file") | |||||
if err != nil { | |||||
ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.get_file_fail"))) | |||||
return | |||||
} | |||||
defer file.Close() | |||||
contentType := header.Header.Get("Content-Type") | |||||
if !isInAllowedContentType(contentType) { | |||||
ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.content_type_unsupported"))) | |||||
return | |||||
} | |||||
client := getRestyClient() | |||||
res, err := client.R().SetMultipartField( | |||||
"file", header.Filename, contentType, file).Post(setting.ModelApp.DesensitizationUrl + "?mode=" + strconv.Itoa(ctx.QueryInt("mode"))) | |||||
if err != nil { | |||||
ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.process_image_fail"))) | |||||
return | |||||
} | |||||
image, _, err := image.Decode(bytes.NewReader(res.Body())) | |||||
if err != nil { | |||||
ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.process_image_fail"))) | |||||
return | |||||
} | |||||
png.Encode(ctx.Resp, image) | |||||
return | |||||
} | |||||
func isInAllowedContentType(contentType string) bool { | |||||
for _, allowType := range allowedContentType { | |||||
if allowType == contentType { | |||||
return true | |||||
} | |||||
} | |||||
return false | |||||
} | |||||
func getRestyClient() *resty.Client { | |||||
if restyClient == nil { | |||||
restyClient = resty.New() | |||||
restyClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) | |||||
} | |||||
return restyClient | |||||
} |
@@ -12,6 +12,7 @@ import ( | |||||
"text/template" | "text/template" | ||||
"time" | "time" | ||||
"code.gitea.io/gitea/routers/modelapp" | |||||
"code.gitea.io/gitea/routers/reward/point" | "code.gitea.io/gitea/routers/reward/point" | ||||
"code.gitea.io/gitea/routers/task" | "code.gitea.io/gitea/routers/task" | ||||
"code.gitea.io/gitea/services/reward" | "code.gitea.io/gitea/services/reward" | ||||
@@ -347,6 +348,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Post("/user/login/kanban", user.SignInPostAPI) | m.Post("/user/login/kanban", user.SignInPostAPI) | ||||
m.Get("/home/term", routers.HomeTerm) | m.Get("/home/term", routers.HomeTerm) | ||||
m.Get("/home/privacy", routers.HomePrivacy) | m.Get("/home/privacy", routers.HomePrivacy) | ||||
m.Get("/extension/tuomin/upload", modelapp.ProcessImageUI) | |||||
m.Post("/extension/tuomin/upload", reqSignIn, modelapp.ProcessImage) | |||||
m.Group("/explore", func() { | m.Group("/explore", func() { | ||||
m.Get("", func(ctx *context.Context) { | m.Get("", func(ctx *context.Context) { | ||||
ctx.Redirect(setting.AppSubURL + "/explore/repos") | ctx.Redirect(setting.AppSubURL + "/explore/repos") | ||||
@@ -32,9 +32,15 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui simple dropdown item" id='dropdown_explore'> | <div class="ui simple dropdown item" id='dropdown_explore'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -68,6 +74,14 @@ | |||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui simple dropdown item" id='dropdown_PageHome'> | <div class="ui simple dropdown item" id='dropdown_PageHome'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -34,6 +34,13 @@ | |||||
</div> | </div> | ||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_explore'> | <div class="ui dropdown item" id='dropdown_explore'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -66,6 +73,13 @@ | |||||
</div> | </div> | ||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_PageHome'> | <div class="ui dropdown item" id='dropdown_PageHome'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -26,6 +26,13 @@ | |||||
</div> | </div> | ||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_explore'> | <div class="ui dropdown item" id='dropdown_explore'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -59,6 +66,13 @@ | |||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_PageHome'> | <div class="ui dropdown item" id='dropdown_PageHome'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -36,6 +36,13 @@ | |||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_explore'> | <div class="ui dropdown item" id='dropdown_explore'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -69,6 +76,13 @@ | |||||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | ||||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | ||||
<div class="ui simple dropdown item" > | |||||
{{.i18n.Tr "repo.model_manager"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||||
</div> | |||||
</div> | |||||
<div class="ui dropdown item" id='dropdown_PageHome'> | <div class="ui dropdown item" id='dropdown_PageHome'> | ||||
{{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
@@ -0,0 +1,12 @@ | |||||
{{template "base/head" .}} | |||||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-tuomin.css?v={{MD5 AppVer}}" /> | |||||
<div> | |||||
{{if .Flash}} | |||||
<div class="sixteen wide column"> | |||||
{{template "base/alert" .}} | |||||
</div> | |||||
{{end}} | |||||
<div id="__vue-root"></div> | |||||
</div> | |||||
<script src="{{StaticUrlPrefix}}/js/vp-model-tuomin.js?v={{MD5 AppVer}}"></script> | |||||
{{template "base/footer" .}} |
@@ -1,80 +0,0 @@ | |||||
{{template "base/head" .}} | |||||
<div class="organization members"> | |||||
{{template "org/header" .}} | |||||
<div class="ui container"> | |||||
{{template "base/alert" .}} | |||||
{{template "org/navber" .}} | |||||
<div class="ui stackable grid"> | |||||
<div class="ui sixteen wide computer column list"> | |||||
{{ range .Members}} | |||||
<div class="item ui grid"> | |||||
<div class="three wide mobile two wide tablet one wide computer column"> | |||||
<img class="ui avatar" src="{{.SizedRelAvatarLink 48}}"> | |||||
</div> | |||||
<div class="seven wide mobile three wide tablet three wide computer column"> | |||||
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div> | |||||
<div class="meta">{{.FullName}}</div> | |||||
</div> | |||||
<div class="ui three wide tablet four wide computer column center tablet only computer only"> | |||||
<div class="meta"> | |||||
{{$.i18n.Tr "org.members.membership_visibility"}} | |||||
</div> | |||||
<div class="meta"> | |||||
{{ $isPublic := index $.MembersIsPublicMember .ID}} | |||||
{{if $isPublic}} | |||||
<strong>{{$.i18n.Tr "org.members.public"}}</strong> | |||||
{{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} | |||||
{{else}} | |||||
<strong>{{$.i18n.Tr "org.members.private"}}</strong> | |||||
{{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
<div class="five wide mobile three wide tablet three wide computer column"> | |||||
<div class="meta"> | |||||
{{$.i18n.Tr "org.members.member_role"}} | |||||
</div> | |||||
<div class="meta"> | |||||
<strong>{{if index $.MembersIsUserOrgOwner .ID}}{{svg "octicon-shield-lock" 16}} {{$.i18n.Tr "org.members.owner"}}{{else}}{{$.i18n.Tr "org.members.member"}}{{end}}</strong> | |||||
</div> | |||||
</div> | |||||
<div class="ui one wide column center tablet only computer only"> | |||||
<div class="meta"> | |||||
2FA | |||||
</div> | |||||
<div class="meta"> | |||||
<strong> | |||||
{{if index $.MembersTwoFaStatus .ID}} | |||||
<span class="text green">{{svg "octicon-check" 16}}</span> | |||||
{{else}} | |||||
{{svg "octicon-x" 16}} | |||||
{{end}} | |||||
</strong> | |||||
</div> | |||||
</div> | |||||
<div class="ui three wide column tablet only computer only"> | |||||
<div class="text right"> | |||||
{{if eq $.SignedUser.ID .ID}} | |||||
<form method="post" action="{{$.OrgLink}}/members/action/leave"> | |||||
{{$.CsrfTokenHtml}} | |||||
<button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.leave"}}</button> | |||||
</form> | |||||
{{else if $.IsOrganizationOwner}} | |||||
<form method="post" action="{{$.OrgLink}}/members/action/remove"> | |||||
{{$.CsrfTokenHtml}} | |||||
<button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.remove"}}</button> | |||||
</form> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{end}} | |||||
</div> | |||||
{{template "base/paginate" .}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{template "base/footer" .}} |
@@ -176,6 +176,22 @@ const en = { | |||||
Activated: 'Activated', | Activated: 'Activated', | ||||
notActive: 'Not active', | notActive: 'Not active', | ||||
}, | }, | ||||
tranformImageFailed:'Picture desensitization failed', | |||||
originPicture:'Origin picture', | |||||
desensitizationPicture:'Desensitization picture', | |||||
desensitizationObject:'Desensitization object', | |||||
example:'Example', | |||||
startDesensitization:'Start desensitization', | |||||
all:'All', | |||||
onlyFace:'Only face', | |||||
onlyLicensePlate:'Only license plate', | |||||
dragThePictureHere:'Drag the picture here', | |||||
or:'or', | |||||
clickUpload:'Click upload', | |||||
dataDesensitizationModelExperience:'Data desensitization model experience', | |||||
dataDesensitizationModelDesc:'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project', | |||||
limitFilesUpload:'Only jpg/jpeg/png files can be uploaded', | |||||
limitSizeUpload:'The size of the uploaded file cannot exceed 20M!', | |||||
} | } | ||||
export default en; | export default en; |
@@ -176,6 +176,22 @@ const zh = { | |||||
Activated: '已激活', | Activated: '已激活', | ||||
notActive: '未激活', | notActive: '未激活', | ||||
}, | }, | ||||
tranformImageFailed:'图片脱敏失败', | |||||
originPicture:'原始图片', | |||||
desensitizationPicture:'脱敏图片', | |||||
desensitizationObject:'脱敏对象', | |||||
example:'示例', | |||||
startDesensitization:'开始处理', | |||||
all:'全部', | |||||
onlyFace:'仅人脸', | |||||
onlyLicensePlate:'仅车牌', | |||||
dragThePictureHere:'拖动图片到这里', | |||||
or:'或', | |||||
clickUpload:'点击上传', | |||||
dataDesensitizationModelExperience:'数据脱敏模型体验', | |||||
dataDesensitizationModelDesc:'利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目', | |||||
limitFilesUpload:'只能上传 jpg/jpeg/png 格式的文件', | |||||
limitSizeUpload:'上传文件大小不能超过 20M !', | |||||
} | } | ||||
export default zh; | export default zh; |
@@ -0,0 +1,380 @@ | |||||
<template> | |||||
<div class="ui container"> | |||||
<div class="tuomin-title"> | |||||
<h2>{{ $t("dataDesensitizationModelExperience") }}</h2> | |||||
<p> | |||||
{{ $t("dataDesensitizationModelDesc") }} <a | |||||
href="https://git.openi.org.cn/tengxiao/tuomin" | |||||
target="_blank" | |||||
>tengxiao / tuomin</a | |||||
> | |||||
</p> | |||||
</div> | |||||
<el-row :gutter="12" style="margin-top: 33px"> | |||||
<el-col :xs="24" :span="12"> | |||||
<div class="tuomin-content-image"> | |||||
<div class="tuomin-icon"> | |||||
<i | |||||
class="ri-image-line" | |||||
style="font-size: 16px; margin-right: 2px" | |||||
></i> | |||||
<span style="font-size: 12px">img</span> | |||||
</div> | |||||
<div style="height: 230px; width: 96%; margin: 0 auto"> | |||||
<el-upload | |||||
action="#" | |||||
accept=".jpg,.jpeg,.png,.JPG,.JPEG,.PNG" | |||||
:show-file-list="false" | |||||
:on-change="handleChangePicture" | |||||
list-type="picture-card" | |||||
:file-list="fileList" | |||||
:style="{ display: ImageUrl ? 'none' : 'block' }" | |||||
:auto-upload="false" | |||||
drag | |||||
> | |||||
<div class="el-upload__text"> | |||||
{{ $t("dragThePictureHere") | |||||
}}<span style="color: rgba(136, 136, 136, 0.87)">{{ | |||||
$t("or") | |||||
}}</span | |||||
>{{ $t("clickUpload") }} | |||||
</div> | |||||
</el-upload> | |||||
<img class="preview-image" v-if="ImageUrl" :src="ImageUrl" alt="" /> | |||||
</div> | |||||
<div> | |||||
<div class="tuomin-radio-model"> | |||||
<label class="radio-label" | |||||
>{{ $t("desensitizationObject") }}:</label | |||||
> | |||||
<div> | |||||
<el-radio-group v-model="radio"> | |||||
<el-radio :label="2">{{ $t("all") }}</el-radio> | |||||
<el-radio :label="1">{{ $t("onlyFace") }}</el-radio> | |||||
<el-radio :label="0">{{ $t("onlyLicensePlate") }}</el-radio> | |||||
</el-radio-group> | |||||
</div> | |||||
</div> | |||||
<div class="tuomin-button-model"> | |||||
<el-button @click="cancelUpload">{{ $t("cancel") }}</el-button> | |||||
<el-button | |||||
:disabled="fileList.length < 1" | |||||
@click="startTranform" | |||||
type="primary" | |||||
>{{ $t("startDesensitization") }}</el-button | |||||
> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :span="12"> | |||||
<div class="tuomin-content-image" v-loading="tranformImageLoading"> | |||||
<div class="tuomin-icon"> | |||||
<i | |||||
class="ri-image-line" | |||||
style="font-size: 16px; margin-right: 2px" | |||||
></i> | |||||
<span style="font-size: 12px">output</span> | |||||
</div> | |||||
<div | |||||
v-if="resultImgSrc" | |||||
class="tuomin-icon-download" | |||||
@click="downImg" | |||||
> | |||||
<i | |||||
class="ri-download-2-line" | |||||
style="font-size: 16px; margin-right: 2px" | |||||
></i> | |||||
<span style="font-size: 14px">下载</span> | |||||
</div> | |||||
<div style="height: 358px"> | |||||
<el-image | |||||
style="height: 100%; width: 100%" | |||||
:src="resultImgSrc" | |||||
:preview-src-list="[resultImgSrc]" | |||||
> | |||||
<div slot="error" class="image-slot"> | |||||
<i style="font-size: 0" class="el-icon-picture-outline"></i> | |||||
</div> | |||||
</el-image> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | |||||
<div style="margin: 39px 0 21px 0"> | |||||
<span>{{ $t("example") }}:</span> | |||||
</div> | |||||
<div class="table-container"> | |||||
<div> | |||||
<el-table border :data="tableData1" style="width: 100%"> | |||||
<el-table-column :label="$t('originPicture')" align="center"> | |||||
<template slot-scope="scope"> | |||||
<div style="width: 100%; height: 200px"> | |||||
<el-image | |||||
style="height: 100%; width: 100%" | |||||
:src="scope.row.imgSrc1" | |||||
:preview-src-list="[scope.row.imgSrc1]" | |||||
> | |||||
<div slot="error" class="image-slot"> | |||||
<i style="font-size: 0" class="el-icon-picture-outline"></i> | |||||
</div> | |||||
</el-image> | |||||
</div> | |||||
</template> | |||||
</el-table-column> | |||||
<el-table-column :label="$t('desensitizationPicture')" align="center"> | |||||
<template slot-scope="scope"> | |||||
<div style="width: 100%; height: 200px"> | |||||
<el-image | |||||
style="height: 100%; width: 100%" | |||||
:src="scope.row.imgSrc2" | |||||
:preview-src-list="[scope.row.imgSrc2]" | |||||
> | |||||
<div slot="error" class="image-slot"> | |||||
<i style="font-size: 0" class="el-icon-picture-outline"></i> | |||||
</div> | |||||
</el-image> | |||||
</div> | |||||
</template> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="mode" | |||||
:label="$t('desensitizationObject')" | |||||
align="center" | |||||
header-align="center" | |||||
> | |||||
</el-table-column> | |||||
</el-table> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import axios from "axios"; | |||||
export default { | |||||
data() { | |||||
return { | |||||
ImageUrl: "", | |||||
radio: 2, | |||||
file: "", | |||||
fileList: [], | |||||
resultImgSrc: "", | |||||
tranformImageLoading: false, | |||||
tableData1: [ | |||||
{ | |||||
imgSrc1: "/img/origin.png", | |||||
imgSrc2: "/img/tuomin.png", | |||||
mode: this.$t("all"), | |||||
}, | |||||
], | |||||
}; | |||||
}, | |||||
components: {}, | |||||
methods: { | |||||
// 选择文件、移除文件、上传文件成功/失败后,都会触发 | |||||
handleChangePicture(file, fileList) { | |||||
let acceptList = ["jpg", "jpeg", "png"]; | |||||
// 根据文件名获取文件的后缀名 | |||||
let fileType = file.name.split(".").pop().toLowerCase(); | |||||
// 判断文件格式是否符合要求 | |||||
if (acceptList.indexOf(fileType) === -1) { | |||||
this.$message.error(this.$t("limitFilesUpload")); | |||||
return false; | |||||
} | |||||
// 判断文件大小是否符合要求 | |||||
if (file.size / 1024 / 1024 > 20) { | |||||
this.$message.error(this.$t("limitSizeUpload")); | |||||
return false; | |||||
} | |||||
this.ImageUrl = URL.createObjectURL(file.raw); | |||||
this.file = file; | |||||
this.fileList = fileList; | |||||
}, | |||||
cancelUpload() { | |||||
this.ImageUrl = ""; | |||||
this.file = ""; | |||||
this.fileList = []; | |||||
}, | |||||
downImg() { | |||||
const a = document.createElement("a"); | |||||
a.download = "result.png"; | |||||
a.style.display = "none"; | |||||
a.href = this.resultImgSrc; | |||||
document.body.appendChild(a); | |||||
a.click(); | |||||
document.body.removeChild(a); | |||||
}, | |||||
startTranform() { | |||||
if (!this.file) return; | |||||
let fd = new FormData(); | |||||
fd.append("file", this.file.raw); | |||||
this.tranformImageLoading = true; | |||||
axios({ | |||||
method: "POST", | |||||
url: "/extension/tuomin/upload", | |||||
headers: { Accept: "image/png" }, | |||||
responseType: "blob", | |||||
params: { mode: this.radio }, | |||||
data: fd, | |||||
}) | |||||
.then((res) => { | |||||
const objectURL = URL.createObjectURL(res.data); | |||||
this.resultImgSrc = objectURL; | |||||
this.tranformImageLoading = false; | |||||
}) | |||||
.catch((err) => { | |||||
this.tranformImageLoading = false; | |||||
if (err.response.status === 400) { | |||||
const fr = new FileReader(); | |||||
fr.onload = (e) => { | |||||
try { | |||||
const jsonResult = JSON.parse(e.target.result); | |||||
this.$message({ | |||||
type: "error", | |||||
message: jsonResult.Message, | |||||
}); | |||||
} catch (e) { | |||||
this.$message({ | |||||
type: "error", | |||||
message: this.$t("tranformImageFailed"), | |||||
}); | |||||
} | |||||
}; | |||||
fr.readAsText(err.response.data); | |||||
} else { | |||||
this.$message({ | |||||
type: "error", | |||||
message: this.$t("tranformImageFailed"), | |||||
}); | |||||
} | |||||
}); | |||||
}, | |||||
}, | |||||
mounted() {}, | |||||
beforeDestroy() {}, | |||||
}; | |||||
</script> | |||||
<style scoped lang="less"> | |||||
.tuomin-title { | |||||
margin-top: 34px; | |||||
h2 { | |||||
display: flex; | |||||
justify-content: center; | |||||
} | |||||
p { | |||||
display: flex; | |||||
justify-content: center; | |||||
color: rgba(136, 136, 136, 0.87); | |||||
} | |||||
} | |||||
.tuomin-content-image { | |||||
border: 1px solid rgba(0, 0, 0, 0.1); | |||||
border-radius: 5px; | |||||
min-height: 358px; | |||||
position: relative; | |||||
.tuomin-icon { | |||||
z-index: 99; | |||||
display: flex; | |||||
align-items: center; | |||||
position: absolute; | |||||
left: 0; | |||||
top: 0; | |||||
width: 66px; | |||||
height: 22px; | |||||
justify-content: center; | |||||
color: rgba(136, 136, 136, 0.87); | |||||
border-radius: 5px 0px 10px 0px; | |||||
border: 1px solid rgba(0, 0, 0, 0.1); | |||||
} | |||||
.tuomin-icon-download { | |||||
z-index: 99; | |||||
display: flex; | |||||
align-items: center; | |||||
position: absolute; | |||||
right: 10px; | |||||
bottom: 10px; | |||||
width: 66px; | |||||
height: 30px; | |||||
justify-content: center; | |||||
color: rgba(255, 255, 255, 1); | |||||
background-color: rgba(0, 0, 0, 0); | |||||
background: transparent; | |||||
border: 1px solid rgba(136, 136, 136, 0.5); | |||||
border-radius: 4px; | |||||
cursor: pointer; | |||||
} | |||||
.el-upload__text { | |||||
height: 100%; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
} | |||||
.preview-image { | |||||
height: 100%; | |||||
width: 100%; | |||||
} | |||||
.tuomin-radio-model { | |||||
display: flex; | |||||
margin: 25px 12px 0 12px; | |||||
.radio-label { | |||||
font-weight: 600; | |||||
margin-right: 4px; | |||||
color: rgba(16, 16, 16, 1); | |||||
} | |||||
} | |||||
.tuomin-button-model { | |||||
text-align: right; | |||||
margin: 22px 12px 0 12px; | |||||
} | |||||
} | |||||
/deep/ .el-upload--picture-card { | |||||
width: 100%; | |||||
background: #ffff; | |||||
border: none; | |||||
border-bottom: 1px dashed #888; | |||||
border-radius: 0; | |||||
min-height: 230px; | |||||
} | |||||
/deep/ .el-upload-dragger { | |||||
width: 100%; | |||||
background: #ffff; | |||||
border: none; | |||||
border-radius: 0; | |||||
height: 100%; | |||||
} | |||||
.table-container { | |||||
margin-bottom: 16px; | |||||
/deep/ .el-table__header { | |||||
th { | |||||
background: rgb(245, 245, 246); | |||||
font-size: 14px; | |||||
color: rgb(36, 36, 36); | |||||
font-weight: 400; | |||||
} | |||||
} | |||||
/deep/ .el-table__body { | |||||
td { | |||||
font-size: 14px; | |||||
} | |||||
} | |||||
} | |||||
.center { | |||||
display: flex; | |||||
justify-content: center; | |||||
} | |||||
@media screen and (max-width: 768px) { | |||||
body { | |||||
background-color: black; | |||||
} | |||||
} | |||||
</style> |
@@ -0,0 +1,17 @@ | |||||
import Vue from 'vue'; | |||||
import ElementUI from 'element-ui'; | |||||
import 'element-ui/lib/theme-chalk/index.css'; | |||||
import localeEn from 'element-ui/lib/locale/lang/en'; | |||||
import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||||
import { i18n, lang } from '~/langs'; | |||||
import App from './index.vue'; | |||||
Vue.use(ElementUI, { | |||||
locale: lang === 'zh-CN' ? localeZh : localeEn, | |||||
size: 'small', | |||||
}); | |||||
new Vue({ | |||||
i18n, | |||||
render: (h) => h(App), | |||||
}).$mount('#__vue-root'); |