Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/3033tags/v1.22.10.1^2
| @@ -707,6 +707,9 @@ var ( | |||||
| NPU_MINDSPORE_IMAGE_ID int | NPU_MINDSPORE_IMAGE_ID int | ||||
| NPU_TENSORFLOW_IMAGE_ID int | NPU_TENSORFLOW_IMAGE_ID int | ||||
| }{} | }{} | ||||
| 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. | ||||
| @@ -1527,6 +1530,7 @@ func NewContext() { | |||||
| getGrampusConfig() | getGrampusConfig() | ||||
| getModelartsCDConfig() | getModelartsCDConfig() | ||||
| getModelConvertConfig() | getModelConvertConfig() | ||||
| getModelAppConfig() | |||||
| } | } | ||||
| func getModelConvertConfig() { | func getModelConvertConfig() { | ||||
| @@ -1548,6 +1552,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") | ||||
| @@ -3261,3 +3261,8 @@ hours = Hours | |||||
| expected_time = , expected to be available for | expected_time = , expected to be available for | ||||
| points_acquisition_instructions = Points Acquisition Instructions | points_acquisition_instructions = Points Acquisition Instructions | ||||
| insufficient_points_balance = Insufficient points balance | insufficient_points_balance = Insufficient points balance | ||||
| [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. | |||||
| @@ -3282,3 +3282,7 @@ points_acquisition_instructions = 积分获取说明 | |||||
| insufficient_points_balance = 积分余额不足 | insufficient_points_balance = 积分余额不足 | ||||
| [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 | |||||
| } | |||||
| @@ -6,15 +6,17 @@ package routes | |||||
| import ( | import ( | ||||
| "bytes" | "bytes" | ||||
| "code.gitea.io/gitea/routers/reward/point" | |||||
| "code.gitea.io/gitea/routers/task" | |||||
| "code.gitea.io/gitea/services/reward" | |||||
| "encoding/gob" | "encoding/gob" | ||||
| "net/http" | "net/http" | ||||
| "path" | "path" | ||||
| "text/template" | "text/template" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/routers/modelapp" | |||||
| "code.gitea.io/gitea/routers/reward/point" | |||||
| "code.gitea.io/gitea/routers/task" | |||||
| "code.gitea.io/gitea/services/reward" | |||||
| "code.gitea.io/gitea/modules/slideimage" | "code.gitea.io/gitea/modules/slideimage" | ||||
| "code.gitea.io/gitea/routers/image" | "code.gitea.io/gitea/routers/image" | ||||
| @@ -346,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'); | |||||