# Conflicts: # models/models.go # modules/cloudbrain/resty.go # modules/cron/tasks_basic.go # modules/notification/base/notifier.go # modules/notification/base/null.go # modules/notification/notification.go # modules/setting/setting.go # options/locale/locale_en-US.ini # options/locale/locale_zh-CN.ini # package-lock.json # routers/repo/cloudbrain.go # routers/repo/modelarts.go # templates/repo/cloudbrain/benchmark/new.tmpl # templates/repo/cloudbrain/new.tmpl # templates/repo/cloudbrain/trainjob/new.tmpl # templates/repo/modelarts/inferencejob/new.tmpl # templates/repo/modelarts/notebook/new.tmpl # templates/repo/modelarts/trainjob/new.tmpl # web_src/vuepages/components/BaseDialog.vue # web_src/vuepages/const/index.js # web_src/vuepages/langs/config/en-US.js # web_src/vuepages/langs/config/zh-CN.js # webpack_pro.config.jstags/v1.22.9.2^2
| @@ -55,6 +55,7 @@ coverage.all | |||
| !/custom/conf/templates | |||
| /custom/conf/app.ini | |||
| !/custom/conf/app.ini.sample | |||
| /custom/public/kanban | |||
| /data | |||
| /indexers | |||
| /log | |||
| @@ -54,4 +54,7 @@ | |||
| ## 平台引用 | |||
| 如果本平台对您的科研工作提供了帮助,可在论文致谢中加入: | |||
| 英文版:```Thanks for the support provided by OpenI Community (https://git.openi.org.cn).``` | |||
| 中文版:```感谢启智社区提供的技术支持(https://git.openi.org.cn)。``` | |||
| 中文版:```感谢启智社区提供的技术支持(https://git.openi.org.cn)。``` | |||
| 如果您的成果中引用了本平台,也欢迎在下述开源项目中提交您的成果信息: | |||
| https://git.openi.org.cn/OpenIOSSG/references | |||
| @@ -29,51 +29,22 @@ | |||
| } | |||
| .rotation3D__item .scale{ position: absolute; top: 0; width: 100%; height: 100%; } | |||
| .rotation3D__item .cont{ position: relative; z-index: 2; } | |||
| .rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; } | |||
| .rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; height: 35px;} | |||
| .rotation3D__item .cont p{ color: #101010; } | |||
| .itemList .rotation3D__item .cont p::after{ | |||
| font-size: 12px; | |||
| content: ''; | |||
| position: absolute; | |||
| left: 0; | |||
| right: 0; | |||
| margin-top: 60px; | |||
| color: #101010; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(1) .cont p::after{ | |||
| content: "鹏城云脑一号"; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(2) .cont p::after{ | |||
| content: "鹏城云脑二号"; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(3) .cont p::after{ | |||
| content: "北大人工智能集群系统"; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(4) .cont p::after{ | |||
| content: "合肥类脑智能开放平台"; | |||
| .lineList .rotation3D__line:nth-child(5n+0) .dot{ | |||
| } | |||
| .itemList .rotation3D__item:nth-child(5) .cont p::after{ | |||
| content: "武汉人工智能计算中心"; | |||
| .lineList .rotation3D__line:nth-child(5n+1) .dot{ | |||
| animation-delay: 1s; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(6) .cont p::after{ | |||
| content: "西安未来人工智能计算中心"; | |||
| .lineList .rotation3D__line:nth-child(5n+2) .dot{ | |||
| animation-delay: 3s; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(7) .cont p::after{ | |||
| content: "更多接入中…"; | |||
| .lineList .rotation3D__line:nth-child(5n+3) .dot{ | |||
| animation-delay: 2s; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(8) .cont p::after{ | |||
| content: "中原人工智能计算中心"; | |||
| .lineList .rotation3D__line:nth-child(5n+3) .dot{ | |||
| animation-delay: 4s; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(9) .cont p::after{ | |||
| content: "成都人工智能计算中心"; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(10) .cont p::after{ | |||
| content: "横琴先进智能计算中心"; | |||
| } | |||
| .itemList .rotation3D__item:nth-child(11) .cont p::after{ | |||
| content: "国家超级计算济南中心"; | |||
| } | |||
| .rotation3D__item.blue{ color: #01e9fc; } | |||
| .rotation3D__item.green{ color: #b4b3ca; } | |||
| .rotation3D__item.yellow{ color: #ffd200; } | |||
| @@ -90,14 +61,17 @@ | |||
| ---------------------------*/ | |||
| .rotation3D__line{ | |||
| position: absolute; left: 50%; top: 50%; | |||
| display: block; width: 1px; height: 50%; | |||
| display: block; | |||
| width: 30px; | |||
| height: 50%; | |||
| padding-top: 60px; color: #fff; font-size: 50px; | |||
| /*background: #fff;*/ | |||
| /*原点设置在中间*/ | |||
| transform-origin: 50% 0; | |||
| transform-style: preserve-3d; | |||
| } | |||
| .rotation3D__line .pos{ position: absolute; top: 0; } | |||
| overflow: hidden; | |||
| } | |||
| .rotation3D__line .pos{ position: absolute; top: 0; left: 15px;} | |||
| .rotation3D__line svg { position: absolute; top: 0; } | |||
| .rotation3D__line svg path { | |||
| stroke: #fff; fill: none; | |||
| @@ -139,8 +113,10 @@ | |||
| position: absolute; | |||
| font-size: 12px; | |||
| color: #888; | |||
| transform: rotate(180deg)scale(0.80); | |||
| } | |||
| transform:scale(0.80); | |||
| transform-origin:left; | |||
| white-space: nowrap; | |||
| } | |||
| /*颜色*/ | |||
| .rotation3D__line.blue { color: #07b2f9; } | |||
| @@ -22,6 +22,7 @@ require ( | |||
| github.com/PuerkitoBio/goquery v1.5.0 | |||
| github.com/RichardKnop/machinery v1.6.9 | |||
| github.com/RoaringBitmap/roaring v0.4.23 // indirect | |||
| github.com/alecthomas/chroma v0.10.0 | |||
| github.com/alibabacloud-go/darabonba-openapi v0.1.18 | |||
| github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 | |||
| github.com/alibabacloud-go/tea v1.1.17 | |||
| @@ -120,8 +121,9 @@ require ( | |||
| github.com/urfave/cli v1.22.1 | |||
| github.com/xanzy/go-gitlab v0.31.0 | |||
| github.com/yohcop/openid-go v1.0.0 | |||
| github.com/yuin/goldmark v1.1.30 | |||
| github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 | |||
| github.com/yuin/goldmark v1.4.13 | |||
| github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 | |||
| github.com/yuin/goldmark-meta v1.1.0 | |||
| golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 | |||
| golang.org/x/mod v0.3.0 // indirect | |||
| golang.org/x/net v0.0.0-20200513185701-a91f0712d120 | |||
| @@ -138,7 +140,7 @@ require ( | |||
| gopkg.in/ldap.v3 v3.0.2 | |||
| gopkg.in/macaron.v1 v1.3.9 // indirect | |||
| gopkg.in/testfixtures.v2 v2.5.0 | |||
| gopkg.in/yaml.v2 v2.2.8 | |||
| gopkg.in/yaml.v2 v2.3.0 | |||
| mvdan.cc/xurls/v2 v2.1.0 | |||
| strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 | |||
| xorm.io/builder v0.3.7 | |||
| @@ -76,6 +76,8 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx | |||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||
| github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= | |||
| github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | |||
| github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= | |||
| github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= | |||
| github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | |||
| github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | |||
| github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= | |||
| @@ -203,6 +205,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm | |||
| github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | |||
| github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= | |||
| github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= | |||
| github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= | |||
| github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | |||
| github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |||
| github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |||
| github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= | |||
| @@ -709,12 +713,14 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 | |||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
| github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= | |||
| github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= | |||
| github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= | |||
| github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= | |||
| github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= | |||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
| github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
| github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
| github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
| github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= | |||
| github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
| github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | |||
| github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= | |||
| @@ -804,8 +810,16 @@ github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo= | |||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
| github.com/yuin/goldmark v1.1.30 h1:j4d4Lw3zqZelDhBksEo3BnWg9xhXRQGJPPSL6OApZjI= | |||
| github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
| github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
| github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
| github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= | |||
| github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | |||
| github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= | |||
| github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU= | |||
| github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo= | |||
| github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60/go.mod h1:i9VhcIHN2PxXMbQrKqXNueok6QNONoPjNMoj9MygVL0= | |||
| github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= | |||
| github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= | |||
| github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= | |||
| github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= | |||
| go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | |||
| @@ -1086,6 +1100,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= | |||
| gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | |||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | |||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
| grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= | |||
| @@ -0,0 +1,688 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en-US"> | |||
| <head data-suburl=""> | |||
| <meta charset="utf-8"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <meta http-equiv="x-ua-compatible" content="ie=edge"> | |||
| <title> OpenI</title> | |||
| <link rel="manifest" href="/manifest.json" crossorigin="use-credentials"> | |||
| <script> | |||
| if ('serviceWorker' in navigator) { | |||
| navigator.serviceWorker.register('/serviceworker.js').then(function(registration) { | |||
| console.info('ServiceWorker registration successful with scope: ', registration.scope); | |||
| }, function(err) { | |||
| console.info('ServiceWorker registration failed: ', err); | |||
| }); | |||
| } | |||
| </script> | |||
| <meta name="theme-color" content="#6cc644"> | |||
| <meta name="author" content="OpenI - open i project management" /> | |||
| <meta name="description" content="Efficient code management center, you can host and review code" /> | |||
| <meta name="keywords" content="OpenI,git"> | |||
| <meta name="referrer" content="no-referrer" /> | |||
| <meta name="_csrf" content="R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ" /> | |||
| <script> | |||
| /* | |||
| @licstart The following is the entire license notice for the | |||
| JavaScript code in this page. | |||
| Copyright (c) 2016 The Gitea Authors | |||
| Copyright (c) 2015 The Gogs Authors | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| of this software and associated documentation files (the "Software"), to deal | |||
| in the Software without restriction, including without limitation the rights | |||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| copies of the Software, and to permit persons to whom the Software is | |||
| furnished to do so, subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be included in | |||
| all copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| THE SOFTWARE. | |||
| --- | |||
| Licensing information for additional javascript libraries can be found at: | |||
| {{StaticUrlPrefix}}/vendor/librejs.html | |||
| @licend The above is the entire license notice | |||
| for the JavaScript code in this page. | |||
| */ | |||
| </script> | |||
| <script> | |||
| window.config = { | |||
| AppSubUrl: '', | |||
| StaticUrlPrefix: '', | |||
| csrf: 'R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ', | |||
| HighlightJS: false, | |||
| Minicolors: false, | |||
| SimpleMDE: false, | |||
| Tribute: false, | |||
| U2F: false, | |||
| Heatmap: false, | |||
| heatmapUser: null, | |||
| NotificationSettings: { | |||
| MinTimeout: 10000 , | |||
| TimeoutStep: 10000 , | |||
| MaxTimeout: 60000 , | |||
| EventSourceUpdateTime: 10000 , | |||
| }, | |||
| }; | |||
| </script> | |||
| <link rel="shortcut icon" href="/img/favicon.png"> | |||
| <link rel="mask-icon" href="/img/openi-safari.svg" color="#609926"> | |||
| <link rel="fluid-icon" href="/img/gitea-lg.png" title="OpenI"> | |||
| <link rel="stylesheet" href="/vendor/assets/font-awesome/css/font-awesome.min.css"> | |||
| <link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
| <link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
| <link rel="stylesheet" href="/css/git.openi.css"> | |||
| <link rel="stylesheet" href="/fomantic/semantic.min.css?v=eef985e4d4b587d055fc7c3eff3f18e9"> | |||
| <link rel="stylesheet" href="/css/index.css?v=eef985e4d4b587d055fc7c3eff3f18e9"> | |||
| <noscript> | |||
| <style> | |||
| .dropdown:hover > .menu { display: block; } | |||
| .ui.secondary.menu .dropdown.item > .menu { margin-top: 0; } | |||
| </style> | |||
| </noscript> | |||
| <style class="list-search-style"></style> | |||
| <meta property="og:title" content="OpenI"> | |||
| <meta property="og:type" content="website" /> | |||
| <meta property="og:image" content="/img/gitea-lg.png" /> | |||
| <meta property="og:url" content="https://git.openi.org.cn/" /> | |||
| <meta property="og:description" content="Efficient code management center, you can host and review code"> | |||
| <meta property="og:site_name" content="OpenI" /> | |||
| <script> | |||
| var _hmt = _hmt || []; | |||
| (function() { | |||
| var hm = document.createElement("script"); | |||
| hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
| var s = document.getElementsByTagName("script")[0]; | |||
| s.parentNode.insertBefore(hm, s); | |||
| })(); | |||
| </script> | |||
| <script src="/self/func.js" type="text/javascript"></script> | |||
| <link rel="stylesheet" href="/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css"> | |||
| <link rel="stylesheet" href="/swiper/swiper-bundle.min.css"> | |||
| <script src="/swiper/swiper-bundle.min.js"></script> | |||
| <link rel="stylesheet" href="/rotation3D/rotation3D.css"> | |||
| </head> | |||
| <body> | |||
| <div class="full height"> | |||
| <noscript>This website works better with JavaScript.</noscript> | |||
| <div class="ui top secondary stackable main menu following bar dark"> | |||
| <div class="ui container" id="navbar"> | |||
| <div class="item brand" style="justify-content: space-between;"> | |||
| <a href="https://openi.org.cn/"> | |||
| <img class="ui mini image" src="/img/logo-w.svg"> | |||
| </a> | |||
| <div class="ui basic icon button mobile-only" id="navbar-expand-toggle"> | |||
| <i class="sidebar icon"></i> | |||
| </div> | |||
| </div> | |||
| <div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div> | |||
| <div class="item brand" style="margin-left: 0.9rem;"> | |||
| <a href="/"> | |||
| <img class="ui mini image" style="height: 1.3rem;" src="/img/git-logo.svg"> | |||
| </a> | |||
| </div> | |||
| <div class="item edge"> | |||
| <div class="dropdown-menu"> | |||
| <a class=" item lfpd" href="/user/login"> | |||
| Home <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="/user/login">Issues</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="/user/login">Pull Requests</a> | |||
| <a style="border: none;color: #000;" class=" item" href="/user/login">Milestones</a> | |||
| <a style="border: none;color: #000;" class=" item" href="/cloudbrains">Cloudbrain Task</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="/explore/repos">Repositories</a> | |||
| <a class="item" href="/explore/datasets">Datasets</a> | |||
| <div class="ui simple dropdown item" id='dropdown_PageHome'> | |||
| Explore | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu" > | |||
| <a class="item" href="/explore/users">Users</a> | |||
| <a class="item" href="/explore/organizations">Organizations</a> | |||
| <a class="item" href="/explore/images">Cloudbrain Mirror</a> | |||
| <a class="item" href="/OpenI">OpenI Projects</a> | |||
| </div> | |||
| </div> | |||
| <div class="right stackable menu"> | |||
| <form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
| <input name="q" value="" placeholder="Search..." | |||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
| <input type="hidden" name="tab" value=""> | |||
| <input type="hidden" name="sort" value="hot"> | |||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
| </button> | |||
| </div> | |||
| </form> | |||
| <a class="item" href="/user/sign_up"> | |||
| <svg class="svg octicon-person" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-person" /></svg> Register | |||
| </a> | |||
| <a class="item" rel="nofollow" href="/user/login"> | |||
| <svg class="svg octicon-sign-in" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-sign-in" /></svg> Sign In | |||
| </a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="notic_content" id ="notic_content" style="display: block; position: relative"> | |||
| <div class="ui container"> | |||
| <marquee behavior="scroll" direction="left"> | |||
| <a href=https://openi.org.cn/html/2022/notices_0701/636.html class="a_width" style = 'margin-left: 0px !important;' target="_blank"> | |||
| <i class="ri-arrow-right-s-line"></i> | |||
| “我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认>>> | |||
| </a> | |||
| <a href=https://git.openi.org.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md class="a_width" target="_blank"> | |||
| <i class="ri-arrow-right-s-line"></i> | |||
| 7月中下旬登录启智AI协作平台,需登记手机号码啦>>> | |||
| </a> | |||
| <a href=https://openi.org.cn/html/2022/dongtai_0628/634.html class="a_width" target="_blank"> | |||
| <i class="ri-arrow-right-s-line"></i> | |||
| 智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~>>> | |||
| </a> | |||
| <a href=https://wj.qq.com/s2/10362208/5c0c class="a_width" target="_blank"> | |||
| <i class="ri-arrow-right-s-line"></i> | |||
| 启智AI协作平台问卷调查,邀请您参加>>> | |||
| </a> | |||
| </marquee> | |||
| <div class="item right" style="position:absolute;right: 1px;top:0px;"> | |||
| <i class="ri-close-fill x_icon" onclick="closeNoice()"></i> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <script> | |||
| function closeNoice(){ | |||
| document.getElementById("notic_content").style.display='none' | |||
| localStorage.setItem("isCloseNotice",true) | |||
| } | |||
| function isShowNotice(){ | |||
| var current_notice = localStorage.getItem("notices") | |||
| if (current_notice != "f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de"){ | |||
| localStorage.setItem('notices',"f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de"); | |||
| isNewNotice=true; | |||
| localStorage.setItem("isCloseNotice",false) | |||
| }else{ | |||
| isNewNotice=false; | |||
| } | |||
| let isShowNoticeTag = false; | |||
| let notices= [{"Title":"“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/notices_0701/636.html","Visible":1},{"Title":"7月中下旬登录启智AI协作平台,需登记手机号码啦\u003e\u003e\u003e","Link":"https://git.openi.org.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md","Visible":1},{"Title":"智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/dongtai_0628/634.html","Visible":1},{"Title":"启智AI协作平台问卷调查,邀请您参加\u003e\u003e\u003e","Link":"https://wj.qq.com/s2/10362208/5c0c","Visible":1}] | |||
| if(notices != null && notices!=''){ | |||
| for (i =0;i<notices.length;i++){ | |||
| if (notices[i].Visible==1){ | |||
| isShowNoticeTag =true; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (isShowNoticeTag){ | |||
| if(isNewNotice){ | |||
| document.getElementById("notic_content").style.display='block' | |||
| }else{ | |||
| isCloseNotice = localStorage.getItem("isCloseNotice") | |||
| if (JSON.parse(isCloseNotice)){ | |||
| document.getElementById("notic_content").style.display='none' | |||
| }else{ | |||
| document.getElementById("notic_content").style.display='block' | |||
| } | |||
| } | |||
| }else{ | |||
| if (document.getElementById("notic_content") != null){ | |||
| document.getElementById("notic_content").style.display='none' | |||
| } | |||
| } | |||
| } | |||
| if(!("" == true || "" =='true')) { | |||
| isShowNotice(); | |||
| } | |||
| </script> | |||
| <div class="ui vertical masthead secondary hometop segment"> | |||
| <div class="ui container" style="position: relative;"> | |||
| <div class="ui center homebanner"> | |||
| <h1 class="ui huge header"> | |||
| Explore Better AI | |||
| <div class="sub header"> | |||
| OpenI AI Development Cooperation Platform | |||
| </div> | |||
| </h1> | |||
| <p class="ui am-lh-18">The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation</p> | |||
| <a class="circular huge ui secondary button" href="/user/login">Use Now <i class="right arrow icon"></i></a> | |||
| </div> | |||
| <div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div> | |||
| <div id="homenews"> | |||
| <p>* Only show the dynamics of open source projects</p> | |||
| <div class="ui grid"> | |||
| <div class="sixteen wide mobile twelve wide tablet ten wide computer column homenews"> | |||
| <div class="newslist"> | |||
| <div class="ui mini aligned list swiper-wrapper" id="newmessage"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="ui container homeorg"> | |||
| <div class="ui stackable grid"> | |||
| <div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
| <h2>Recommended Organizations</h2> | |||
| <p><span class="ui text grey">These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here, </span><a href="/OpenIOSSG/promote/">Click here to submit.</a></p> | |||
| <a href="/explore/organizations" class="circular ui primary basic button">More Organizations <i class="arrow circle right icon"></i></a> | |||
| </div> | |||
| <div class="sixteen wide tablet twelve wide computer column"> | |||
| <div class="homeorg-list"> | |||
| <div class="swiper-wrapper" id="recommendorg"> | |||
| </div> | |||
| <div class="swiper-pagination"></div> | |||
| </div> | |||
| </div> | |||
| <div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
| <h2>Community Activities</h2> | |||
| <p><span class="ui text grey">The community has prepared a wealth of activities, waiting for you to participate!</p> | |||
| </div> | |||
| <div class="sixteen wide tablet twelve wide computer column"> | |||
| <div class="event-list"> | |||
| <div class="swiper-wrapper" id="recommendactivity"> | |||
| </div> | |||
| <div class="swiper-pagination"></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="leftline01"></div> | |||
| </div> | |||
| <div class="ui container homepro"> | |||
| <div class="leftline02"></div> | |||
| <div class="leftline02-2"></div> | |||
| <div class="ui center homepro-tit am-mb-20"> | |||
| <h2>Recommended Projects</h2> | |||
| <p><span class="ui text grey">Excellent AI projects recommendation. To show your project here, </span><a href="/OpenIOSSG/promote/">Click here to submit.</a>Click here to <a href="/explore/">explore more projects.</a></p> | |||
| </div> | |||
| <div class="homepro-list"> | |||
| <div class="swiper-wrapper" id="recommendrepo"> | |||
| </div> | |||
| <div class="swiper-pagination"></div> | |||
| </div> | |||
| </div> | |||
| <div class="ui vertical masthead secondary c2net segment"> | |||
| <div class="ui container"> | |||
| <div class="ui center am-pt-30 am-pb-30"> | |||
| <h2>智算网络</h2> | |||
| <p><span class="ui text grey">人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P</p> | |||
| </div> | |||
| <div id="app" v-cloak> | |||
| <div class="rotation3D-baseMap"></div> | |||
| <div id="rotation3D" class="rotation3D"> | |||
| <button class="center">中心</button> | |||
| <div class="itemList"> | |||
| <div class="rotation3D__item" :class="item.type" v-for="item in itemList"> | |||
| <div class="scale"> | |||
| <div class="baseImg"></div> | |||
| <div class="cont"> | |||
| <i class="iconfont" :class="item.icon"></i> | |||
| <p></p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="lineList"> | |||
| <div class="rotation3D__line" v-for="item in itemList" :class="item.type"> | |||
| <div v-if="item.type=='blue'" class="pos"> | |||
| <svg width="50" height="400"> | |||
| <path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
| </svg> | |||
| <div class="dot dot1 ri-arrow-left-s-line"><span></span></div> | |||
| </div> | |||
| <div v-if="item.type=='yellow'" class="pos"> | |||
| <svg width="10" height="400"> | |||
| <path id="path2" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
| </svg> | |||
| <div class="dot dot2"><i class="el-icon-close"></i></div> | |||
| </div> | |||
| <div v-if="item.type=='green'" class="pos"> | |||
| <svg width="50" height="400"> | |||
| <path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
| </svg> | |||
| <div class="dot dot1 ri-arrow-left-s-line"></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <a name="fourth"></a> | |||
| <div class="ui container i-env"> | |||
| <div class="ui center am-pb-30"> | |||
| <h2>Collaborative Development Environment</h2> | |||
| <p><span class="ui text grey">Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms.</p> | |||
| </div> | |||
| <div class="ui four doubling cards"> | |||
| <div class="card"> | |||
| <div class="image"> | |||
| <img src="/img/i-pic-01.jpg"> | |||
| </div> | |||
| <div class="content"> | |||
| <h3 class="ui centered small header">Unified Management of Development Elements</h3> | |||
| <div class="description ui text grey"> | |||
| The platform provides four elements of AI development: unified management of model code, data set, model and execution environment. | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="card"> | |||
| <div class="image"> | |||
| <img src="/img/i-pic-02.jpg"> | |||
| </div> | |||
| <div class="content"> | |||
| <h3 class="ui centered small header">Data Collaboration and Sharing</h3> | |||
| <div class="description ui text grey"> | |||
| By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset. | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="card"> | |||
| <div class="image"> | |||
| <img src="/img/i-pic-03.jpg"> | |||
| </div> | |||
| <div class="content"> | |||
| <h3 class="ui centered small header">Model Management and Sharing</h3> | |||
| <div class="description ui text grey"> | |||
| Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="card"> | |||
| <div class="image"> | |||
| <img src="/img/i-pic-04.jpg"> | |||
| </div> | |||
| <div class="content"> | |||
| <h3 class="ui centered small header">Once Configuration, Multiple Reuse</h3> | |||
| <div class="description ui text grey"> | |||
| Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <a name="fifth"></a> | |||
| <div class="ui container"> | |||
| <div class="ui very padded inverted segment radius15"> | |||
| <div class="ui stackable grid"> | |||
| <div class="six wide column"> | |||
| <img class="ui centered large image" src="/img/i-yunnao.svg"> | |||
| </div> | |||
| <div class="ten wide column am-pt-30"> | |||
| <h2 class="ui grey inverted header">PengCheng Cloudbrain Open Source Collaboration</h2> | |||
| <p class="am-lh-18 ui text grey"> | |||
| The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks.<br> | |||
| Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors.<br> | |||
| Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments.<br> | |||
| If your model requires more computing resources, you can also apply for it separately.<br> | |||
| </p> | |||
| <a class="ui blue basic button am-mt-20" href="/user/login">Use Now</a> | |||
| <a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">Apply Separately</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="am-mt-30"></div> | |||
| <script src="/self/js/jquery.min.js" type="text/javascript"></script> | |||
| <script src="/home/home.js?v=eef985e4d4b587d055fc7c3eff3f18e9" type="text/javascript"></script> | |||
| </div> | |||
| <footer> | |||
| <div class="ui container"> | |||
| <div class="ui grid"> | |||
| <div class="sixteen wide mobile eight wide tablet eight wide computer column"> | |||
| <div class="ui three column grid"> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">Community</div> | |||
| <a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Council</a> | |||
| <a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Technical Committee</a> | |||
| <a href="https://openi.org.cn/html/Club/2019/0228/17.html" class="item">Join OpenI</a> | |||
| <a href="/home/term/" class="item">Use agreement</a> | |||
| </div> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">News</div> | |||
| <a href="https://openi.org.cn/html/news/dongtai/" class="item">Community News</a> | |||
| <a href="https://openi.org.cn/html/news/huodong/" class="item">Member news</a> | |||
| <a href="https://openi.org.cn/html/news/zixun/" class="item">Industry Advisory</a> | |||
| </div> | |||
| <div class="column ui vertical text menu"> | |||
| <div class="header item">help</div> | |||
| <div class="ui language bottom floating slide up dropdown link item"> | |||
| <i class="world icon"></i> | |||
| <div class="text">English</div> | |||
| <div class="menu"> | |||
| <a lang="en-US" class="item active selected" href="#">English</a> | |||
| <a lang="zh-CN" class="item " href="?lang=zh-CN">简体中文</a> | |||
| </div> | |||
| </div> | |||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">Tutorial</p> </a> | |||
| <a href="/api/swagger" class=" item a_margin"><i class="ri-exchange-line footer_icon" > </i><p class="footer_icon">API</p> </a> | |||
| <a href="/user/login" class=" item a_margin" ><i class="ri-mail-send-line footer_icon" ></i><p class="footer_icon">Feedback</p></a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="sixteen wide mobile eight wide tablet eight wide computer column" style=" margin:2.0rem 0"> | |||
| Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI) <a href="http://beian.miit.gov.cn/" target="_blank">京ICP备18004880号</a> | |||
| <br> | |||
| Powered_by 鹏城实验室云脑、<a href="https://www.trustie.net/" target="_blank">Trustie确实</a>、gitea | |||
| <br> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </footer> | |||
| <script src="/js/jquery.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
| <script rel="stylesheet" src="/vendor/plugins/jquery.particleground/jquery.particleground.min.js"></script> | |||
| <script src="/fomantic/semantic.min.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
| <script src="/js/index.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
| <script src="/rotation3D/vue-2.6.10.min.js"></script> | |||
| <script src="/rotation3D/rotation3D.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
| <script> | |||
| var app = new Vue({ | |||
| el: "#app", | |||
| data: { | |||
| itemList: [ | |||
| { name:'鹏城云脑一号', type:'blue', icon:'', }, | |||
| { name:'鹏城云脑二号', type:'blue', icon:'', }, | |||
| { name:'北大人工智能集群系统', type:'green', icon:'', }, | |||
| { name:'合肥类脑智能开放平台', type:'green', icon:'', }, | |||
| { name:'武汉人工智能计算中心', type:'green', icon:'', }, | |||
| { name:'西安未来人工智能计算中心', type:'green', icon:'', }, | |||
| { name:'……', type:'yellow', icon:'', }, | |||
| { name:'中原人工智能计算中心', type:'green', icon:'', }, | |||
| { name:'成都人工智能计算中心', type:'green', icon:'', }, | |||
| { name:'横琴先进智能计算中心', type:'green', icon:'', }, | |||
| { name:'国家超级计算济南中心', type:'green', icon:'', }, | |||
| ], | |||
| }, | |||
| mounted: function () { | |||
| new Rotation3D({ | |||
| id: '#rotation3D', | |||
| farScale: 0.6, | |||
| xRadius: 0, | |||
| yRadius: 130, | |||
| }) | |||
| }, | |||
| methods: {}, | |||
| }); | |||
| </script> | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,49 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "encoding/json" | |||
| ) | |||
| type AdminOperateLog struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| BizType string | |||
| OperateType string | |||
| OldValue string `xorm:"TEXT"` | |||
| NewValue string `xorm:"TEXT"` | |||
| RelatedId string `xorm:"INDEX"` | |||
| Comment string | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| CreatedBy int64 | |||
| } | |||
| type LogValues struct { | |||
| Params []LogValue | |||
| } | |||
| type LogValue struct { | |||
| Key string | |||
| Val interface{} | |||
| } | |||
| func (l *LogValues) Add(key string, val interface{}) *LogValues { | |||
| l.Params = append(l.Params, LogValue{Key: key, Val: val}) | |||
| return l | |||
| } | |||
| func (l *LogValues) JsonString() string { | |||
| if len(l.Params) == 0 { | |||
| return "" | |||
| } | |||
| b, err := json.Marshal(l) | |||
| if err != nil { | |||
| log.Error("LogValues JsonString error . %v", err) | |||
| return "" | |||
| } | |||
| return string(b) | |||
| } | |||
| func InsertAdminOperateLog(log AdminOperateLog) (int64, error) { | |||
| return x.Insert(&log) | |||
| } | |||
| @@ -2,6 +2,7 @@ package models | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| @@ -39,6 +40,40 @@ type AiModelManage struct { | |||
| IsCanDelete bool | |||
| } | |||
| type AiModelConvert struct { | |||
| ID string `xorm:"pk"` | |||
| Name string `xorm:"INDEX NOT NULL"` | |||
| Status string `xorm:"NULL"` | |||
| StatusResult string `xorm:"NULL"` | |||
| SrcEngine int `xorm:"NOT NULL DEFAULT 0"` | |||
| RepoId int64 `xorm:"INDEX NULL"` | |||
| ModelId string `xorm:"NOT NULL"` | |||
| ModelName string `xorm:"NULL"` | |||
| ModelVersion string `xorm:"NOT NULL"` | |||
| ModelPath string `xorm:"NULL"` | |||
| DestFormat int `xorm:"NOT NULL DEFAULT 0"` | |||
| NetOutputFormat int `xorm:"NULL"` | |||
| UserId int64 `xorm:"NOT NULL"` | |||
| CloudBrainTaskId string `xorm:"NULL"` | |||
| ModelArtsVersionId string `xorm:"NULL"` | |||
| ContainerID string | |||
| ContainerIp string | |||
| RunTime int64 `xorm:"NULL"` | |||
| TrainJobDuration string | |||
| InputShape string `xorm:"varchar(2000)"` | |||
| InputDataFormat string `xorm:"NOT NULL"` | |||
| Description string `xorm:"varchar(2000)"` | |||
| Path string `xorm:"varchar(400) NOT NULL"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
| StartTime timeutil.TimeStamp | |||
| EndTime timeutil.TimeStamp | |||
| UserName string | |||
| UserRelAvatarLink string | |||
| IsCanOper bool | |||
| IsCanDelete bool | |||
| } | |||
| type AiModelQueryOptions struct { | |||
| ListOptions | |||
| RepoID int64 // include all repos if empty | |||
| @@ -47,7 +82,124 @@ type AiModelQueryOptions struct { | |||
| SortType string | |||
| New int | |||
| // JobStatus CloudbrainStatus | |||
| Type int | |||
| Type int | |||
| Status int | |||
| } | |||
| func (a *AiModelConvert) IsGpuTrainTask() bool { | |||
| if a.SrcEngine == 0 || a.SrcEngine == 1 { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| func ModelComputeAndSetDuration(task *AiModelConvert, result JobResultPayload) { | |||
| if task.StartTime == 0 { | |||
| task.StartTime = timeutil.TimeStamp(result.JobStatus.CreatedTime / 1000) | |||
| } | |||
| if task.EndTime == 0 { | |||
| if result.JobStatus.CompletedTime > 0 { | |||
| task.EndTime = timeutil.TimeStamp(result.JobStatus.CompletedTime / 1000) | |||
| } | |||
| } | |||
| var d int64 | |||
| if task.StartTime == 0 { | |||
| d = 0 | |||
| } else if task.EndTime == 0 { | |||
| d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||
| } else { | |||
| d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||
| } | |||
| if d < 0 { | |||
| d = 0 | |||
| } | |||
| task.RunTime = d | |||
| task.TrainJobDuration = ConvertDurationToStr(d) | |||
| } | |||
| func ModelConvertSetDuration(task *AiModelConvert) { | |||
| var d int64 | |||
| if task.StartTime == 0 { | |||
| d = 0 | |||
| } else if task.EndTime == 0 { | |||
| d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||
| } else { | |||
| d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||
| } | |||
| if d < 0 { | |||
| d = 0 | |||
| } | |||
| task.RunTime = d | |||
| task.TrainJobDuration = ConvertDurationToStr(d) | |||
| } | |||
| func UpdateModelConvertModelArts(id string, CloudBrainTaskId string, VersionId string) error { | |||
| var sess *xorm.Session | |||
| sess = x.ID(id) | |||
| defer sess.Close() | |||
| re, err := sess.Cols("cloud_brain_task_id,model_arts_version_id").Update(&AiModelConvert{ | |||
| CloudBrainTaskId: CloudBrainTaskId, | |||
| ModelArtsVersionId: VersionId, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func UpdateModelConvertFailed(id string, status string, statusResult string) error { | |||
| var sess *xorm.Session | |||
| sess = x.ID(id) | |||
| defer sess.Close() | |||
| re, err := sess.Cols("status", "status_result").Update(&AiModelConvert{ | |||
| Status: status, | |||
| StatusResult: statusResult, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func UpdateModelConvertCBTI(id string, CloudBrainTaskId string) error { | |||
| var sess *xorm.Session | |||
| sess = x.ID(id) | |||
| defer sess.Close() | |||
| re, err := sess.Cols("cloud_brain_task_id").Update(&AiModelConvert{ | |||
| CloudBrainTaskId: CloudBrainTaskId, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func UpdateModelConvert(job *AiModelConvert) error { | |||
| return updateModelConvert(x, job) | |||
| } | |||
| func updateModelConvert(e Engine, job *AiModelConvert) error { | |||
| var sess *xorm.Session | |||
| sess = e.Where("id = ?", job.ID) | |||
| _, err := sess.Cols("status", "train_job_duration", "run_time", "start_time", "end_time", "updated_unix").Update(job) | |||
| return err | |||
| } | |||
| func SaveModelConvert(modelConvert *AiModelConvert) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| re, err := sess.Insert(modelConvert) | |||
| if err != nil { | |||
| log.Info("insert modelConvert error." + err.Error()) | |||
| return err | |||
| } | |||
| log.Info("success to save modelConvert db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func SaveModelToDb(model *AiModelManage) error { | |||
| @@ -63,6 +215,20 @@ func SaveModelToDb(model *AiModelManage) error { | |||
| return nil | |||
| } | |||
| func QueryModelConvertById(id string) (*AiModelConvert, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| sess.Select("*").Table(new(AiModelConvert)).Where("id='" + id + "'") | |||
| aiModelManageConvertList := make([]*AiModelConvert, 0) | |||
| err := sess.Find(&aiModelManageConvertList) | |||
| if err == nil { | |||
| if len(aiModelManageConvertList) == 1 { | |||
| return aiModelManageConvertList[0], nil | |||
| } | |||
| } | |||
| return nil, err | |||
| } | |||
| func QueryModelById(id string) (*AiModelManage, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| @@ -74,14 +240,28 @@ func QueryModelById(id string) (*AiModelManage, error) { | |||
| if len(aiModelManageList) == 1 { | |||
| return aiModelManageList[0], nil | |||
| } | |||
| } else { | |||
| log.Info("error=" + err.Error()) | |||
| } | |||
| return nil, err | |||
| } | |||
| func DeleteModelById(id string) error { | |||
| func DeleteModelConvertById(id string) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| re, err := sess.Delete(&AiModelConvert{ | |||
| ID: id, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| log.Info("success to delete AiModelManageConvert from db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func DeleteModelById(id string) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| re, err := sess.Delete(&AiModelManage{ | |||
| ID: id, | |||
| }) | |||
| @@ -90,7 +270,6 @@ func DeleteModelById(id string) error { | |||
| } | |||
| log.Info("success to delete from db.re=" + fmt.Sprint((re))) | |||
| return nil | |||
| } | |||
| func ModifyModelDescription(id string, description string) error { | |||
| @@ -201,3 +380,73 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
| return aiModelManages, count, nil | |||
| } | |||
| func QueryModelConvertByRepoID(repoId int64) ([]*AiModelConvert, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var cond = builder.NewCond() | |||
| cond = cond.And( | |||
| builder.Eq{"ai_model_convert.repo_id": repoId}, | |||
| ) | |||
| sess.OrderBy("ai_model_convert.created_unix DESC") | |||
| aiModelManageConvert := make([]*AiModelConvert, 0) | |||
| if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
| Find(&aiModelManageConvert); err != nil { | |||
| return nil, fmt.Errorf("Find: %v", err) | |||
| } | |||
| return aiModelManageConvert, nil | |||
| } | |||
| func QueryModelConvertByUserID(userID int64) ([]*AiModelConvert, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var cond = builder.NewCond() | |||
| cond = cond.And( | |||
| builder.Eq{"ai_model_convert.user_id": userID}, | |||
| ) | |||
| sess.OrderBy("ai_model_convert.created_unix DESC") | |||
| aiModelManageConvert := make([]*AiModelConvert, 0) | |||
| if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
| Find(&aiModelManageConvert); err != nil { | |||
| return nil, fmt.Errorf("Find: %v", err) | |||
| } | |||
| return aiModelManageConvert, nil | |||
| } | |||
| func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelConvert, int64, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var cond = builder.NewCond() | |||
| if opts.RepoID > 0 { | |||
| cond = cond.And( | |||
| builder.Eq{"ai_model_convert.repo_id": opts.RepoID}, | |||
| ) | |||
| } | |||
| if opts.UserID > 0 { | |||
| cond = cond.And( | |||
| builder.Eq{"ai_model_convert.user_id": opts.UserID}, | |||
| ) | |||
| } | |||
| count, err := sess.Where(cond).Count(new(AiModelConvert)) | |||
| if err != nil { | |||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||
| } | |||
| if opts.Page >= 0 && opts.PageSize > 0 { | |||
| var start int | |||
| if opts.Page == 0 { | |||
| start = 0 | |||
| } else { | |||
| start = (opts.Page - 1) * opts.PageSize | |||
| } | |||
| sess.Limit(opts.PageSize, start) | |||
| } | |||
| sess.OrderBy("ai_model_convert.created_unix DESC") | |||
| aiModelManageConvert := make([]*AiModelConvert, 0, setting.UI.IssuePagingNum) | |||
| if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
| Find(&aiModelManageConvert); err != nil { | |||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||
| } | |||
| return aiModelManageConvert, count, nil | |||
| } | |||
| @@ -111,6 +111,20 @@ const ( | |||
| GrampusStatusWaiting = "WAITING" | |||
| ) | |||
| const ( | |||
| //cluster | |||
| OpenICluster = "OpenI" | |||
| C2NetCluster = "C2Net" | |||
| //AI center | |||
| AICenterOfCloudBrainOne = "OpenIOne" | |||
| AICenterOfCloudBrainTwo = "OpenITwo" | |||
| //ComputeResource | |||
| GPU = "GPU" | |||
| NPU = "NPU" | |||
| ) | |||
| type Cloudbrain struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| JobID string `xorm:"INDEX NOT NULL"` | |||
| @@ -134,14 +148,16 @@ type Cloudbrain struct { | |||
| CanDebug bool `xorm:"-"` | |||
| CanDel bool `xorm:"-"` | |||
| CanModify bool `xorm:"-"` | |||
| Type int | |||
| Type int `xorm:"INDEX"` | |||
| BenchmarkTypeID int | |||
| BenchmarkChildTypeID int | |||
| CardType string | |||
| Cluster string | |||
| VersionID int64 //版本id | |||
| VersionName string `xorm:"INDEX"` //当前版本 | |||
| Uuid string //数据集id | |||
| DatasetName string | |||
| DatasetName string `xorm:"varchar(2000)"` | |||
| VersionCount int //任务的当前版本数量,不包括删除的 | |||
| IsLatestVersion string //是否是最新版本,1是,0否 | |||
| CommitID string //提交的仓库代码id | |||
| @@ -164,12 +180,11 @@ type Cloudbrain struct { | |||
| FlavorName string //规格名称 | |||
| EngineName string //引擎名称 | |||
| TotalVersionCount int //任务的所有版本数量,包括删除的 | |||
| LabelName string //标签名称 | |||
| ModelName string //模型名称 | |||
| ModelVersion string //模型版本 | |||
| CkptName string //权重文件名称 | |||
| ResultUrl string //推理结果的obs路径 | |||
| LabelName string //标签名称 | |||
| ModelName string //模型名称 | |||
| ModelVersion string //模型版本 | |||
| CkptName string //权重文件名称 | |||
| ResultUrl string //推理结果的obs路径 | |||
| User *User `xorm:"-"` | |||
| Repo *Repository `xorm:"-"` | |||
| @@ -178,6 +193,7 @@ type Cloudbrain struct { | |||
| BenchmarkTypeRankLink string `xorm:"-"` | |||
| StartTime timeutil.TimeStamp | |||
| EndTime timeutil.TimeStamp | |||
| Spec *Specification `xorm:"-"` | |||
| } | |||
| type CloudbrainShow struct { | |||
| @@ -246,7 +262,16 @@ func (task *Cloudbrain) CorrectCreateUnix() { | |||
| func (task *Cloudbrain) IsTerminal() bool { | |||
| status := task.Status | |||
| return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded) | |||
| return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || | |||
| status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || | |||
| status == string(JobStopped) || status == string(JobFailed) || | |||
| status == string(JobSucceeded) || status == GrampusStatusFailed || | |||
| status == GrampusStatusSucceeded || status == GrampusStatusStopped | |||
| } | |||
| func (task *Cloudbrain) IsRunning() bool { | |||
| status := task.Status | |||
| return status == string(ModelArtsTrainJobRunning) || status == string(ModelArtsRunning) || | |||
| status == string(JobRunning) || status == GrampusStatusRunning | |||
| } | |||
| func ConvertDurationToStr(duration int64) string { | |||
| @@ -345,6 +370,22 @@ type CreateJobResult struct { | |||
| Payload map[string]interface{} `json:"payload"` | |||
| } | |||
| type QueueDetailResult struct { | |||
| Code string `json:"code"` | |||
| Msg string `json:"msg"` | |||
| Payload map[string]QueueDetail `json:"payload"` | |||
| } | |||
| type QueueDetail struct { | |||
| JobScheduleInfo JobScheduleInfo `json:"JobScheduleInfo"` | |||
| } | |||
| type JobScheduleInfo struct { | |||
| Pending int `json:"Pending"` | |||
| Running int `json:"Running"` | |||
| MedianPendingJobDurationSec int `json:"MedianPendingJobDurationSec"` | |||
| } | |||
| type GetJobResult struct { | |||
| Code string `json:"code"` | |||
| Msg string `json:"msg"` | |||
| @@ -385,6 +426,9 @@ type CloudbrainsOptions struct { | |||
| ComputeResource string | |||
| BeginTimeUnix int64 | |||
| EndTimeUnix int64 | |||
| AiCenter string | |||
| NeedDeleteInfo string | |||
| Cluster string | |||
| } | |||
| type TaskPod struct { | |||
| @@ -617,6 +661,7 @@ type SpecialPool struct { | |||
| Pool []*GpuInfo `json:"pool"` | |||
| JobType []string `json:"jobType"` | |||
| ResourceSpec []*ResourceSpec `json:"resourceSpecs"` | |||
| Flavor []*FlavorInfo `json:"flavor"` | |||
| } | |||
| type ImageInfosModelArts struct { | |||
| @@ -958,6 +1003,28 @@ type NotebookDelResult struct { | |||
| InstanceID string `json:"instance_id"` | |||
| } | |||
| type CreateUserImageTrainJobParams struct { | |||
| JobName string `json:"job_name"` | |||
| Description string `json:"job_desc"` | |||
| Config UserImageConfig `json:"config"` | |||
| WorkspaceID string `json:"workspace_id"` | |||
| } | |||
| type UserImageConfig struct { | |||
| WorkServerNum int `json:"worker_server_num"` | |||
| AppUrl string `json:"app_url"` //训练作业的代码目录 | |||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | |||
| Parameter []Parameter `json:"parameter"` | |||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | |||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||
| LogUrl string `json:"log_url"` | |||
| UserImageUrl string `json:"user_image_url"` | |||
| UserCommand string `json:"user_command"` | |||
| CreateVersion bool `json:"create_version"` | |||
| Flavor Flavor `json:"flavor"` | |||
| PoolID string `json:"pool_id"` | |||
| } | |||
| type CreateTrainJobParams struct { | |||
| JobName string `json:"job_name"` | |||
| Description string `json:"job_desc"` | |||
| @@ -1005,6 +1072,11 @@ type CreateTrainJobVersionParams struct { | |||
| Config TrainJobVersionConfig `json:"config"` | |||
| } | |||
| type CreateTrainJobVersionUserImageParams struct { | |||
| Description string `json:"job_desc"` | |||
| Config TrainJobVersionUserImageConfig `json:"config"` | |||
| } | |||
| type TrainJobVersionConfig struct { | |||
| WorkServerNum int `json:"worker_server_num"` | |||
| AppUrl string `json:"app_url"` //训练作业的代码目录 | |||
| @@ -1019,6 +1091,21 @@ type TrainJobVersionConfig struct { | |||
| PreVersionId int64 `json:"pre_version_id"` | |||
| } | |||
| type TrainJobVersionUserImageConfig struct { | |||
| WorkServerNum int `json:"worker_server_num"` | |||
| AppUrl string `json:"app_url"` //训练作业的代码目录 | |||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | |||
| Parameter []Parameter `json:"parameter"` | |||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | |||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||
| LogUrl string `json:"log_url"` | |||
| Flavor Flavor `json:"flavor"` | |||
| PoolID string `json:"pool_id"` | |||
| PreVersionId int64 `json:"pre_version_id"` | |||
| UserImageUrl string `json:"user_image_url"` | |||
| UserCommand string `json:"user_command"` | |||
| } | |||
| type CreateConfigParams struct { | |||
| ConfigName string `json:"config_name"` | |||
| Description string `json:"config_desc"` | |||
| @@ -1231,6 +1318,52 @@ type LogFile struct { | |||
| Name string | |||
| } | |||
| type JobList struct { | |||
| JobName string `json:"job_name"` | |||
| JobID int64 `json:"job_id"` | |||
| VersionID int64 `json:"version_id"` | |||
| VersionCount int64 `json:"version_count"` | |||
| Description string `json:"job_desc"` | |||
| IntStatus int `json:"status"` | |||
| } | |||
| type GetTrainJobListResult struct { | |||
| ErrorResult | |||
| JobTotalCount int `json:"job_total_count"` //查询到的用户创建作业总数 | |||
| JobCountLimit int `json:"job_count_limit"` //用户还可以创建训练作业的数量 | |||
| Quotas int `json:"quotas"` //训练作业的运行数量上限 | |||
| JobList []JobList `json:"jobs"` | |||
| } | |||
| type JobVersionList struct { | |||
| VersionName string `json:"version_name"` | |||
| VersionID int64 `json:"version_id"` | |||
| IntStatus int `json:"status"` | |||
| } | |||
| type GetTrainJobVersionListResult struct { | |||
| ErrorResult | |||
| JobID int64 `json:"job_id"` | |||
| JobName string `json:"job_name"` | |||
| JobDesc string `json:"job_desc"` | |||
| VersionCount int64 `json:"version_count"` | |||
| JobVersionList []JobVersionList `json:"versions"` | |||
| } | |||
| type NotebookList struct { | |||
| JobName string `json:"name"` | |||
| JobID string `json:"id"` | |||
| Status string `json:"status"` | |||
| } | |||
| type GetNotebookListResult struct { | |||
| TotalCount int64 `json:"total"` //总的记录数量 | |||
| CurrentPage int `json:"current"` //当前页数 | |||
| TotalPages int `json:"pages"` //总的页数 | |||
| Size int `json:"size"` //每一页的数量 | |||
| NotebookList []NotebookList `json:"data"` | |||
| } | |||
| //Grampus | |||
| type GrampusResult struct { | |||
| ErrorCode int `json:"errorCode"` | |||
| @@ -1261,6 +1394,34 @@ type GrampusSpec struct { | |||
| Name string `json:"name"` | |||
| ProcessorType string `json:"processorType"` | |||
| Centers []Center `json:"centers"` | |||
| SpecInfo SpecInfo `json:"specInfo"` | |||
| } | |||
| type GrampusAiCenter struct { | |||
| AccDevices []GrampusAccDevice `json:"accDevices"` | |||
| Id string `json:"id"` | |||
| Name string `json:"name"` | |||
| Resource []GrampusCenterResource `json:"resource"` | |||
| } | |||
| type GrampusAccDevice struct { | |||
| Kind string `json:"kind"` //加速卡类别, npu.huawei.com/NPU,nvidia.com/gpu,cambricon.com/mlu | |||
| Model string `json:"model"` //加速卡型号 | |||
| } | |||
| type GrampusCenterResource struct { | |||
| Allocated string `json:"allocated"` | |||
| Capacity string `json:"capacity"` | |||
| Name string `json:"name"` | |||
| } | |||
| type SpecInfo struct { | |||
| AccDeviceKind string `json:"accDeviceKind"` | |||
| AccDeviceMemory string `json:"accDeviceMemory"` | |||
| AccDeviceModel string `json:"accDeviceModel"` | |||
| AccDeviceNum int `json:"accDeviceNum"` | |||
| CpuCoreNum int `json:"cpuCoreNum"` | |||
| MemorySize string `json:"memorySize"` | |||
| } | |||
| type GetGrampusResourceSpecsResult struct { | |||
| @@ -1268,6 +1429,12 @@ type GetGrampusResourceSpecsResult struct { | |||
| Infos []GrampusSpec `json:"resourceSpecs"` | |||
| } | |||
| type GetGrampusAiCentersResult struct { | |||
| GrampusResult | |||
| Infos []GrampusAiCenter `json:"aiCenterInfos"` | |||
| TotalSize int `json:"totalSize"` | |||
| } | |||
| type GrampusImage struct { | |||
| CreatedAt int64 `json:"createdAt"` | |||
| UpdatedAt int64 `json:"updatedAt"` | |||
| @@ -1375,6 +1542,23 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| ) | |||
| } | |||
| } | |||
| if (opts.AiCenter) != "" { | |||
| cond = cond.And( | |||
| builder.Like{"cloudbrain.ai_center", opts.AiCenter}, | |||
| ) | |||
| } | |||
| if (opts.Cluster) != "" { | |||
| if opts.Cluster == "resource_cluster_openi" { | |||
| cond = cond.And( | |||
| builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}), | |||
| ) | |||
| } | |||
| if opts.Cluster == "resource_cluster_c2net" { | |||
| cond = cond.And( | |||
| builder.Eq{"cloudbrain.type": TypeC2Net}, | |||
| ) | |||
| } | |||
| } | |||
| if (opts.IsLatestVersion) != "" { | |||
| cond = cond.And(builder.Or(builder.And(builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion}, builder.Eq{"cloudbrain.job_type": "TRAIN"}), builder.Neq{"cloudbrain.job_type": "TRAIN"})) | |||
| @@ -1455,7 +1639,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| return cloudbrains, count, nil | |||
| } | |||
| func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) { | |||
| func QueryModelTrainJobVersionList(jobId string) ([]*Cloudbrain, int, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| @@ -1470,7 +1654,7 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) | |||
| ) | |||
| sess.OrderBy("cloudbrain.created_unix DESC") | |||
| cloudbrains := make([]*CloudbrainInfo, 0) | |||
| cloudbrains := make([]*Cloudbrain, 0) | |||
| if err := sess.Table(&Cloudbrain{}).Where(cond). | |||
| Find(&cloudbrains); err != nil { | |||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||
| @@ -1492,9 +1676,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { | |||
| cond = cond.And( | |||
| builder.Eq{"job_type": "TRAIN"}, | |||
| ) | |||
| cond = cond.And( | |||
| builder.In("type", 0, 1), | |||
| ) | |||
| // cond = cond.And( | |||
| // builder.In("type", 0, 1), | |||
| // ) | |||
| cloudbrains := make([]*CloudbrainInfo, 0) | |||
| if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | |||
| @@ -1580,11 +1764,24 @@ func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, e | |||
| } | |||
| func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | |||
| session := x.NewSession() | |||
| defer session.Close() | |||
| err = session.Begin() | |||
| cloudbrain.TrainJobDuration = DURATION_STR_ZERO | |||
| if _, err = x.NoAutoTime().Insert(cloudbrain); err != nil { | |||
| if _, err = session.NoAutoTime().InsertOne(cloudbrain); err != nil { | |||
| session.Rollback() | |||
| return err | |||
| } | |||
| if cloudbrain.Spec != nil { | |||
| if _, err = session.Insert(NewCloudBrainSpec(cloudbrain.ID, *cloudbrain.Spec)); err != nil { | |||
| session.Rollback() | |||
| return err | |||
| } | |||
| } | |||
| session.Commit() | |||
| go IncreaseDatasetUseCount(cloudbrain.Uuid) | |||
| return nil | |||
| } | |||
| @@ -1652,12 +1849,34 @@ func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | |||
| return cloudBrains, err | |||
| } | |||
| func GetModelartsReDebugTaskByJobId(jobID string) ([]*Cloudbrain, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var cond = builder.NewCond() | |||
| cond = cond.And( | |||
| builder.Eq{"cloudbrain.job_id": jobID}, | |||
| ) | |||
| sess.OrderBy("cloudbrain.created_unix ASC limit 1") | |||
| cloudbrains := make([]*Cloudbrain, 0, 10) | |||
| if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
| Find(&cloudbrains); err != nil { | |||
| log.Info("find error.") | |||
| } | |||
| return cloudbrains, nil | |||
| } | |||
| func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) { | |||
| cloudBrains := make([]*Cloudbrain, 0) | |||
| err := x.Cols("job_id", "status", "type", "job_type", "version_id", "start_time").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||
| return cloudBrains, err | |||
| } | |||
| func GetCloudbrainsNeededDeleteByRepoID(repoID int64) ([]*Cloudbrain, error) { | |||
| cloudBrains := make([]*Cloudbrain, 0) | |||
| err := x.Where("repo_id=?", repoID).Find(&cloudBrains) | |||
| return cloudBrains, err | |||
| } | |||
| func GetCloudbrainsByDisplayJobName(repoID int64, jobType string, displayJobName string) ([]*Cloudbrain, error) { | |||
| cloudBrains := make([]*Cloudbrain, 0) | |||
| err := x.Cols("job_id", "job_name", "repo_id", "user_id", "job_type", "display_job_name").Where("repo_id=? AND job_type =? AND lower(display_job_name) = lower(?)", repoID, jobType, displayJobName).Find(&cloudBrains) | |||
| @@ -1784,6 +2003,17 @@ func GetBenchmarkCountByUserID(userID int64) (int, error) { | |||
| return int(count), err | |||
| } | |||
| func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...JobType) (int64, error) { | |||
| sess := x.Where("status=? and type=?", JobWaiting, cloudbrainType) | |||
| if len(jobTypes) > 0 { | |||
| sess.In("job_type", jobTypes) | |||
| } | |||
| if computeResource != "" { | |||
| sess.And("compute_resource=?", computeResource) | |||
| } | |||
| return sess.Count(new(Cloudbrain)) | |||
| } | |||
| func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { | |||
| count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). | |||
| And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||
| @@ -1830,11 +2060,18 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
| return err | |||
| } | |||
| if _, err = sess.NoAutoTime().Insert(new); err != nil { | |||
| if _, err = sess.NoAutoTime().InsertOne(new); err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| if new.Spec != nil { | |||
| if _, err = sess.Insert(NewCloudBrainSpec(new.ID, *new.Spec)); err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| } | |||
| if err = sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| @@ -1889,8 +2126,27 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| } | |||
| } | |||
| if (opts.AiCenter) != "" { | |||
| cond = cond.And( | |||
| builder.Like{"cloudbrain.ai_center", opts.AiCenter}, | |||
| ) | |||
| } | |||
| if (opts.NeedDeleteInfo) != "" { | |||
| if opts.NeedDeleteInfo == "yes" { | |||
| cond = cond.And( | |||
| builder.And(builder.NotNull{"cloudbrain.deleted_at"}), | |||
| ) | |||
| } | |||
| if opts.NeedDeleteInfo == "no" { | |||
| cond = cond.And( | |||
| builder.And(builder.IsNull{"cloudbrain.deleted_at"}), | |||
| ) | |||
| } | |||
| } | |||
| if (opts.IsLatestVersion) != "" { | |||
| cond = cond.And(builder.Or(builder.And(builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion}, builder.Eq{"cloudbrain.job_type": "TRAIN"}), builder.Neq{"cloudbrain.job_type": "TRAIN"})) | |||
| cond = cond.And(builder.Or(builder.And(builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion}, | |||
| builder.Eq{"cloudbrain.job_type": "TRAIN"}), builder.Neq{"cloudbrain.job_type": "TRAIN"})) | |||
| } | |||
| if len(opts.CloudbrainIDs) > 0 { | |||
| @@ -1928,7 +2184,8 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| } else { | |||
| lowerKeyWord := strings.ToLower(opts.Keyword) | |||
| cond = cond.And(builder.Or(builder.Like{"LOWER(cloudbrain.job_name)", lowerKeyWord}, builder.Like{"LOWER(cloudbrain.display_job_name)", lowerKeyWord}, builder.Like{"`user`.lower_name", lowerKeyWord})) | |||
| cond = cond.And(builder.Or(builder.Like{"LOWER(cloudbrain.job_name)", lowerKeyWord}, | |||
| builder.Like{"LOWER(cloudbrain.display_job_name)", lowerKeyWord}, builder.Like{"`user`.lower_name", lowerKeyWord})) | |||
| count, err = sess.Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
| Join("left", "`user`", condition).Count(new(CloudbrainInfo)) | |||
| @@ -2006,7 +2263,8 @@ func CloudbrainAllStatic(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, er | |||
| } | |||
| sess.OrderBy("cloudbrain.created_unix DESC") | |||
| cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum) | |||
| if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource", "created_unix", "start_time", "end_time").Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
| if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource", | |||
| "created_unix", "start_time", "end_time").Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
| Find(&cloudbrains); err != nil { | |||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||
| } | |||
| @@ -2180,7 +2438,18 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { | |||
| log.Error("GetAttachmentsByUUIDs failed: %v", err) | |||
| return nil, datasetNames, err | |||
| } | |||
| for i, attach := range attachs { | |||
| for i, tmpUuid := range uuids { | |||
| var attach *Attachment | |||
| for _, tmpAttach := range attachs { | |||
| if tmpAttach.UUID == tmpUuid { | |||
| attach = tmpAttach | |||
| break | |||
| } | |||
| } | |||
| if attach == nil { | |||
| log.Error("GetAttachmentsByUUIDs failed: %v", err) | |||
| return nil, datasetNames, err | |||
| } | |||
| fileName := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(attach.Name, ".zip"), ".tar.gz"), ".tgz") | |||
| for _, datasetInfo := range datasetInfos { | |||
| if fileName == datasetInfo.Name { | |||
| @@ -2208,3 +2477,147 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { | |||
| return datasetInfos, datasetNames, nil | |||
| } | |||
| var ( | |||
| SpecsMapInitFlag = false | |||
| CloudbrainDebugResourceSpecsMap map[int]*ResourceSpec | |||
| CloudbrainTrainResourceSpecsMap map[int]*ResourceSpec | |||
| CloudbrainInferenceResourceSpecsMap map[int]*ResourceSpec | |||
| CloudbrainBenchmarkResourceSpecsMap map[int]*ResourceSpec | |||
| CloudbrainSpecialResourceSpecsMap map[int]*ResourceSpec | |||
| GpuInfosMapInitFlag = false | |||
| CloudbrainDebugGpuInfosMap map[string]*GpuInfo | |||
| CloudbrainTrainGpuInfosMap map[string]*GpuInfo | |||
| CloudbrainInferenceGpuInfosMap map[string]*GpuInfo | |||
| CloudbrainBenchmarkGpuInfosMap map[string]*GpuInfo | |||
| CloudbrainSpecialGpuInfosMap map[string]*GpuInfo | |||
| ) | |||
| func InitCloudbrainOneResourceSpecMap() { | |||
| if CloudbrainDebugResourceSpecsMap == nil || len(CloudbrainDebugResourceSpecsMap) == 0 { | |||
| t := ResourceSpecs{} | |||
| json.Unmarshal([]byte(setting.ResourceSpecs), &t) | |||
| CloudbrainDebugResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec)) | |||
| for _, spec := range t.ResourceSpec { | |||
| CloudbrainDebugResourceSpecsMap[spec.Id] = spec | |||
| } | |||
| } | |||
| if CloudbrainTrainResourceSpecsMap == nil || len(CloudbrainTrainResourceSpecsMap) == 0 { | |||
| t := ResourceSpecs{} | |||
| json.Unmarshal([]byte(setting.TrainResourceSpecs), &t) | |||
| CloudbrainTrainResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec)) | |||
| for _, spec := range t.ResourceSpec { | |||
| CloudbrainTrainResourceSpecsMap[spec.Id] = spec | |||
| } | |||
| } | |||
| if CloudbrainInferenceResourceSpecsMap == nil || len(CloudbrainInferenceResourceSpecsMap) == 0 { | |||
| t := ResourceSpecs{} | |||
| json.Unmarshal([]byte(setting.InferenceResourceSpecs), &t) | |||
| CloudbrainInferenceResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec)) | |||
| for _, spec := range t.ResourceSpec { | |||
| CloudbrainInferenceResourceSpecsMap[spec.Id] = spec | |||
| } | |||
| } | |||
| if CloudbrainBenchmarkResourceSpecsMap == nil || len(CloudbrainBenchmarkResourceSpecsMap) == 0 { | |||
| t := ResourceSpecs{} | |||
| json.Unmarshal([]byte(setting.BenchmarkResourceSpecs), &t) | |||
| CloudbrainBenchmarkResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec)) | |||
| for _, spec := range t.ResourceSpec { | |||
| CloudbrainBenchmarkResourceSpecsMap[spec.Id] = spec | |||
| } | |||
| } | |||
| if CloudbrainSpecialResourceSpecsMap == nil || len(CloudbrainSpecialResourceSpecsMap) == 0 { | |||
| t := SpecialPools{} | |||
| json.Unmarshal([]byte(setting.SpecialPools), &t) | |||
| for _, pool := range t.Pools { | |||
| CloudbrainSpecialResourceSpecsMap = make(map[int]*ResourceSpec, len(pool.ResourceSpec)) | |||
| for _, spec := range pool.ResourceSpec { | |||
| CloudbrainSpecialResourceSpecsMap[spec.Id] = spec | |||
| } | |||
| } | |||
| } | |||
| SpecsMapInitFlag = true | |||
| } | |||
| func InitCloudbrainOneGpuInfoMap() { | |||
| if CloudbrainDebugGpuInfosMap == nil || len(CloudbrainDebugGpuInfosMap) == 0 { | |||
| t := GpuInfos{} | |||
| json.Unmarshal([]byte(setting.GpuTypes), &t) | |||
| CloudbrainDebugGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo)) | |||
| for _, GpuInfo := range t.GpuInfo { | |||
| CloudbrainDebugGpuInfosMap[GpuInfo.Queue] = GpuInfo | |||
| } | |||
| } | |||
| if CloudbrainTrainGpuInfosMap == nil || len(CloudbrainTrainGpuInfosMap) == 0 { | |||
| t := GpuInfos{} | |||
| json.Unmarshal([]byte(setting.TrainGpuTypes), &t) | |||
| CloudbrainTrainGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo)) | |||
| for _, GpuInfo := range t.GpuInfo { | |||
| CloudbrainTrainGpuInfosMap[GpuInfo.Queue] = GpuInfo | |||
| } | |||
| } | |||
| if CloudbrainInferenceGpuInfosMap == nil || len(CloudbrainInferenceGpuInfosMap) == 0 { | |||
| t := GpuInfos{} | |||
| json.Unmarshal([]byte(setting.InferenceGpuTypes), &t) | |||
| CloudbrainInferenceGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo)) | |||
| for _, GpuInfo := range t.GpuInfo { | |||
| CloudbrainInferenceGpuInfosMap[GpuInfo.Queue] = GpuInfo | |||
| } | |||
| } | |||
| if CloudbrainBenchmarkGpuInfosMap == nil || len(CloudbrainBenchmarkGpuInfosMap) == 0 { | |||
| t := GpuInfos{} | |||
| json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &t) | |||
| CloudbrainBenchmarkGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo)) | |||
| for _, GpuInfo := range t.GpuInfo { | |||
| CloudbrainBenchmarkGpuInfosMap[GpuInfo.Queue] = GpuInfo | |||
| } | |||
| } | |||
| if CloudbrainSpecialGpuInfosMap == nil || len(CloudbrainSpecialGpuInfosMap) == 0 { | |||
| t := SpecialPools{} | |||
| json.Unmarshal([]byte(setting.SpecialPools), &t) | |||
| for _, pool := range t.Pools { | |||
| CloudbrainSpecialGpuInfosMap = make(map[string]*GpuInfo, len(pool.Pool)) | |||
| for _, GpuInfo := range pool.Pool { | |||
| CloudbrainSpecialGpuInfosMap[GpuInfo.Queue] = GpuInfo | |||
| } | |||
| } | |||
| } | |||
| GpuInfosMapInitFlag = true | |||
| } | |||
| func GetNewestJobsByAiCenter() ([]int64, error) { | |||
| ids := make([]int64, 0) | |||
| return ids, x. | |||
| Select("max(id) as id"). | |||
| Where("type=? and ai_center!='' and ai_center is not null", TypeC2Net). | |||
| GroupBy("ai_center"). | |||
| Table(Cloudbrain{}). | |||
| Find(&ids) | |||
| } | |||
| func GetNewestJobsByType() ([]int64, error) { | |||
| ids := make([]int64, 0) | |||
| return ids, x. | |||
| Select("max(id) as id"). | |||
| In("type", TypeCloudBrainOne, TypeCloudBrainTwo). | |||
| GroupBy("type"). | |||
| Table(Cloudbrain{}). | |||
| Find(&ids) | |||
| } | |||
| func GetCloudbrainByIDs(ids []int64) ([]*Cloudbrain, error) { | |||
| cloudbrains := make([]*Cloudbrain, 0) | |||
| return cloudbrains, x. | |||
| In("id", ids). | |||
| Find(&cloudbrains) | |||
| } | |||
| func GetCloudbrainWithDeletedByIDs(ids []int64) ([]*Cloudbrain, error) { | |||
| cloudbrains := make([]*Cloudbrain, 0) | |||
| return cloudbrains, x. | |||
| In("id", ids).Unscoped().Find(&cloudbrains) | |||
| } | |||
| func GetCloudbrainCountByJobName(jobName, jobType string, typeCloudbrain int) (int, error) { | |||
| count, err := x.Where("job_name = ? and job_type= ? and type = ?", jobName, jobType, typeCloudbrain).Count(new(Cloudbrain)) | |||
| return int(count), err | |||
| } | |||
| @@ -518,6 +518,10 @@ func UpdateLocalImageStatus(image *Image) error { | |||
| return err | |||
| } | |||
| func UpdateAutoIncrementIndex() { | |||
| x.Exec("SELECT setval('image_id_seq', (SELECT MAX(id) from image))") | |||
| } | |||
| func DeleteLocalImage(id int64) error { | |||
| image := new(Image) | |||
| _, err := x.ID(id).Delete(image) | |||
| @@ -0,0 +1,109 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| type CloudbrainSpec struct { | |||
| CloudbrainID int64 `xorm:"pk"` | |||
| SpecId int64 `xorm:"index"` | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| AccCardType string | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| ComputeResource string | |||
| UnitPrice int | |||
| QueueId int64 | |||
| QueueCode string | |||
| Cluster string | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| IsExclusive bool | |||
| ExclusiveOrg string | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
| } | |||
| func (s CloudbrainSpec) ConvertToSpecification() *Specification { | |||
| return &Specification{ | |||
| ID: s.SpecId, | |||
| SourceSpecId: s.SourceSpecId, | |||
| AccCardsNum: s.AccCardsNum, | |||
| AccCardType: s.AccCardType, | |||
| CpuCores: s.CpuCores, | |||
| MemGiB: s.MemGiB, | |||
| GPUMemGiB: s.GPUMemGiB, | |||
| ShareMemGiB: s.ShareMemGiB, | |||
| ComputeResource: s.ComputeResource, | |||
| UnitPrice: s.UnitPrice, | |||
| QueueId: s.QueueId, | |||
| QueueCode: s.QueueCode, | |||
| Cluster: s.Cluster, | |||
| AiCenterCode: s.AiCenterCode, | |||
| AiCenterName: s.AiCenterName, | |||
| IsExclusive: s.IsExclusive, | |||
| ExclusiveOrg: s.ExclusiveOrg, | |||
| } | |||
| } | |||
| func NewCloudBrainSpec(cloudbrainId int64, s Specification) CloudbrainSpec { | |||
| return CloudbrainSpec{ | |||
| CloudbrainID: cloudbrainId, | |||
| SpecId: s.ID, | |||
| SourceSpecId: s.SourceSpecId, | |||
| AccCardsNum: s.AccCardsNum, | |||
| AccCardType: s.AccCardType, | |||
| CpuCores: s.CpuCores, | |||
| MemGiB: s.MemGiB, | |||
| GPUMemGiB: s.GPUMemGiB, | |||
| ShareMemGiB: s.ShareMemGiB, | |||
| ComputeResource: s.ComputeResource, | |||
| UnitPrice: s.UnitPrice, | |||
| QueueId: s.QueueId, | |||
| QueueCode: s.QueueCode, | |||
| Cluster: s.Cluster, | |||
| AiCenterCode: s.AiCenterCode, | |||
| AiCenterName: s.AiCenterName, | |||
| IsExclusive: s.IsExclusive, | |||
| ExclusiveOrg: s.ExclusiveOrg, | |||
| } | |||
| } | |||
| func InsertCloudbrainSpec(c CloudbrainSpec) (int64, error) { | |||
| return x.Insert(&c) | |||
| } | |||
| func GetCloudbrainSpecByID(cloudbrainId int64) (*CloudbrainSpec, error) { | |||
| r := &CloudbrainSpec{} | |||
| if has, err := x.Where("cloudbrain_id = ?", cloudbrainId).Get(r); err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, nil | |||
| } | |||
| return r, nil | |||
| } | |||
| func FindCloudbrainTask(page, pageSize int) ([]*Cloudbrain, error) { | |||
| r := make([]*Cloudbrain, 0) | |||
| err := x.Unscoped(). | |||
| Limit(pageSize, (page-1)*pageSize). | |||
| OrderBy("cloudbrain.id"). | |||
| Find(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| } | |||
| func CountNoSpecHistoricTask() (int64, error) { | |||
| n, err := x.Unscoped(). | |||
| Where(" 1=1 and not exists (select 1 from cloudbrain_spec where cloudbrain.id = cloudbrain_spec.cloudbrain_id)"). | |||
| Count(&Cloudbrain{}) | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return n, nil | |||
| } | |||
| @@ -29,133 +29,11 @@ type TaskDetail struct { | |||
| RepoAlias string `json:"RepoAlias"` | |||
| RepoID int64 `json:"RepoID"` | |||
| IsDelete bool `json:"IsDelete"` | |||
| } | |||
| func GetDebugOnePeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeDebug) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainOne) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetDebugOnePeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeDebug, TypeCloudBrainOne).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetTrainOnePeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeTrain) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainOne) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetTrainOnePeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeTrain, TypeCloudBrainOne).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetBenchmarkOnePeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeBenchmark) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainOne) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetBenchmarkOnePeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeBenchmark, TypeCloudBrainOne).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetDebugTwoPeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeDebug) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainTwo) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetDebugTwoPeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeDebug, TypeCloudBrainTwo).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetTrainTwoPeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeTrain) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainTwo) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetTrainTwoPeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeTrain, TypeCloudBrainTwo).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetInferenceTwoPeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and job_type ='" + string(JobTypeInference) + "'" + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainTwo) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetInferenceTwoPeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And job_type = ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), JobTypeInference, TypeCloudBrainTwo).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetCloudBrainOnePeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainOne) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetCloudBrainOnePeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), TypeCloudBrainOne).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| } | |||
| func GetCloudBrainTwoPeriodCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + | |||
| " and type='" + strconv.Itoa(TypeCloudBrainTwo) + "'" | |||
| return x.SQL(countSql).Count() | |||
| } | |||
| func GetCloudBrainTwoPeriodDuration(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| total, err := x.Where("created_unix >= ? And created_unix < ? And type = ? ", strconv.FormatInt(beginTime.Unix(), 10), strconv.FormatInt(endTime.Unix(), 10), TypeCloudBrainTwo).SumInt(&Cloudbrain{}, "duration") | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| return total, nil | |||
| CardNum int `json:"CardNum"` | |||
| CardType string `json:"CardType"` | |||
| CardDuration string `json:"CardDuration"` | |||
| AiCenter string `json:"AiCenter"` | |||
| FlavorName string `json:"FlavorName"` | |||
| } | |||
| func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
| @@ -221,6 +99,7 @@ func GetWaittingTop() ([]*CloudbrainInfo, error) { | |||
| } | |||
| return cloudbrains, nil | |||
| } | |||
| func GetRunningTop() ([]*CloudbrainInfo, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| @@ -0,0 +1,68 @@ | |||
| package models | |||
| import ( | |||
| "time" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| const ( | |||
| TempJobId = "TEMP" | |||
| TempVersionId = TempJobId | |||
| TempJobStatus = TempJobId | |||
| ) | |||
| type CloudbrainTemp struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| JobID string `xorm:"NOT NULL DEFAULT 'TEMP'"` | |||
| VersionID string `xorm:"NOT NULL DEFAULT 'TEMP'"` | |||
| JobName string `xorm:"NOT NULL "` | |||
| Type int `xorm:"NOT NULL "` | |||
| JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"` | |||
| Status string `xorm:"INDEX NOT NULL DEFAULT 'TEMP'"` | |||
| QueryTimes int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| DeletedAt time.Time `xorm:"deleted"` | |||
| } | |||
| func InsertCloudbrainTemp(temp *CloudbrainTemp) (err error) { | |||
| if _, err = x.Insert(temp); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| func getCloudBrainTemp(temp *CloudbrainTemp) (*CloudbrainTemp, error) { | |||
| has, err := x.Get(temp) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, ErrJobNotExist{} | |||
| } | |||
| return temp, nil | |||
| } | |||
| func GetCloudBrainTempJobs() ([]*CloudbrainTemp, error) { | |||
| jobs := make([]*CloudbrainTemp, 0, 10) | |||
| return jobs, x.In("status", TempJobStatus, string(ModelArtsStopping), string(ModelArtsTrainJobKilling)). | |||
| And("query_times < ?", setting.MaxTempQueryTimes). | |||
| Limit(100). | |||
| Find(&jobs) | |||
| } | |||
| func DeleteCloudbrainTemp(temp *CloudbrainTemp) error { | |||
| return deleteCloudbrainTemp(x, temp) | |||
| } | |||
| func deleteCloudbrainTemp(e Engine, temp *CloudbrainTemp) error { | |||
| _, err := e.ID(temp.ID).Delete(temp) | |||
| return err | |||
| } | |||
| func UpdateCloudbrainTemp(temp *CloudbrainTemp) error { | |||
| _, err := x.ID(temp.ID).AllCols().Update(temp) | |||
| return err | |||
| } | |||
| @@ -6,6 +6,8 @@ import ( | |||
| "sort" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| @@ -88,7 +90,7 @@ func (datasets DatasetList) loadAttributes(e Engine) error { | |||
| if err := e. | |||
| Where("id > 0"). | |||
| In("id", keysInt64(set)). | |||
| Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias","is_private"). | |||
| Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias", "is_private"). | |||
| Find(&repos); err != nil { | |||
| return fmt.Errorf("find repos: %v", err) | |||
| } | |||
| @@ -121,12 +123,12 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions) | |||
| if attachment.DatasetID == datasets[i].ID { | |||
| if opts.StarByMe { | |||
| permission,ok := permissionMap[datasets[i].ID]; | |||
| permission, ok := permissionMap[datasets[i].ID] | |||
| if !ok { | |||
| permission = false | |||
| datasets[i].Repo.GetOwner() | |||
| if datasets[i].Repo.Owner.IsOrganization() { | |||
| if datasets[i].Repo.Owner.IsOrganization() { | |||
| if datasets[i].Repo.Owner.IsUserPartOfOrg(opts.User.ID) { | |||
| log.Info("user is member of org.") | |||
| permission = true | |||
| @@ -140,10 +142,10 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions) | |||
| } | |||
| } | |||
| permissionMap[datasets[i].ID]=permission | |||
| permissionMap[datasets[i].ID] = permission | |||
| } | |||
| if permission{ | |||
| if permission { | |||
| datasets[i].Attachments = append(datasets[i].Attachments, attachment) | |||
| } else if !attachment.IsPrivate { | |||
| datasets[i].Attachments = append(datasets[i].Attachments, attachment) | |||
| @@ -159,8 +161,8 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions) | |||
| } | |||
| for i := range datasets { | |||
| if datasets[i].Attachments==nil{ | |||
| datasets[i].Attachments=[]*Attachment{} | |||
| if datasets[i].Attachments == nil { | |||
| datasets[i].Attachments = []*Attachment{} | |||
| } | |||
| datasets[i].Repo.Owner = nil | |||
| } | |||
| @@ -178,7 +180,7 @@ type SearchDatasetOptions struct { | |||
| Category string | |||
| Task string | |||
| License string | |||
| DatasetIDs []int64 // 目前只在StarByMe为true时起作用 | |||
| DatasetIDs []int64 | |||
| ListOptions | |||
| SearchOrderBy | |||
| IsOwner bool | |||
| @@ -188,6 +190,7 @@ type SearchDatasetOptions struct { | |||
| JustNeedZipFile bool | |||
| NeedAttachment bool | |||
| UploadAttachmentByMe bool | |||
| QueryReference bool | |||
| } | |||
| func CreateDataset(dataset *Dataset) (err error) { | |||
| @@ -258,7 +261,7 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||
| } | |||
| } | |||
| if len(opts.DatasetIDs) > 0 { | |||
| if opts.StarByMe { | |||
| if opts.StarByMe || (opts.RepoID == 0 && opts.QueryReference) { | |||
| cond = cond.And(builder.In("dataset.id", opts.DatasetIDs)) | |||
| } else { | |||
| subCon := builder.NewCond() | |||
| @@ -329,13 +332,15 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da | |||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||
| } | |||
| sess.Select(selectColumnsSql).Join("INNER", "repository", "repository.id = dataset.repo_id"). | |||
| builderQuery := builder.Dialect(setting.Database.Type).Select("id", "title", "status", "category", "description", "download_times", "license", "task", "release_id", "user_id", "repo_id", "created_unix", "updated_unix", "num_stars", "recommend", "use_count").From(builder.Dialect(setting.Database.Type).Select(selectColumnsSql).From("dataset").Join("INNER", "repository", "repository.id = dataset.repo_id"). | |||
| Join("INNER", "attachment", "attachment.dataset_id=dataset.id"). | |||
| Where(cond).OrderBy(opts.SearchOrderBy.String()) | |||
| Where(cond), "d").OrderBy(opts.SearchOrderBy.String()) | |||
| if opts.PageSize > 0 { | |||
| sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
| builderQuery.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
| } | |||
| if err = sess.Find(&datasets); err != nil { | |||
| if err = sess.SQL(builderQuery).Find(&datasets); err != nil { | |||
| return nil, 0, fmt.Errorf("Dataset: %v", err) | |||
| } | |||
| @@ -585,3 +590,13 @@ func GetTeamDatasetIdsByUserID(userID int64) []int64 { | |||
| Cols("dataset.id").Find(&datasets) | |||
| return datasets | |||
| } | |||
| func UpdateDatasetCreateUser(ID int64, user *User) error { | |||
| _, err := x.Where("id = ?", ID).Cols("user_id").Update(&Dataset{ | |||
| UserID: user.ID, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -0,0 +1,88 @@ | |||
| package models | |||
| import ( | |||
| "strconv" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| type DatasetReference struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"INDEX unique"` | |||
| DatasetID string `xorm:"TEXT"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| } | |||
| func GetDatasetIdsByRepoID(repoID int64) []int64 { | |||
| var datasets []int64 | |||
| var datasetIds []string | |||
| _ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
| Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
| if len(datasetIds) > 0 { | |||
| for _, datasetIdStr := range strings.Split(datasetIds[0], ",") { | |||
| datasetId, err := strconv.ParseInt(datasetIdStr, 10, 64) | |||
| if err != nil { | |||
| continue | |||
| } | |||
| datasets = append(datasets, datasetId) | |||
| } | |||
| } | |||
| return datasets | |||
| } | |||
| func HasReferenceDataset(repoID int64) bool { | |||
| var datasetIds []string | |||
| _ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
| Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
| return len(datasetIds) > 0 | |||
| } | |||
| func getReferenceDatasetStr(repoID int64) string { | |||
| var datasetIds []string | |||
| _ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
| Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
| if len(datasetIds) > 0 { | |||
| return datasetIds[0] | |||
| } | |||
| return "" | |||
| } | |||
| func DeleteReferenceDatasetIdsByRepoID(repoID int64) error { | |||
| _, err := x.Exec("delete from dataset_reference where repo_id=?", repoID) | |||
| return err | |||
| } | |||
| func NewDatasetIdsByRepoID(repoID int64, datasetIds []int64) error { | |||
| if len(datasetIds) == 0 { //关联数据集数组为空 | |||
| DeleteReferenceDatasetIdsByRepoID(repoID) | |||
| } | |||
| var datasetsStrArray []string | |||
| for _, datasetId := range datasetIds { | |||
| datasetsStrArray = append(datasetsStrArray, strconv.FormatInt(datasetId, 10)) | |||
| } | |||
| newDatasetStr := strings.Join(datasetsStrArray, ",") | |||
| oldDatasetStr := getReferenceDatasetStr(repoID) | |||
| if newDatasetStr == oldDatasetStr { //关联数据集无变化,不需要处理 | |||
| return nil | |||
| } | |||
| if oldDatasetStr != "" { //已经存在关联数据集 | |||
| _, err := x.Exec("update dataset_reference set dataset_id=? where repo_id=?", newDatasetStr, repoID) | |||
| return err | |||
| } else { | |||
| datasetReference := DatasetReference{ | |||
| DatasetID: newDatasetStr, | |||
| RepoID: repoID, | |||
| } | |||
| _, err := x.Insert(datasetReference) | |||
| return err | |||
| } | |||
| } | |||
| @@ -158,16 +158,20 @@ DROP TRIGGER IF EXISTS es_update_dataset on public.dataset; | |||
| CREATE OR REPLACE FUNCTION public.update_dataset() RETURNS trigger AS | |||
| $def$ | |||
| BEGIN | |||
| UPDATE public.dataset_es | |||
| SET description=NEW.description, | |||
| title=NEW.title, | |||
| category=NEW.category, | |||
| task=NEW.task, | |||
| download_times=NEW.download_times, | |||
| updated_unix=NEW.updated_unix, | |||
| file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false), | |||
| file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false) | |||
| where id=NEW.id; | |||
| if (NEW.status=0) then | |||
| delete from public.dataset_es where id=NEW.id; | |||
| elsif (NEW.status=1) then | |||
| UPDATE public.dataset_es | |||
| SET description=NEW.description, | |||
| title=NEW.title, | |||
| category=NEW.category, | |||
| task=NEW.task, | |||
| download_times=NEW.download_times, | |||
| updated_unix=NEW.updated_unix, | |||
| file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false), | |||
| file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false) | |||
| where id=NEW.id; | |||
| end if; | |||
| return new; | |||
| END | |||
| $def$ | |||
| @@ -461,7 +461,7 @@ $def$ | |||
| if not OLD.is_private and NEW.is_private then | |||
| delete from public.issue_es where repo_id=NEW.id; | |||
| delete from public.dataset_es where repo_id=NEW.id; | |||
| -- delete from public.dataset_es where repo_id=NEW.id; | |||
| delete from public.repository_es where id=NEW.id; | |||
| end if; | |||
| @@ -152,6 +152,15 @@ func init() { | |||
| new(PointAccountLog), | |||
| new(PointAccount), | |||
| new(RewardAdminLog), | |||
| new(AiModelConvert), | |||
| new(ResourceQueue), | |||
| new(ResourceSpecification), | |||
| new(ResourceScene), | |||
| new(ResourceSceneSpec), | |||
| new(AdminOperateLog), | |||
| new(CloudbrainSpec), | |||
| new(CloudbrainTemp), | |||
| new(DatasetReference), | |||
| ) | |||
| tablesStatistic = append(tablesStatistic, | |||
| @@ -470,6 +470,14 @@ func isOrganizationMember(e Engine, orgID, uid int64) (bool, error) { | |||
| Exist() | |||
| } | |||
| func IsOrganizationMemberByOrgName(orgName string, uid int64) (bool, error) { | |||
| org, _ := GetOrgByName(orgName) | |||
| if org != nil { | |||
| return IsOrganizationMember(org.ID, uid) | |||
| } | |||
| return false, nil | |||
| } | |||
| // IsPublicMembership returns true if given user public his/her membership. | |||
| func IsPublicMembership(orgID, uid int64) (bool, error) { | |||
| return x. | |||
| @@ -1609,13 +1609,6 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e | |||
| if err != nil { | |||
| return err | |||
| } | |||
| //If repo has become private, we need set dataset and dataset_file to private | |||
| _, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
| Status: 0, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| dataset, err := GetDatasetByRepo(repo) | |||
| if err != nil && !IsErrNotExist(err) { | |||
| @@ -1630,6 +1623,14 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e | |||
| } | |||
| } | |||
| //If repo has become private, we need set dataset and dataset_file to private | |||
| _, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
| Status: 0, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } else { | |||
| //If repo has become public, we need set dataset to public | |||
| _, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
| @@ -1793,7 +1794,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
| // Delete dataset attachment record and remove related files | |||
| deleteDatasetAttachmentByRepoId(sess, repoID) | |||
| if err = deleteBeans(sess, | |||
| &Access{RepoID: repo.ID}, | |||
| &Action{RepoID: repo.ID}, | |||
| @@ -2255,6 +2255,18 @@ func CheckRepoStats(ctx context.Context) error { | |||
| "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", | |||
| "repository count 'num_stars'", | |||
| }, | |||
| //Repository.NumIssues | |||
| { | |||
| "SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=false)", | |||
| "UPDATE `repository` SET num_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_pull=false) WHERE id=?", | |||
| "repository count 'num_issues'", | |||
| }, | |||
| //Repository.NumPulls | |||
| { | |||
| "SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=true)", | |||
| "UPDATE `repository` SET num_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_pull=true) WHERE id=?", | |||
| "repository count 'num_pulls'", | |||
| }, | |||
| // Label.NumIssues | |||
| { | |||
| "SELECT label.id FROM `label` WHERE label.num_issues!=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=label.id)", | |||
| @@ -211,6 +211,45 @@ func setKeyContributerDict(contributorDistinctDict map[string]int, email string, | |||
| } | |||
| } | |||
| func GetAllUserPublicRepoKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { | |||
| authors := make(map[string]*git.UserKPIStats) | |||
| repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name", "is_private") | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, repository := range repositorys { | |||
| if repository.IsPrivate { | |||
| continue | |||
| } | |||
| authorsOneRepo, err1 := git.GetUserKPIStats(repository.RepoPath(), startTime, endTime) | |||
| if err1 != nil { | |||
| log.Warn("get user kpi status err:"+repository.RepoPath(), err1.Error()) | |||
| continue | |||
| } | |||
| for key, value := range authorsOneRepo { | |||
| if _, ok := authors[key]; !ok { | |||
| authors[key] = &git.UserKPIStats{ | |||
| Name: value.Name, | |||
| Email: value.Email, | |||
| Commits: 0, | |||
| CommitLines: 0, | |||
| } | |||
| } | |||
| if value.Email == "1250125907@qq.com" || value.Email == "peiyongyu-34@163.com" { | |||
| log.Info("repo path=" + repository.RepoPath()) | |||
| } | |||
| authors[key].Commits += value.Commits | |||
| authors[key].CommitLines += value.CommitLines | |||
| } | |||
| } | |||
| return authors, nil | |||
| } | |||
| func GetAllUserKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { | |||
| authors := make(map[string]*git.UserKPIStats) | |||
| repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name") | |||
| @@ -0,0 +1,349 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "errors" | |||
| "strconv" | |||
| "strings" | |||
| "xorm.io/builder" | |||
| ) | |||
| type ResourceQueue struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| QueueCode string | |||
| Cluster string `xorm:"notnull"` | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| ComputeResource string | |||
| AccCardType string | |||
| CardsTotalNum int | |||
| IsAutomaticSync bool | |||
| Remark string | |||
| DeletedTime timeutil.TimeStamp `xorm:"deleted"` | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| CreatedBy int64 | |||
| UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
| UpdatedBy int64 | |||
| } | |||
| func (r ResourceQueue) ConvertToRes() *ResourceQueueRes { | |||
| return &ResourceQueueRes{ | |||
| ID: r.ID, | |||
| QueueCode: r.QueueCode, | |||
| Cluster: r.Cluster, | |||
| AiCenterCode: r.AiCenterCode, | |||
| AiCenterName: r.AiCenterName, | |||
| ComputeResource: r.ComputeResource, | |||
| AccCardType: r.AccCardType, | |||
| CardsTotalNum: r.CardsTotalNum, | |||
| UpdatedTime: r.UpdatedTime, | |||
| Remark: r.Remark, | |||
| } | |||
| } | |||
| type ResourceQueueReq struct { | |||
| QueueCode string | |||
| Cluster string `binding:"Required"` | |||
| AiCenterCode string | |||
| ComputeResource string `binding:"Required"` | |||
| AccCardType string `binding:"Required"` | |||
| CardsTotalNum int | |||
| CreatorId int64 | |||
| IsAutomaticSync bool | |||
| Remark string | |||
| } | |||
| func (r ResourceQueueReq) ToDTO() ResourceQueue { | |||
| q := ResourceQueue{ | |||
| QueueCode: r.QueueCode, | |||
| Cluster: r.Cluster, | |||
| AiCenterCode: r.AiCenterCode, | |||
| ComputeResource: strings.ToUpper(r.ComputeResource), | |||
| AccCardType: strings.ToUpper(r.AccCardType), | |||
| CardsTotalNum: r.CardsTotalNum, | |||
| IsAutomaticSync: r.IsAutomaticSync, | |||
| Remark: r.Remark, | |||
| CreatedBy: r.CreatorId, | |||
| UpdatedBy: r.CreatorId, | |||
| } | |||
| if r.Cluster == OpenICluster { | |||
| if r.AiCenterCode == AICenterOfCloudBrainOne { | |||
| q.AiCenterName = "云脑一" | |||
| } else if r.AiCenterCode == AICenterOfCloudBrainTwo { | |||
| q.AiCenterName = "云脑二" | |||
| } | |||
| } | |||
| return q | |||
| } | |||
| type SearchResourceQueueOptions struct { | |||
| ListOptions | |||
| Cluster string | |||
| AiCenterCode string | |||
| ComputeResource string | |||
| AccCardType string | |||
| } | |||
| type ResourceQueueListRes struct { | |||
| TotalSize int64 | |||
| List []*ResourceQueueRes | |||
| } | |||
| type ResourceQueueCodesRes struct { | |||
| ID int64 | |||
| QueueCode string | |||
| Cluster string | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| } | |||
| func (ResourceQueueCodesRes) TableName() string { | |||
| return "resource_queue" | |||
| } | |||
| type ResourceAiCenterRes struct { | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| } | |||
| type GetQueueCodesOptions struct { | |||
| Cluster string | |||
| } | |||
| func NewResourceQueueListRes(totalSize int64, list []ResourceQueue) *ResourceQueueListRes { | |||
| resList := make([]*ResourceQueueRes, len(list)) | |||
| for i, v := range list { | |||
| resList[i] = v.ConvertToRes() | |||
| } | |||
| return &ResourceQueueListRes{ | |||
| TotalSize: totalSize, | |||
| List: resList, | |||
| } | |||
| } | |||
| type ResourceQueueRes struct { | |||
| ID int64 | |||
| QueueCode string | |||
| Cluster string | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| ComputeResource string | |||
| AccCardType string | |||
| CardsTotalNum int | |||
| UpdatedTime timeutil.TimeStamp | |||
| Remark string | |||
| } | |||
| func InsertResourceQueue(queue ResourceQueue) (int64, error) { | |||
| return x.Insert(&queue) | |||
| } | |||
| func UpdateResourceQueueById(queueId int64, queue ResourceQueue) (int64, error) { | |||
| return x.ID(queueId).Update(&queue) | |||
| } | |||
| func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueue, error) { | |||
| var cond = builder.NewCond() | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| if opts.Cluster != "" { | |||
| cond = cond.And(builder.Eq{"cluster": opts.Cluster}) | |||
| } | |||
| if opts.AiCenterCode != "" { | |||
| cond = cond.And(builder.Eq{"ai_center_code": opts.AiCenterCode}) | |||
| } | |||
| if opts.ComputeResource != "" { | |||
| cond = cond.And(builder.Eq{"compute_resource": opts.ComputeResource}) | |||
| } | |||
| if opts.AccCardType != "" { | |||
| cond = cond.And(builder.Eq{"acc_card_type": opts.AccCardType}) | |||
| } | |||
| n, err := x.Where(cond).Unscoped().Count(&ResourceQueue{}) | |||
| if err != nil { | |||
| return 0, nil, err | |||
| } | |||
| r := make([]ResourceQueue, 0) | |||
| err = x.Where(cond).Desc("id").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Unscoped().Find(&r) | |||
| if err != nil { | |||
| return 0, nil, err | |||
| } | |||
| return n, r, nil | |||
| } | |||
| func GetResourceQueueCodes(opts GetQueueCodesOptions) ([]*ResourceQueueCodesRes, error) { | |||
| cond := builder.NewCond() | |||
| if opts.Cluster != "" { | |||
| cond = cond.And(builder.Eq{"cluster": opts.Cluster}) | |||
| } | |||
| cond = cond.And(builder.Or(builder.IsNull{"deleted_time"}, builder.Eq{"deleted_time": 0})) | |||
| r := make([]*ResourceQueueCodesRes, 0) | |||
| err := x.Where(cond).OrderBy("cluster desc,ai_center_code asc").Find(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| } | |||
| func GetResourceQueue(r *ResourceQueue) (*ResourceQueue, error) { | |||
| has, err := x.Get(r) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, nil | |||
| } | |||
| return r, nil | |||
| } | |||
| func ParseComputeResourceFormGrampus(grampusDeviceKind string) string { | |||
| t := strings.Split(grampusDeviceKind, "/") | |||
| if len(t) < 2 { | |||
| return "" | |||
| } | |||
| return strings.ToUpper(t[1]) | |||
| } | |||
| type MemSize struct { | |||
| Sizes []string | |||
| Hex int | |||
| } | |||
| var memSize = MemSize{Sizes: []string{"K", "M", "G", "T", "P", "E"}, Hex: 1000} | |||
| var iMemSize = MemSize{Sizes: []string{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei"}, Hex: 1024} | |||
| func MatchMemSize(memSize MemSize, val string) (int, float32, error) { | |||
| for i, v := range memSize.Sizes { | |||
| if strings.HasSuffix(val, v) { | |||
| s := strings.TrimSuffix(val, v) | |||
| f, err := strconv.ParseFloat(s, 32) | |||
| if err != nil { | |||
| return 0, 0, err | |||
| } | |||
| return i, float32(f), nil | |||
| } | |||
| } | |||
| return -1, 0, nil | |||
| } | |||
| //TransferMemSize transfer oldValue format from old index to new index | |||
| //eg: memSize.Sizes = []string{"M", "G", "T", "P", "E"}, oldValue = 10 , oldIndex = 1 , newIndex = 0. it means transfer 10G to 10000M | |||
| //so it returns 10000 | |||
| func TransferMemSize(memSize MemSize, oldValue float32, oldIndex int, newIndex int) float32 { | |||
| diff := oldIndex - newIndex | |||
| r := oldValue | |||
| if diff > 0 { | |||
| r = oldValue * float32(diff) * float32(memSize.Hex) | |||
| } else if diff < 0 { | |||
| r = oldValue / float32(-1*diff) / float32(memSize.Hex) | |||
| } | |||
| return r | |||
| } | |||
| //ParseMemSize find the memSize which matches value's format,and parse the number from value | |||
| func ParseMemSize(value string, memSize MemSize, newIndex int) (bool, float32, error) { | |||
| index, r, err := MatchMemSize(memSize, value) | |||
| if err != nil { | |||
| return false, 0, err | |||
| } | |||
| if index < 0 { | |||
| return false, 0, nil | |||
| } | |||
| return true, TransferMemSize(memSize, r, index, newIndex), nil | |||
| } | |||
| func ParseMemSizeFromGrampus(grampusMemSize string) (float32, error) { | |||
| if grampusMemSize == "" { | |||
| return 0, nil | |||
| } | |||
| memflag, memResult, err := ParseMemSize(grampusMemSize, memSize, 2) | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| if memflag { | |||
| return memResult, nil | |||
| } | |||
| iMemFlag, imemResult, err := ParseMemSize(grampusMemSize, iMemSize, 2) | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| if iMemFlag { | |||
| return imemResult, nil | |||
| } | |||
| return 0, errors.New("grampus memSize format error") | |||
| } | |||
| func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, existIds []int64) error { | |||
| sess := x.NewSession() | |||
| var err error | |||
| defer func() { | |||
| if err != nil { | |||
| sess.Rollback() | |||
| } | |||
| sess.Close() | |||
| }() | |||
| //delete queues that no longer exists | |||
| deleteQueueIds := make([]int64, 0) | |||
| queueCond := builder.NewCond() | |||
| queueCond = queueCond.And(builder.NotIn("resource_queue.id", existIds)).And(builder.Eq{"resource_queue.cluster": C2NetCluster}) | |||
| if err := sess.Cols("resource_queue.id").Table("resource_queue"). | |||
| Where(queueCond).Find(&deleteQueueIds); err != nil { | |||
| return err | |||
| } | |||
| if len(deleteQueueIds) > 0 { | |||
| if _, err = sess.In("id", deleteQueueIds).Update(&ResourceQueue{Remark: "自动同步时被下架"}); err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.In("id", deleteQueueIds).Delete(&ResourceQueue{}); err != nil { | |||
| return err | |||
| } | |||
| //delete specs and scene that no longer exists | |||
| deleteSpcIds := make([]int64, 0) | |||
| if err := sess.Cols("resource_specification.id").Table("resource_specification"). | |||
| In("queue_id", deleteQueueIds).Find(&deleteSpcIds); err != nil { | |||
| return err | |||
| } | |||
| if len(deleteSpcIds) > 0 { | |||
| if _, err = sess.In("id", deleteSpcIds).Update(&ResourceSpecification{Status: SpecOffShelf}); err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.In("spec_id", deleteSpcIds).Delete(&ResourceSceneSpec{}); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| //update exists specs | |||
| if len(updateList) > 0 { | |||
| for _, v := range updateList { | |||
| if _, err = sess.ID(v.ID).Update(&v); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| //insert new specs | |||
| if len(insertList) > 0 { | |||
| if _, err = sess.Insert(insertList); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func GetResourceAiCenters() ([]ResourceAiCenterRes, error) { | |||
| r := make([]ResourceAiCenterRes, 0) | |||
| err := x.SQL("SELECT t.ai_center_code, t.ai_center_name FROM (SELECT DISTINCT ai_center_code, ai_center_name,cluster FROM resource_queue WHERE (deleted_time IS NULL OR deleted_time=0)) t ORDER BY cluster desc,ai_center_code asc").Find(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| } | |||
| @@ -0,0 +1,329 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "errors" | |||
| "xorm.io/builder" | |||
| ) | |||
| const ( | |||
| Exclusive = iota + 1 | |||
| NotExclusive | |||
| ) | |||
| type ResourceScene struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| SceneName string | |||
| JobType string | |||
| IsExclusive bool | |||
| ExclusiveOrg string | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| CreatedBy int64 | |||
| UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
| UpdatedBy int64 | |||
| DeleteTime timeutil.TimeStamp `xorm:"deleted"` | |||
| DeletedBy int64 | |||
| } | |||
| type ResourceSceneSpec struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| SceneId int64 `xorm:"unique(idx_scene_spec)"` | |||
| SpecId int64 `xorm:"unique(idx_scene_spec)"` | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| } | |||
| type ResourceSceneReq struct { | |||
| ID int64 | |||
| SceneName string | |||
| JobType string | |||
| IsExclusive bool | |||
| ExclusiveOrg string | |||
| CreatorId int64 | |||
| SpecIds []int64 | |||
| } | |||
| type SearchResourceSceneOptions struct { | |||
| ListOptions | |||
| JobType string | |||
| IsExclusive int | |||
| AiCenterCode string | |||
| QueueId int64 | |||
| } | |||
| type ResourceSceneListRes struct { | |||
| TotalSize int64 | |||
| List []ResourceSceneRes | |||
| } | |||
| func NewResourceSceneListRes(totalSize int64, list []ResourceSceneRes) *ResourceSceneListRes { | |||
| return &ResourceSceneListRes{ | |||
| TotalSize: totalSize, | |||
| List: list, | |||
| } | |||
| } | |||
| type ResourceSceneRes struct { | |||
| ID int64 | |||
| SceneName string | |||
| JobType JobType | |||
| IsExclusive bool | |||
| ExclusiveOrg string | |||
| Specs []ResourceSpecWithSceneId | |||
| } | |||
| func (ResourceSceneRes) TableName() string { | |||
| return "resource_scene" | |||
| } | |||
| type ResourceSceneBriefRes struct { | |||
| ID int64 | |||
| SceneName string | |||
| } | |||
| func (ResourceSceneBriefRes) TableName() string { | |||
| return "resource_scene" | |||
| } | |||
| type ResourceSpecWithSceneId struct { | |||
| ID int64 | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| UnitPrice int | |||
| Status int | |||
| UpdatedTime timeutil.TimeStamp | |||
| SceneId int64 | |||
| //queue | |||
| Cluster string | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| QueueCode string | |||
| QueueId int64 | |||
| ComputeResource string | |||
| AccCardType string | |||
| } | |||
| func (ResourceSpecWithSceneId) TableName() string { | |||
| return "resource_specification" | |||
| } | |||
| func InsertResourceScene(r ResourceSceneReq) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| //check | |||
| specs := make([]ResourceSpecification, 0) | |||
| cond := builder.In("id", r.SpecIds).And(builder.Eq{"status": SpecOnShelf}) | |||
| if err := sess.Where(cond).Find(&specs); err != nil { | |||
| return err | |||
| } | |||
| if len(specs) < len(r.SpecIds) { | |||
| return errors.New("specIds not correct") | |||
| } | |||
| rs := ResourceScene{ | |||
| SceneName: r.SceneName, | |||
| JobType: r.JobType, | |||
| IsExclusive: r.IsExclusive, | |||
| ExclusiveOrg: r.ExclusiveOrg, | |||
| CreatedBy: r.CreatorId, | |||
| UpdatedBy: r.CreatorId, | |||
| } | |||
| _, err := sess.InsertOne(&rs) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| if len(r.SpecIds) == 0 { | |||
| return sess.Commit() | |||
| } | |||
| rss := make([]ResourceSceneSpec, len(r.SpecIds)) | |||
| for i, v := range r.SpecIds { | |||
| rss[i] = ResourceSceneSpec{ | |||
| SceneId: rs.ID, | |||
| SpecId: v, | |||
| } | |||
| } | |||
| _, err = sess.Insert(&rss) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func UpdateResourceScene(r ResourceSceneReq) error { | |||
| sess := x.NewSession() | |||
| var err error | |||
| defer func() { | |||
| if err != nil { | |||
| sess.Rollback() | |||
| } | |||
| sess.Close() | |||
| }() | |||
| // find old scene | |||
| old := ResourceScene{} | |||
| if has, _ := sess.ID(r.ID).Get(&old); !has { | |||
| return errors.New("ResourceScene not exist") | |||
| } | |||
| //check specification | |||
| specs := make([]ResourceSpecification, 0) | |||
| cond := builder.In("id", r.SpecIds).And(builder.Eq{"status": SpecOnShelf}) | |||
| if err := sess.Where(cond).Find(&specs); err != nil { | |||
| return err | |||
| } | |||
| if len(specs) < len(r.SpecIds) { | |||
| return errors.New("specIds not correct") | |||
| } | |||
| //update scene | |||
| rs := ResourceScene{ | |||
| SceneName: r.SceneName, | |||
| IsExclusive: r.IsExclusive, | |||
| ExclusiveOrg: r.ExclusiveOrg, | |||
| } | |||
| if _, err = sess.ID(r.ID).UseBool("is_exclusive").Update(&rs); err != nil { | |||
| return err | |||
| } | |||
| //delete scene spec relation | |||
| if _, err = sess.Where("scene_id = ? ", r.ID).Delete(&ResourceSceneSpec{}); err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| if len(r.SpecIds) == 0 { | |||
| return sess.Commit() | |||
| } | |||
| //build new scene spec relation | |||
| rss := make([]ResourceSceneSpec, len(r.SpecIds)) | |||
| for i, v := range r.SpecIds { | |||
| rss[i] = ResourceSceneSpec{ | |||
| SceneId: r.ID, | |||
| SpecId: v, | |||
| } | |||
| } | |||
| if _, err = sess.Insert(&rss); err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func DeleteResourceScene(sceneId int64) error { | |||
| sess := x.NewSession() | |||
| var err error | |||
| defer func() { | |||
| if err != nil { | |||
| sess.Rollback() | |||
| } | |||
| sess.Close() | |||
| }() | |||
| if _, err = sess.ID(sceneId).Delete(&ResourceScene{}); err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.Where("scene_id = ? ", sceneId).Delete(&ResourceSceneSpec{}); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceSceneRes, error) { | |||
| var cond = builder.NewCond() | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| if opts.JobType != "" { | |||
| cond = cond.And(builder.Eq{"resource_scene.job_type": opts.JobType}) | |||
| } | |||
| if opts.IsExclusive == Exclusive { | |||
| cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 1}) | |||
| } else if opts.IsExclusive == NotExclusive { | |||
| cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 0}) | |||
| } | |||
| if opts.AiCenterCode != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AiCenterCode}) | |||
| } | |||
| if opts.QueueId > 0 { | |||
| cond = cond.And(builder.Eq{"resource_queue.id": opts.QueueId}) | |||
| } | |||
| cond = cond.And(builder.NewCond().Or(builder.Eq{"resource_scene.delete_time": 0}).Or(builder.IsNull{"resource_scene.delete_time"})) | |||
| cols := []string{"resource_scene.id", "resource_scene.scene_name", "resource_scene.job_type", "resource_scene.is_exclusive", | |||
| "resource_scene.exclusive_org"} | |||
| count, err := x.Where(cond). | |||
| Distinct("resource_scene.id"). | |||
| Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id"). | |||
| Join("INNER", "resource_specification", "resource_specification.id = resource_scene_spec.spec_id"). | |||
| Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
| Count(&ResourceSceneRes{}) | |||
| if err != nil { | |||
| return 0, nil, err | |||
| } | |||
| r := make([]ResourceSceneRes, 0) | |||
| if err = x.Where(cond).Distinct(cols...). | |||
| Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id"). | |||
| Join("INNER", "resource_specification", "resource_specification.id = resource_scene_spec.spec_id"). | |||
| Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
| Desc("resource_scene.id"). | |||
| Limit(opts.PageSize, (opts.Page-1)*opts.PageSize). | |||
| Find(&r); err != nil { | |||
| return 0, nil, err | |||
| } | |||
| if len(r) == 0 { | |||
| return 0, r, err | |||
| } | |||
| //find related specs | |||
| sceneIds := make([]int64, 0, len(r)) | |||
| for _, v := range r { | |||
| sceneIds = append(sceneIds, v.ID) | |||
| } | |||
| specs := make([]ResourceSpecWithSceneId, 0) | |||
| if err := x.Cols("resource_specification.id", "resource_specification.source_spec_id", | |||
| "resource_specification.acc_cards_num", "resource_specification.cpu_cores", | |||
| "resource_specification.mem_gi_b", "resource_specification.gpu_mem_gi_b", | |||
| "resource_specification.share_mem_gi_b", "resource_specification.unit_price", | |||
| "resource_specification.status", "resource_specification.updated_time", | |||
| "resource_scene_spec.scene_id", "resource_queue.cluster", | |||
| "resource_queue.ai_center_code", "resource_queue.acc_card_type", | |||
| "resource_queue.id as queue_id", "resource_queue.compute_resource", | |||
| "resource_queue.queue_code", "resource_queue.ai_center_name", | |||
| ).In("resource_scene_spec.scene_id", sceneIds). | |||
| Join("INNER", "resource_scene_spec", "resource_scene_spec.spec_id = resource_specification.id"). | |||
| Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id"). | |||
| OrderBy("resource_specification.acc_cards_num"). | |||
| Find(&specs); err != nil { | |||
| return 0, nil, err | |||
| } | |||
| specsMap := make(map[int64][]ResourceSpecWithSceneId, 0) | |||
| for _, v := range specs { | |||
| if _, ok := specsMap[v.SceneId]; !ok { | |||
| specsMap[v.SceneId] = []ResourceSpecWithSceneId{v} | |||
| } else { | |||
| specsMap[v.SceneId] = append(specsMap[v.SceneId], v) | |||
| } | |||
| } | |||
| for i, v := range r { | |||
| s := specsMap[v.ID] | |||
| if s == nil { | |||
| s = make([]ResourceSpecWithSceneId, 0) | |||
| } | |||
| r[i].Specs = s | |||
| } | |||
| return count, r, nil | |||
| } | |||
| @@ -0,0 +1,550 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "fmt" | |||
| "xorm.io/builder" | |||
| ) | |||
| const ( | |||
| SpecNotVerified int = iota + 1 | |||
| SpecOnShelf | |||
| SpecOffShelf | |||
| ) | |||
| type ResourceSpecification struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| QueueId int64 `xorm:"INDEX"` | |||
| SourceSpecId string `xorm:"INDEX"` | |||
| AccCardsNum int | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| UnitPrice int | |||
| Status int | |||
| IsAutomaticSync bool | |||
| CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
| CreatedBy int64 | |||
| UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
| UpdatedBy int64 | |||
| } | |||
| func (r ResourceSpecification) ConvertToRes() *ResourceSpecificationRes { | |||
| return &ResourceSpecificationRes{ | |||
| ID: r.ID, | |||
| SourceSpecId: r.SourceSpecId, | |||
| AccCardsNum: r.AccCardsNum, | |||
| CpuCores: r.CpuCores, | |||
| MemGiB: r.MemGiB, | |||
| ShareMemGiB: r.ShareMemGiB, | |||
| GPUMemGiB: r.GPUMemGiB, | |||
| UnitPrice: r.UnitPrice, | |||
| Status: r.Status, | |||
| UpdatedTime: r.UpdatedTime, | |||
| } | |||
| } | |||
| type ResourceSpecificationReq struct { | |||
| QueueId int64 `binding:"Required"` | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| UnitPrice int | |||
| Status int | |||
| IsAutomaticSync bool | |||
| CreatorId int64 | |||
| } | |||
| func (r ResourceSpecificationReq) ToDTO() ResourceSpecification { | |||
| return ResourceSpecification{ | |||
| QueueId: r.QueueId, | |||
| SourceSpecId: r.SourceSpecId, | |||
| AccCardsNum: r.AccCardsNum, | |||
| CpuCores: r.CpuCores, | |||
| MemGiB: r.MemGiB, | |||
| GPUMemGiB: r.GPUMemGiB, | |||
| ShareMemGiB: r.ShareMemGiB, | |||
| UnitPrice: r.UnitPrice, | |||
| Status: r.Status, | |||
| IsAutomaticSync: r.IsAutomaticSync, | |||
| CreatedBy: r.CreatorId, | |||
| UpdatedBy: r.CreatorId, | |||
| } | |||
| } | |||
| type SearchResourceSpecificationOptions struct { | |||
| ListOptions | |||
| QueueId int64 | |||
| Status int | |||
| Cluster string | |||
| } | |||
| type SearchResourceBriefSpecificationOptions struct { | |||
| QueueId int64 | |||
| Cluster string | |||
| } | |||
| type ResourceSpecAndQueueListRes struct { | |||
| TotalSize int64 | |||
| List []*ResourceSpecAndQueueRes | |||
| } | |||
| func NewResourceSpecAndQueueListRes(totalSize int64, list []ResourceSpecAndQueue) *ResourceSpecAndQueueListRes { | |||
| resList := make([]*ResourceSpecAndQueueRes, len(list)) | |||
| for i, v := range list { | |||
| resList[i] = v.ConvertToRes() | |||
| } | |||
| return &ResourceSpecAndQueueListRes{ | |||
| TotalSize: totalSize, | |||
| List: resList, | |||
| } | |||
| } | |||
| type ResourceSpecificationRes struct { | |||
| ID int64 | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| UnitPrice int | |||
| Status int | |||
| UpdatedTime timeutil.TimeStamp | |||
| } | |||
| func (ResourceSpecificationRes) TableName() string { | |||
| return "resource_specification" | |||
| } | |||
| type ResourceSpecAndQueueRes struct { | |||
| Spec *ResourceSpecificationRes | |||
| Queue *ResourceQueueRes | |||
| } | |||
| type ResourceSpecAndQueue struct { | |||
| ResourceSpecification `xorm:"extends"` | |||
| ResourceQueue `xorm:"extends"` | |||
| } | |||
| func (*ResourceSpecAndQueue) TableName() string { | |||
| return "resource_specification" | |||
| } | |||
| func (r ResourceSpecAndQueue) ConvertToRes() *ResourceSpecAndQueueRes { | |||
| return &ResourceSpecAndQueueRes{ | |||
| Spec: r.ResourceSpecification.ConvertToRes(), | |||
| Queue: r.ResourceQueue.ConvertToRes(), | |||
| } | |||
| } | |||
| type FindSpecsOptions struct { | |||
| JobType JobType | |||
| ComputeResource string | |||
| Cluster string | |||
| AiCenterCode string | |||
| SpecId int64 | |||
| QueueCode string | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| UseAccCardsNum bool | |||
| AccCardType string | |||
| CpuCores int | |||
| UseCpuCores bool | |||
| MemGiB float32 | |||
| UseMemGiB bool | |||
| GPUMemGiB float32 | |||
| UseGPUMemGiB bool | |||
| ShareMemGiB float32 | |||
| UseShareMemGiB bool | |||
| //if true,find specs no matter used or not used in scene. if false,only find specs used in scene | |||
| RequestAll bool | |||
| } | |||
| type Specification struct { | |||
| ID int64 | |||
| SourceSpecId string | |||
| AccCardsNum int | |||
| AccCardType string | |||
| CpuCores int | |||
| MemGiB float32 | |||
| GPUMemGiB float32 | |||
| ShareMemGiB float32 | |||
| ComputeResource string | |||
| UnitPrice int | |||
| QueueId int64 | |||
| QueueCode string | |||
| Cluster string | |||
| AiCenterCode string | |||
| AiCenterName string | |||
| IsExclusive bool | |||
| ExclusiveOrg string | |||
| } | |||
| func (Specification) TableName() string { | |||
| return "resource_specification" | |||
| } | |||
| func InsertResourceSpecification(r ResourceSpecification) (int64, error) { | |||
| return x.Insert(&r) | |||
| } | |||
| func UpdateResourceSpecificationById(queueId int64, spec ResourceSpecification) (int64, error) { | |||
| return x.ID(queueId).Update(&spec) | |||
| } | |||
| func UpdateSpecUnitPriceById(id int64, unitPrice int) error { | |||
| _, err := x.Exec("update resource_specification set unit_price = ? ,updated_time = ? where id = ?", unitPrice, timeutil.TimeStampNow(), id) | |||
| return err | |||
| } | |||
| func SearchResourceSpecification(opts SearchResourceSpecificationOptions) (int64, []ResourceSpecAndQueue, error) { | |||
| var cond = builder.NewCond() | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| if opts.QueueId > 0 { | |||
| cond = cond.And(builder.Eq{"resource_specification.queue_id": opts.QueueId}) | |||
| } | |||
| if opts.Status > 0 { | |||
| cond = cond.And(builder.Eq{"resource_specification.status": opts.Status}) | |||
| } | |||
| if opts.Cluster != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.cluster": opts.Cluster}) | |||
| } | |||
| //cond = cond.And(builder.Or(builder.Eq{"resource_queue.deleted_time": 0}).Or(builder.IsNull{"resource_queue.deleted_time"})) | |||
| n, err := x.Where(cond).Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id"). | |||
| Unscoped().Count(&ResourceSpecAndQueue{}) | |||
| if err != nil { | |||
| return 0, nil, err | |||
| } | |||
| r := make([]ResourceSpecAndQueue, 0) | |||
| err = x.Where(cond). | |||
| Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id"). | |||
| Desc("resource_specification.id"). | |||
| Limit(opts.PageSize, (opts.Page-1)*opts.PageSize). | |||
| Unscoped().Find(&r) | |||
| if err != nil { | |||
| return 0, nil, err | |||
| } | |||
| return n, r, nil | |||
| } | |||
| func GetSpecScenes(specId int64) ([]ResourceSceneBriefRes, error) { | |||
| r := make([]ResourceSceneBriefRes, 0) | |||
| err := x.Where("resource_scene_spec.spec_id = ?", specId). | |||
| Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id"). | |||
| Find(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| } | |||
| func ResourceSpecOnShelf(id int64, unitPrice int) error { | |||
| _, err := x.Exec("update resource_specification set unit_price = ?,updated_time = ?,status = ? where id = ?", unitPrice, timeutil.TimeStampNow(), SpecOnShelf, id) | |||
| return err | |||
| } | |||
| func ResourceSpecOffShelf(id int64) (int64, error) { | |||
| sess := x.NewSession() | |||
| var err error | |||
| defer func() { | |||
| if err != nil { | |||
| sess.Rollback() | |||
| } | |||
| sess.Close() | |||
| }() | |||
| //delete scene spec relation | |||
| if _, err = sess.Where("spec_id = ?", id).Delete(&ResourceSceneSpec{}); err != nil { | |||
| return 0, err | |||
| } | |||
| param := ResourceSpecification{ | |||
| Status: SpecOffShelf, | |||
| } | |||
| n, err := sess.Where("id = ? and status = ?", id, SpecOnShelf).Update(¶m) | |||
| if err != nil { | |||
| return 0, err | |||
| } | |||
| sess.Commit() | |||
| return n, err | |||
| } | |||
| func GetResourceSpecification(r *ResourceSpecification) (*ResourceSpecification, error) { | |||
| has, err := x.Get(r) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, nil | |||
| } | |||
| return r, nil | |||
| } | |||
| func SyncGrampusSpecs(updateList []ResourceSpecification, insertList []ResourceSpecification, existIds []int64) error { | |||
| sess := x.NewSession() | |||
| var err error | |||
| defer func() { | |||
| if err != nil { | |||
| sess.Rollback() | |||
| } | |||
| sess.Close() | |||
| }() | |||
| //delete specs and scene that no longer exists | |||
| deleteIds := make([]int64, 0) | |||
| cond := builder.NewCond() | |||
| cond = cond.And(builder.NotIn("resource_specification.id", existIds)).And(builder.Eq{"resource_queue.cluster": C2NetCluster}) | |||
| if err := sess.Cols("resource_specification.id").Table("resource_specification"). | |||
| Where(cond).Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
| Find(&deleteIds); err != nil { | |||
| return err | |||
| } | |||
| if len(deleteIds) > 0 { | |||
| if _, err = sess.In("id", deleteIds).Update(&ResourceSpecification{Status: SpecOffShelf}); err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.In("spec_id", deleteIds).Delete(&ResourceSceneSpec{}); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| //update exists specs | |||
| if len(updateList) > 0 { | |||
| for _, v := range updateList { | |||
| if _, err = sess.ID(v.ID).Update(&v); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| //insert new specs | |||
| if len(insertList) > 0 { | |||
| if _, err = sess.Insert(insertList); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| //FindSpecs | |||
| func FindSpecs(opts FindSpecsOptions) ([]*Specification, error) { | |||
| var cond = builder.NewCond() | |||
| if !opts.RequestAll && opts.JobType != "" { | |||
| cond = cond.And(builder.Eq{"resource_scene.job_type": opts.JobType}) | |||
| } | |||
| if opts.ComputeResource != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.compute_resource": opts.ComputeResource}) | |||
| } | |||
| if opts.Cluster != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.cluster": opts.Cluster}) | |||
| } | |||
| if opts.AiCenterCode != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AiCenterCode}) | |||
| } | |||
| if opts.SpecId > 0 { | |||
| cond = cond.And(builder.Eq{"resource_specification.id": opts.SpecId}) | |||
| } | |||
| if opts.QueueCode != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.queue_code": opts.QueueCode}) | |||
| } | |||
| if opts.SourceSpecId != "" { | |||
| cond = cond.And(builder.Eq{"resource_specification.source_spec_id": opts.SourceSpecId}) | |||
| } | |||
| if opts.UseAccCardsNum { | |||
| cond = cond.And(builder.Eq{"resource_specification.acc_cards_num": opts.AccCardsNum}) | |||
| } | |||
| if opts.AccCardType != "" { | |||
| cond = cond.And(builder.Eq{"resource_queue.acc_card_type": opts.AccCardType}) | |||
| } | |||
| if opts.UseCpuCores { | |||
| cond = cond.And(builder.Eq{"resource_specification.cpu_cores": opts.CpuCores}) | |||
| } | |||
| if opts.UseMemGiB { | |||
| cond = cond.And(builder.Eq{"resource_specification.mem_gi_b": opts.MemGiB}) | |||
| } | |||
| if opts.UseGPUMemGiB { | |||
| cond = cond.And(builder.Eq{"resource_specification.gpu_mem_gi_b": opts.GPUMemGiB}) | |||
| } | |||
| if opts.UseShareMemGiB { | |||
| cond = cond.And(builder.Eq{"resource_specification.share_mem_gi_b": opts.ShareMemGiB}) | |||
| } | |||
| r := make([]*Specification, 0) | |||
| s := x.Where(cond). | |||
| Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id") | |||
| if !opts.RequestAll { | |||
| s = s.Join("INNER", "resource_scene_spec", "resource_scene_spec.spec_id = resource_specification.id"). | |||
| Join("INNER", "resource_scene", "resource_scene_spec.scene_id = resource_scene.id") | |||
| } | |||
| err := s.OrderBy("resource_queue.compute_resource asc,resource_queue.acc_card_type asc,resource_specification.acc_cards_num asc,resource_specification.cpu_cores asc"). | |||
| Unscoped().Find(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| } | |||
| func InitQueueAndSpec(queue ResourceQueue, spec ResourceSpecification) (*Specification, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| sess.Begin() | |||
| param := ResourceQueue{ | |||
| QueueCode: queue.QueueCode, | |||
| Cluster: queue.Cluster, | |||
| AiCenterCode: queue.AiCenterCode, | |||
| ComputeResource: queue.ComputeResource, | |||
| AccCardType: queue.AccCardType, | |||
| } | |||
| _, err := sess.Get(¶m) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return nil, err | |||
| } | |||
| if param.ID == 0 { | |||
| _, err = sess.InsertOne(&queue) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return nil, err | |||
| } | |||
| } else { | |||
| queue = param | |||
| } | |||
| spec.QueueId = queue.ID | |||
| _, err = sess.InsertOne(&spec) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return nil, err | |||
| } | |||
| sess.Commit() | |||
| return BuildSpecification(queue, spec), nil | |||
| } | |||
| func BuildSpecification(queue ResourceQueue, spec ResourceSpecification) *Specification { | |||
| return &Specification{ | |||
| ID: spec.ID, | |||
| SourceSpecId: spec.SourceSpecId, | |||
| AccCardsNum: spec.AccCardsNum, | |||
| AccCardType: queue.AccCardType, | |||
| CpuCores: spec.CpuCores, | |||
| MemGiB: spec.MemGiB, | |||
| GPUMemGiB: spec.GPUMemGiB, | |||
| ShareMemGiB: spec.ShareMemGiB, | |||
| ComputeResource: queue.ComputeResource, | |||
| UnitPrice: spec.UnitPrice, | |||
| QueueId: queue.ID, | |||
| QueueCode: queue.QueueCode, | |||
| Cluster: queue.Cluster, | |||
| AiCenterCode: queue.AiCenterCode, | |||
| AiCenterName: queue.AiCenterName, | |||
| } | |||
| } | |||
| func GetCloudbrainOneAccCardType(queueCode string) string { | |||
| switch queueCode { | |||
| case "a100": | |||
| return "A100" | |||
| case "openidebug": | |||
| return "T4" | |||
| case "openidgx": | |||
| return "V100" | |||
| } | |||
| return "" | |||
| } | |||
| var cloudbrainTwoSpecsInitFlag = false | |||
| var cloudbrainTwoSpecs map[string]*Specification | |||
| func GetCloudbrainTwoSpecs() (map[string]*Specification, error) { | |||
| if !cloudbrainTwoSpecsInitFlag { | |||
| r, err := InitCloudbrainTwoSpecs() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| cloudbrainTwoSpecsInitFlag = true | |||
| cloudbrainTwoSpecs = r | |||
| } | |||
| return cloudbrainTwoSpecs, nil | |||
| } | |||
| func InitCloudbrainTwoSpecs() (map[string]*Specification, error) { | |||
| r := make(map[string]*Specification, 0) | |||
| queue, err := GetResourceQueue(&ResourceQueue{QueueCode: "openisupport"}) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if queue == nil { | |||
| queue = &ResourceQueue{ | |||
| QueueCode: "openisupport", | |||
| Cluster: OpenICluster, | |||
| AiCenterCode: AICenterOfCloudBrainTwo, | |||
| AiCenterName: "云脑二", | |||
| ComputeResource: NPU, | |||
| AccCardType: "ASCEND910", | |||
| Remark: "处理历史云脑任务时自动生成", | |||
| } | |||
| _, err = x.InsertOne(queue) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| } | |||
| for i := 1; i <= 8; i = i * 2 { | |||
| sourceSpecId := "modelarts.bm.910.arm.public." + fmt.Sprint(i) | |||
| spec, err := GetResourceSpecification(&ResourceSpecification{ | |||
| SourceSpecId: sourceSpecId, | |||
| QueueId: queue.ID, | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if spec == nil { | |||
| spec = &ResourceSpecification{ | |||
| QueueId: queue.ID, | |||
| SourceSpecId: sourceSpecId, | |||
| AccCardsNum: i, | |||
| CpuCores: i * 24, | |||
| MemGiB: float32(i * 256), | |||
| GPUMemGiB: float32(32), | |||
| Status: SpecOffShelf, | |||
| } | |||
| _, err = x.Insert(spec) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| } | |||
| r[sourceSpecId] = BuildSpecification(*queue, *spec) | |||
| } | |||
| return r, nil | |||
| } | |||
| var grampusSpecsInitFlag = false | |||
| var grampusSpecs map[string]*Specification | |||
| func GetGrampusSpecs() (map[string]*Specification, error) { | |||
| if !grampusSpecsInitFlag { | |||
| specMap := make(map[string]*Specification, 0) | |||
| r, err := FindSpecs(FindSpecsOptions{ | |||
| Cluster: C2NetCluster, | |||
| RequestAll: true, | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, spec := range r { | |||
| specMap[spec.SourceSpecId] = spec | |||
| specMap[spec.SourceSpecId+"_"+spec.AiCenterCode] = spec | |||
| } | |||
| grampusSpecsInitFlag = true | |||
| grampusSpecs = specMap | |||
| } | |||
| return grampusSpecs, nil | |||
| } | |||
| @@ -1772,7 +1772,6 @@ func (opts *SearchUserOptions) toConds() builder.Cond { | |||
| if !opts.IsActive.IsNone() { | |||
| cond = cond.And(builder.Eq{"is_active": opts.IsActive.IsTrue()}) | |||
| } | |||
| return cond | |||
| } | |||
| @@ -1784,12 +1783,15 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) { | |||
| if err != nil { | |||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||
| } | |||
| orderby := opts.OrderBy.String() | |||
| if len(opts.OrderBy) == 0 { | |||
| opts.OrderBy = SearchOrderByAlphabetically | |||
| orderby = SearchOrderByAlphabetically.String() | |||
| lowerKeyword := strings.ToLower(opts.Keyword) | |||
| if len(opts.Keyword) > 0 { | |||
| orderby = "CASE when lower_name='" + lowerKeyword + "' then 0 when strpos(lower_name,'" + lowerKeyword + "')>0 then 1 else 2 END ASC,lower_name ASC" | |||
| } | |||
| } | |||
| sess := x.Where(cond).OrderBy(opts.OrderBy.String()) | |||
| sess := x.Where(cond).OrderBy(orderby) | |||
| if opts.Page != 0 { | |||
| sess = opts.setSessionPagination(sess) | |||
| } | |||
| @@ -0,0 +1,451 @@ | |||
| package models | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/builder" | |||
| ) | |||
| type UserBusinessAnalysisForActivity struct { | |||
| ID int64 `xorm:"pk"` | |||
| CountDate int64 `xorm:"pk"` | |||
| //action :ActionMergePullRequest // 11 | |||
| CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| //action :ActionCommitRepo | |||
| CommitCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| //issue // 10 | |||
| IssueCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| //comment table current date | |||
| CommentCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| //follow table | |||
| WatchedCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"` | |||
| //issue, issueassigees | |||
| SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| //use | |||
| RegistDate timeutil.TimeStamp `xorm:"NOT NULL"` | |||
| //user | |||
| Email string `xorm:"NOT NULL"` | |||
| Phone string `xorm:"NULL"` | |||
| //user | |||
| Name string `xorm:"NOT NULL"` | |||
| DataDate string `xorm:"NULL"` | |||
| CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"` | |||
| CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"` | |||
| //0 | |||
| CommitModelCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| } | |||
| func QueryDataForActivity(startTime time.Time, endTime time.Time) []*UserBusinessAnalysisForActivity { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| result := make([]*UserBusinessAnalysisForActivity, 0) | |||
| publicRepo := queryPublicRepo() | |||
| start_unix := startTime.Unix() | |||
| end_unix := endTime.Unix() | |||
| CodeMergeCountMap := queryPullRequestPublic(start_unix, end_unix, publicRepo) | |||
| CommitCodeSizeMap, err := GetAllUserPublicRepoKPIStats(startTime, endTime) | |||
| if err != nil { | |||
| log.Info("error,info=" + err.Error()) | |||
| } | |||
| CommitCountMap := queryCommitActionPublic(start_unix, end_unix, 5, publicRepo) | |||
| IssueCountMap, publicRepoIssueIdMap := queryCreateIssuePublic(start_unix, end_unix, publicRepo) | |||
| SolveIssueCountMap := querySolveIssuePublic(start_unix, end_unix, publicRepoIssueIdMap) | |||
| WatchedCountMap, _ := queryFollow(start_unix, end_unix) | |||
| CommentCountMap := queryCommentPublic(start_unix, end_unix, publicRepoIssueIdMap) | |||
| PublicDataSet := queryAllPublicDataSet(publicRepo) | |||
| DatasetFileNums := queryPublicDatasetFileNums(start_unix, end_unix, PublicDataSet) | |||
| AiModelManageMap := queryUserModelPublic(start_unix, end_unix, publicRepo) | |||
| cond := "type != 1 and is_active=true" | |||
| count, err := sess.Where(cond).Count(new(User)) | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| userList := make([]*User, 0) | |||
| sess.Find(&userList) | |||
| for i, userRecord := range userList { | |||
| var dateRecord UserBusinessAnalysisForActivity | |||
| dateRecord.ID = userRecord.ID | |||
| log.Info("i=" + fmt.Sprint(i) + " userName=" + userRecord.Name) | |||
| dateRecord.Email = userRecord.Email | |||
| dateRecord.Phone = userRecord.PhoneNumber | |||
| dateRecord.RegistDate = userRecord.CreatedUnix | |||
| dateRecord.Name = userRecord.Name | |||
| dateRecord.CodeMergeCount = getMapValue(dateRecord.ID, CodeMergeCountMap) | |||
| dateRecord.CommitCount = getMapValue(dateRecord.ID, CommitCountMap) | |||
| dateRecord.WatchedCount = getMapValue(dateRecord.ID, WatchedCountMap) | |||
| dateRecord.CommitDatasetNum = getMapValue(dateRecord.ID, DatasetFileNums) | |||
| dateRecord.IssueCount = getMapValue(dateRecord.ID, IssueCountMap) | |||
| dateRecord.CommentCount = getMapValue(dateRecord.ID, CommentCountMap) | |||
| if _, ok := CommitCodeSizeMap[dateRecord.Email]; !ok { | |||
| dateRecord.CommitCodeSize = 0 | |||
| } else { | |||
| dateRecord.CommitCodeSize = int(CommitCodeSizeMap[dateRecord.Email].CommitLines) | |||
| } | |||
| dateRecord.SolveIssueCount = getMapValue(dateRecord.ID, SolveIssueCountMap) | |||
| dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap) | |||
| result = append(result, &dateRecord) | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return result | |||
| } | |||
| func querySolveIssuePublic(start_unix int64, end_unix int64, publicRepoIssueIdMap map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| cond := "issue.is_closed=true and issue.closed_unix>=" + fmt.Sprint(start_unix) + " and issue.closed_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Table("issue_assignees").Join("inner", "issue", "issue.id=issue_assignees.issue_id").Where(cond).Count(new(IssueAssignees)) | |||
| if err != nil { | |||
| log.Info("query issue error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| issueAssigneesList := make([]*IssueAssignees, 0) | |||
| sess.Select("issue_assignees.*").Table("issue_assignees"). | |||
| Join("inner", "issue", "issue.id=issue_assignees.issue_id"). | |||
| Where(cond).OrderBy("issue_assignees.id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| sess.Find(&issueAssigneesList) | |||
| log.Info("query IssueAssignees size=" + fmt.Sprint(len(issueAssigneesList))) | |||
| for _, issueAssigneesRecord := range issueAssigneesList { | |||
| if isPublicRepo(issueAssigneesRecord.IssueID, publicRepoIssueIdMap) { | |||
| if _, ok := resultMap[issueAssigneesRecord.AssigneeID]; !ok { | |||
| resultMap[issueAssigneesRecord.AssigneeID] = 1 | |||
| } else { | |||
| resultMap[issueAssigneesRecord.AssigneeID] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func queryPublicRepo() map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| count, err := sess.Table("repository").Count(new(Repository)) | |||
| if err != nil { | |||
| log.Info("query Repository error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| repositoryList := make([]*Repository, 0) | |||
| sess.Select("*").Table("repository").OrderBy("id desc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| sess.Find(&repositoryList) | |||
| log.Info("query repo size=" + fmt.Sprint(len(repositoryList))) | |||
| for _, repositoryRecord := range repositoryList { | |||
| if repositoryRecord.IsPrivate { | |||
| continue | |||
| } | |||
| if _, ok := resultMap[repositoryRecord.ID]; !ok { | |||
| resultMap[repositoryRecord.ID] = 1 | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func isPublicRepo(repoId int64, publicAllRepo map[int64]int) bool { | |||
| if _, ok := publicAllRepo[repoId]; !ok { | |||
| return false | |||
| } | |||
| return true | |||
| } | |||
| func queryPullRequestPublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| cond := "issue.created_unix>=" + fmt.Sprint(start_unix) + " and issue.created_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).Count(new(Issue)) | |||
| if err != nil { | |||
| log.Info("query issue error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| issueList := make([]*Issue, 0) | |||
| sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| sess.Find(&issueList) | |||
| log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList))) | |||
| for _, issueRecord := range issueList { | |||
| if isPublicRepo(issueRecord.RepoID, publicAllRepo) { | |||
| if _, ok := resultMap[issueRecord.PosterID]; !ok { | |||
| resultMap[issueRecord.PosterID] = 1 | |||
| } else { | |||
| resultMap[issueRecord.PosterID] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func queryCommitActionPublic(start_unix int64, end_unix int64, actionType int64, publicAllRepo map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| cond := "user_id=act_user_id and op_type=" + fmt.Sprint(actionType) + " and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Where(cond).Count(new(Action)) | |||
| if err != nil { | |||
| log.Info("query action error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,user_id,op_type,act_user_id,repo_id").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| actionList := make([]*Action, 0) | |||
| sess.Find(&actionList) | |||
| log.Info("query action size=" + fmt.Sprint(len(actionList))) | |||
| for _, actionRecord := range actionList { | |||
| if isPublicRepo(actionRecord.RepoID, publicAllRepo) { | |||
| if _, ok := resultMap[actionRecord.UserID]; !ok { | |||
| resultMap[actionRecord.UserID] = 1 | |||
| } else { | |||
| resultMap[actionRecord.UserID] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func queryCreateIssuePublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) (map[int64]int, map[int64]int) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| publicRepoIssueIdMap := make(map[int64]int) | |||
| cond := "is_pull=false and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Where(cond).Count(new(Issue)) | |||
| if err != nil { | |||
| log.Info("query Issue error. return.") | |||
| return resultMap, publicRepoIssueIdMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,poster_id,repo_id").Table("issue").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| issueList := make([]*Issue, 0) | |||
| sess.Find(&issueList) | |||
| log.Info("query issue size=" + fmt.Sprint(len(issueList))) | |||
| for _, issueRecord := range issueList { | |||
| if isPublicRepo(issueRecord.RepoID, publicAllRepo) { | |||
| if _, ok := resultMap[issueRecord.PosterID]; !ok { | |||
| resultMap[issueRecord.PosterID] = 1 | |||
| } else { | |||
| resultMap[issueRecord.PosterID] += 1 | |||
| } | |||
| publicRepoIssueIdMap[issueRecord.ID] = 1 | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap, publicRepoIssueIdMap | |||
| } | |||
| func queryCommentPublic(start_unix int64, end_unix int64, publicRepoIssueIdMap map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| cond := "created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
| resultMap := make(map[int64]int) | |||
| count, err := sess.Where(cond).Count(new(Comment)) | |||
| if err != nil { | |||
| log.Info("query Comment error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,type,poster_id,issue_id").Table("comment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| commentList := make([]*Comment, 0) | |||
| sess.Find(&commentList) | |||
| log.Info("query Comment size=" + fmt.Sprint(len(commentList))) | |||
| for _, commentRecord := range commentList { | |||
| if isPublicRepo(commentRecord.IssueID, publicRepoIssueIdMap) { | |||
| if _, ok := resultMap[commentRecord.PosterID]; !ok { | |||
| resultMap[commentRecord.PosterID] = 1 | |||
| } else { | |||
| resultMap[commentRecord.PosterID] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func queryAllPublicDataSet(publicAllRepo map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| publicDataSetIdMap := make(map[int64]int) | |||
| count, err := sess.Count(new(Dataset)) | |||
| if err != nil { | |||
| log.Info("query dataset error. return.") | |||
| return publicDataSetIdMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,user_id,repo_id").Table(new(Dataset)).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| datasetList := make([]*Dataset, 0) | |||
| sess.Find(&datasetList) | |||
| log.Info("query datasetList size=" + fmt.Sprint(len(datasetList))) | |||
| for _, datasetRecord := range datasetList { | |||
| if isPublicRepo(datasetRecord.RepoID, publicAllRepo) { | |||
| publicDataSetIdMap[datasetRecord.ID] = 1 | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return publicDataSetIdMap | |||
| } | |||
| func queryPublicDatasetFileNums(start_unix int64, end_unix int64, publicDataSetIdMap map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultNumMap := make(map[int64]int) | |||
| cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Where(cond).Count(new(Attachment)) | |||
| if err != nil { | |||
| log.Info("query attachment error. return.") | |||
| return resultNumMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,uploader_id,size,dataset_id").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| attachmentList := make([]*Attachment, 0) | |||
| sess.Find(&attachmentList) | |||
| log.Info("query Attachment size=" + fmt.Sprint(len(attachmentList))) | |||
| for _, attachRecord := range attachmentList { | |||
| if isPublicRepo(attachRecord.DatasetID, publicDataSetIdMap) { | |||
| if _, ok := resultNumMap[attachRecord.UploaderID]; !ok { | |||
| resultNumMap[attachRecord.UploaderID] = 1 | |||
| } else { | |||
| resultNumMap[attachRecord.UploaderID] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultNumMap | |||
| } | |||
| func queryUserModelPublic(start_unix int64, end_unix int64, publicAllRepo map[int64]int) map[int64]int { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| resultMap := make(map[int64]int) | |||
| cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
| count, err := sess.Where(cond).Count(new(AiModelManage)) | |||
| if err != nil { | |||
| log.Info("query AiModelManage error. return.") | |||
| return resultMap | |||
| } | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| for { | |||
| sess.Select("id,user_id,repo_id").Table("ai_model_manage").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| aiModelList := make([]*AiModelManage, 0) | |||
| sess.Find(&aiModelList) | |||
| log.Info("query AiModelManage size=" + fmt.Sprint(len(aiModelList))) | |||
| for _, aiModelRecord := range aiModelList { | |||
| if isPublicRepo(aiModelRecord.RepoId, publicAllRepo) { | |||
| if _, ok := resultMap[aiModelRecord.UserId]; !ok { | |||
| resultMap[aiModelRecord.UserId] = 1 | |||
| } else { | |||
| resultMap[aiModelRecord.UserId] += 1 | |||
| } | |||
| } | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| return resultMap | |||
| } | |||
| func QueryUserLoginInfo(userIds []int64) []*UserLoginLog { | |||
| statictisSess := xStatistic.NewSession() | |||
| defer statictisSess.Close() | |||
| var cond = builder.NewCond() | |||
| cond = cond.And(builder.In("u_id", userIds)) | |||
| statictisSess.Select("*").Table(new(UserLoginLog)).Where(cond) | |||
| loginList := make([]*UserLoginLog, 0) | |||
| statictisSess.Find(&loginList) | |||
| return loginList | |||
| } | |||
| @@ -105,12 +105,14 @@ type UserBusinessAnalysisAll struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysis struct { | |||
| ID int64 `xorm:"pk"` | |||
| CountDate int64 `xorm:"pk"` | |||
| ID int64 `xorm:"pk"` | |||
| DataDate string `xorm:"pk"` | |||
| CountDate int64 `xorm:"NULL"` | |||
| //action :ActionMergePullRequest // 11 | |||
| CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"` | |||
| @@ -169,8 +171,6 @@ type UserBusinessAnalysis struct { | |||
| //user | |||
| Name string `xorm:"NOT NULL"` | |||
| DataDate string `xorm:"NULL"` | |||
| CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"` | |||
| GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"` | |||
| NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"` | |||
| @@ -192,6 +192,8 @@ type UserBusinessAnalysis struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisQueryOptions struct { | |||
| @@ -358,7 +360,7 @@ func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, q | |||
| var cond = builder.NewCond() | |||
| if len(userName) > 0 { | |||
| cond = cond.And( | |||
| builder.Like{"name", userName}, | |||
| builder.Like{"lower(name)", strings.ToLower(userName)}, | |||
| ) | |||
| } | |||
| allCount, err := statictisSess.Where(cond).Count(queryObj) | |||
| @@ -407,6 +409,51 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi | |||
| return userBusinessAnalysisReturnList, allCount | |||
| } | |||
| func QueryDataForUserDefineFromDb(opts *UserBusinessAnalysisQueryOptions, key string) ([]*UserBusinessAnalysis, int64) { | |||
| statictisSess := xStatistic.NewSession() | |||
| defer statictisSess.Close() | |||
| var cond = builder.NewCond() | |||
| cond = cond.And( | |||
| builder.Eq{"data_date": key}, | |||
| ) | |||
| if len(opts.UserName) > 0 { | |||
| cond = cond.And( | |||
| builder.Like{"name", opts.UserName}, | |||
| ) | |||
| } | |||
| allCount, err := statictisSess.Where(cond).Count(new(UserBusinessAnalysis)) | |||
| if err == nil { | |||
| if allCount > 0 { | |||
| userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0) | |||
| if err := statictisSess.Table("user_business_analysis").Where(cond).OrderBy("id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize). | |||
| Find(&userBusinessAnalysisList); err != nil { | |||
| return nil, 0 | |||
| } | |||
| return userBusinessAnalysisList, allCount | |||
| } | |||
| } | |||
| return nil, 0 | |||
| } | |||
| func WriteDataToDb(dataList []*UserBusinessAnalysis, key string) { | |||
| statictisSess := xStatistic.NewSession() | |||
| defer statictisSess.Close() | |||
| log.Info("write to db, size=" + fmt.Sprint(len(dataList))) | |||
| userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0) | |||
| for _, data := range dataList { | |||
| data.DataDate = key | |||
| userBusinessAnalysisList = append(userBusinessAnalysisList, data) | |||
| if len(userBusinessAnalysisList) > BATCH_INSERT_SIZE { | |||
| statictisSess.Insert(userBusinessAnalysisList) | |||
| userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0) | |||
| } | |||
| } | |||
| if len(userBusinessAnalysisList) > 0 { | |||
| statictisSess.Insert(userBusinessAnalysisList) | |||
| } | |||
| } | |||
| func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wikiCountMap map[string]int) ([]*UserBusinessAnalysis, int64) { | |||
| log.Info("start to count other user info data") | |||
| sess := x.NewSession() | |||
| @@ -475,6 +522,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi | |||
| dateRecord.CountDate = CountDate.Unix() | |||
| dateRecord.DataDate = DataDate | |||
| dateRecord.Email = userRecord.Email | |||
| dateRecord.Phone = userRecord.PhoneNumber | |||
| dateRecord.RegistDate = userRecord.CreatedUnix | |||
| dateRecord.Name = userRecord.Name | |||
| dateRecord.UserLocation = userRecord.Location | |||
| @@ -728,6 +776,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
| var dateRecordAll UserBusinessAnalysisAll | |||
| dateRecordAll.ID = userRecord.ID | |||
| dateRecordAll.Email = userRecord.Email | |||
| dateRecordAll.Phone = userRecord.PhoneNumber | |||
| dateRecordAll.RegistDate = userRecord.CreatedUnix | |||
| dateRecordAll.Name = userRecord.Name | |||
| dateRecordAll.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) | |||
| @@ -839,7 +888,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||
| insertBatchSql := "INSERT INTO public." + tableName + | |||
| "(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + | |||
| "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive) " + | |||
| "commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone) " + | |||
| "VALUES" | |||
| for i, record := range dateRecords { | |||
| @@ -848,7 +897,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||
| ", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + | |||
| ", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + | |||
| ", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "'," + | |||
| fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ")" | |||
| fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "')" | |||
| if i < (len(dateRecords) - 1) { | |||
| insertBatchSql += "," | |||
| } | |||
| @@ -914,7 +963,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| CountDate = time.Date(startTime.Year(), startTime.Month(), startTime.Day(), 0, 1, 0, 0, currentTimeNow.Location()) | |||
| } | |||
| DataDate := startTime.Format("2006-01-02") | |||
| DataDate := CountDate.Format("2006-01-02") | |||
| CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
| CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
| IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
| @@ -948,6 +997,9 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| statictisSess := xStatistic.NewSession() | |||
| defer statictisSess.Close() | |||
| log.Info("truncate all data from table:user_business_analysis ") | |||
| statictisSess.Exec("TRUNCATE TABLE user_business_analysis") | |||
| cond := "type != 1" | |||
| count, err := sess.Where(cond).Count(new(User)) | |||
| if err != nil { | |||
| @@ -973,6 +1025,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| dateRecord.CountDate = CountDate.Unix() | |||
| dateRecord.Email = userRecord.Email | |||
| dateRecord.Phone = userRecord.PhoneNumber | |||
| dateRecord.RegistDate = userRecord.CreatedUnix | |||
| dateRecord.Name = userRecord.Name | |||
| dateRecord.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) | |||
| @@ -1028,12 +1081,12 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord) | |||
| if getUserActivate(dateRecord) > 0 { | |||
| log.Info("has activity." + userRecord.Name) | |||
| addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID) | |||
| addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) | |||
| } | |||
| if userRecord.IsActive { | |||
| addUserToMap(userAcitvateJsonMap, userRecord.CreatedUnix, dateRecord.ID) | |||
| addUserToMap(userAcitvateJsonMap, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) | |||
| } | |||
| addUserToMap(userCurrentDayRegistMap, userRecord.CreatedUnix, dateRecord.ID) | |||
| addUserToMap(userCurrentDayRegistMap, userRecord.CreatedUnix, dateRecord.ID, currentTimeNow) | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| @@ -1056,7 +1109,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics) | |||
| useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) | |||
| useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics) | |||
| useMetrics.CurrentDayRegistUser = getMapKeyStringValue("CurrentDayRegistUser", userMetrics) | |||
| count, err = sess.Where("type=0").Count(new(User)) | |||
| if err != nil { | |||
| log.Info("query user error. return.") | |||
| @@ -1096,6 +1149,8 @@ func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, userA | |||
| ",activate_regist_user=" + fmt.Sprint(useMetrics.ActivateRegistUser) + | |||
| ",not_activate_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser-useMetrics.ActivateRegistUser) + | |||
| ",current_day_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser) + | |||
| ",activate_index=" + fmt.Sprint(float64(useMetrics.ActivateRegistUser)/float64(useMetrics.CurrentDayRegistUser)) + | |||
| ",data_date='" + time.Unix(key, 0).Format("2006-01-02") + "'" + | |||
| " where count_date=" + fmt.Sprint(key) | |||
| statictisSess.Exec(updateSql) | |||
| @@ -1124,8 +1179,9 @@ func setUniqueUserId(jsonString string, value map[int64]int64) (string, int) { | |||
| return userIdArray, len(value) | |||
| } | |||
| func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64) { | |||
| CountDateTime := time.Date(registDate.Year(), registDate.AsTime().Month(), registDate.AsTime().Day(), 0, 1, 0, 0, registDate.AsTime().Location()) | |||
| func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64, currentTimeNow time.Time) { | |||
| registTime := registDate.AsTimeInLocation(currentTimeNow.Location()) | |||
| CountDateTime := time.Date(registTime.Year(), registTime.Month(), registTime.Day(), 0, 1, 0, 0, currentTimeNow.Location()) | |||
| CountDate := CountDateTime.Unix() | |||
| if _, ok := currentUserActivity[CountDate]; !ok { | |||
| userIdMap := make(map[int64]int64, 0) | |||
| @@ -1149,6 +1205,7 @@ func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, en | |||
| } else { | |||
| userMetrics["NotActivateRegistUser"] = getMapKeyStringValue("NotActivateRegistUser", userMetrics) + 1 | |||
| } | |||
| userMetrics["CurrentDayRegistUser"] = getMapKeyStringValue("CurrentDayRegistUser", userMetrics) + 1 | |||
| } | |||
| if user.IsActive { | |||
| userMetrics["TotalActivateRegistUser"] = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) + 1 | |||
| @@ -65,6 +65,8 @@ type UserBusinessAnalysisCurrentYear struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisLast30Day struct { | |||
| @@ -130,6 +132,8 @@ type UserBusinessAnalysisLast30Day struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisLastMonth struct { | |||
| @@ -195,6 +199,8 @@ type UserBusinessAnalysisLastMonth struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisCurrentMonth struct { | |||
| @@ -260,6 +266,8 @@ type UserBusinessAnalysisCurrentMonth struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisCurrentWeek struct { | |||
| @@ -326,6 +334,8 @@ type UserBusinessAnalysisCurrentWeek struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisYesterday struct { | |||
| @@ -392,6 +402,8 @@ type UserBusinessAnalysisYesterday struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserBusinessAnalysisLastWeek struct { | |||
| @@ -458,6 +470,8 @@ type UserBusinessAnalysisLastWeek struct { | |||
| CollectImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| CollectedImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| RecommendImage int `xorm:"NOT NULL DEFAULT 0"` | |||
| Phone string `xorm:"NULL"` | |||
| } | |||
| type UserAnalysisPara struct { | |||
| @@ -23,6 +23,8 @@ type CreateCloudBrainForm struct { | |||
| BootFile string `form:"boot_file"` | |||
| Params string `form:"run_para_list"` | |||
| BranchName string `form:"branch_name"` | |||
| DatasetName string `form:"dataset_name"` | |||
| SpecId int64 `form:"spec_id"` | |||
| } | |||
| type CommitImageCloudBrainForm struct { | |||
| @@ -50,6 +52,30 @@ type EditImageCloudBrainForm struct { | |||
| Topics string `form:"topics"` | |||
| } | |||
| type CreateCloudBrainInferencForm struct { | |||
| JobName string `form:"job_name" binding:"Required"` | |||
| DisplayJobName string `form:"display_job_name" binding:"Required"` | |||
| Image string `form:"image" binding:"Required"` | |||
| Command string `form:"command" binding:"Required"` | |||
| Attachment string `form:"attachment" binding:"Required"` | |||
| JobType string `form:"job_type" binding:"Required"` | |||
| BenchmarkCategory string `form:"get_benchmark_category"` | |||
| GpuType string `form:"gpu_type"` | |||
| TrainUrl string `form:"train_url"` | |||
| TestUrl string `form:"test_url"` | |||
| Description string `form:"description"` | |||
| ResourceSpecId int `form:"resource_spec_id" binding:"Required"` | |||
| BootFile string `form:"boot_file"` | |||
| Params string `form:"run_para_list"` | |||
| BranchName string `form:"branch_name"` | |||
| ModelName string `form:"model_name" binding:"Required"` | |||
| ModelVersion string `form:"model_version" binding:"Required"` | |||
| CkptName string `form:"ckpt_name" binding:"Required"` | |||
| LabelName string `form:"label_names" binding:"Required"` | |||
| DatasetName string `form:"dataset_name"` | |||
| SpecId int64 `form:"spec_id"` | |||
| } | |||
| func (f *CreateCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| @@ -61,3 +87,7 @@ func (f *CommitImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding. | |||
| func (f *EditImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| func (f *CreateCloudBrainInferencForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| @@ -44,3 +44,11 @@ type EditAttachmentForm struct { | |||
| func (f *EditAttachmentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| type ReferenceDatasetForm struct { | |||
| DatasetID []int64 `binding:"Required"` | |||
| } | |||
| func (f *ReferenceDatasetForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| @@ -11,14 +11,14 @@ type CreateGrampusTrainJobForm struct { | |||
| Attachment string `form:"attachment" binding:"Required"` | |||
| BootFile string `form:"boot_file" binding:"Required"` | |||
| ImageID string `form:"image_id" binding:"Required"` | |||
| FlavorID string `form:"flavor" binding:"Required"` | |||
| Params string `form:"run_para_list" binding:"Required"` | |||
| Description string `form:"description"` | |||
| BranchName string `form:"branch_name" binding:"Required"` | |||
| FlavorName string `form:"flavor_name" binding:"Required"` | |||
| EngineName string `form:"engine_name" binding:"Required"` | |||
| WorkServerNumber int `form:"work_server_number" binding:"Required"` | |||
| Image string `form:"image"` | |||
| DatasetName string `form:"dataset_name"` | |||
| SpecId int64 `form:"spec_id"` | |||
| } | |||
| func (f *CreateGrampusTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| @@ -22,6 +22,7 @@ type CreateModelArtsNotebookForm struct { | |||
| Description string `form:"description"` | |||
| Flavor string `form:"flavor" binding:"Required"` | |||
| ImageId string `form:"image_id" binding:"Required"` | |||
| SpecId int64 `form:"spec_id" binding:"Required"` | |||
| } | |||
| func (f *CreateModelArtsNotebookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| @@ -46,6 +47,7 @@ type CreateModelArtsTrainJobForm struct { | |||
| VersionName string `form:"version_name" binding:"Required"` | |||
| FlavorName string `form:"flaver_names" binding:"Required"` | |||
| EngineName string `form:"engine_names" binding:"Required"` | |||
| SpecId int64 `form:"spec_id" binding:"Required"` | |||
| } | |||
| type CreateModelArtsInferenceJobForm struct { | |||
| @@ -71,6 +73,7 @@ type CreateModelArtsInferenceJobForm struct { | |||
| ModelName string `form:"model_name" binding:"Required"` | |||
| ModelVersion string `form:"model_version" binding:"Required"` | |||
| CkptName string `form:"ckpt_name" binding:"Required"` | |||
| SpecId int64 `form:"spec_id" binding:"Required"` | |||
| } | |||
| func (f *CreateModelArtsTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| @@ -19,6 +19,7 @@ const ( | |||
| ACCESS_TOKEN_PATH = "/cgi-bin/token" | |||
| QR_CODE_PATH = "/cgi-bin/qrcode/create" | |||
| GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material" | |||
| SEND_TEMPLATE_PATH = "/cgi-bin/message/template/send" | |||
| ACTION_QR_STR_SCENE = "QR_STR_SCENE" | |||
| ERR_CODE_ACCESSTOKEN_EXPIRE = 42001 | |||
| @@ -41,12 +42,34 @@ type QRCodeRequest struct { | |||
| Action_info ActionInfo `json:"action_info"` | |||
| Expire_seconds int `json:"expire_seconds"` | |||
| } | |||
| type MaterialRequest struct { | |||
| Type string `json:"type"` | |||
| Offset int `json:"offset"` | |||
| Count int `json:"count"` | |||
| } | |||
| type TemplateMsgRequest struct { | |||
| ToUser string `json:"touser"` | |||
| TemplateId string `json:"template_id"` | |||
| Url string `json:"url"` | |||
| ClientMsgId string `json:"client_msg_id"` | |||
| Data interface{} `json:"data"` | |||
| } | |||
| type TemplateValue struct { | |||
| Value string `json:"value"` | |||
| Color string `json:"color"` | |||
| } | |||
| type DefaultWechatTemplate struct { | |||
| First TemplateValue `json:"first"` | |||
| Keyword1 TemplateValue `json:"keyword1"` | |||
| Keyword2 TemplateValue `json:"keyword2"` | |||
| Keyword3 TemplateValue `json:"keyword3"` | |||
| Keyword4 TemplateValue `json:"keyword4"` | |||
| Remark TemplateValue `json:"remark"` | |||
| } | |||
| type ActionInfo struct { | |||
| Scene Scene `json:"scene"` | |||
| } | |||
| @@ -163,3 +186,27 @@ func getErrorCodeFromResponse(r *resty.Response) int { | |||
| c, _ := strconv.Atoi(fmt.Sprint(code)) | |||
| return c | |||
| } | |||
| func sendTemplateMsg(req TemplateMsgRequest) (error, bool) { | |||
| client := getWechatRestyClient() | |||
| bodyJson, _ := json.Marshal(req) | |||
| r, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetQueryParam("access_token", GetWechatAccessToken()). | |||
| SetBody(bodyJson). | |||
| Post(setting.WechatApiHost + SEND_TEMPLATE_PATH) | |||
| if err != nil { | |||
| log.Error("sendTemplateMsg,e=%v", err) | |||
| return nil, false | |||
| } | |||
| a := r.Body() | |||
| resultMap := make(map[string]interface{}, 0) | |||
| json.Unmarshal(a, &resultMap) | |||
| errcode := resultMap["errcode"] | |||
| log.Info("sendTemplateMsg,%v", r) | |||
| if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) { | |||
| return nil, true | |||
| } | |||
| return nil, false | |||
| } | |||
| @@ -0,0 +1,167 @@ | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "fmt" | |||
| "time" | |||
| ) | |||
| type JobOperateType string | |||
| const ( | |||
| JobOperateTypeStart JobOperateType = "start" | |||
| JobOperateTypeStop JobOperateType = "stop" | |||
| ) | |||
| type CloudbrainStartMsg struct { | |||
| } | |||
| func (CloudbrainStartMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate { | |||
| return &DefaultWechatTemplate{ | |||
| First: TemplateValue{Value: setting.CloudbrainStartedTitle}, | |||
| Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName}, | |||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)}, | |||
| Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||
| Remark: TemplateValue{Value: setting.CloudbrainStartedRemark}, | |||
| } | |||
| } | |||
| func (CloudbrainStartMsg) ShouldSend(ctx *TemplateContext) bool { | |||
| if len(setting.CloudbrainStartedNotifyList) == 0 { | |||
| return false | |||
| } | |||
| for _, v := range setting.CloudbrainStartedNotifyList { | |||
| if v == ctx.Cloudbrain.JobType { | |||
| return true | |||
| } | |||
| } | |||
| return false | |||
| } | |||
| func (CloudbrainStartMsg) MsgId(ctx *TemplateContext) string { | |||
| return string(JobOperateTypeStart) + "_" + fmt.Sprint(ctx.Cloudbrain.ID) | |||
| } | |||
| func (CloudbrainStartMsg) Url(ctx *TemplateContext) string { | |||
| repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID) | |||
| if err != nil { | |||
| log.Error("CloudbrainStartMsg GetRepositoryByID error,%v", err) | |||
| return "" | |||
| } | |||
| return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo) | |||
| } | |||
| func (CloudbrainStartMsg) TemplateId(ctx *TemplateContext) string { | |||
| return setting.CloudbrainStartedTemplateId | |||
| } | |||
| type CloudbrainStopMsg struct { | |||
| } | |||
| func (CloudbrainStopMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate { | |||
| return &DefaultWechatTemplate{ | |||
| First: TemplateValue{Value: setting.CloudbrainStoppedTitle}, | |||
| Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName}, | |||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)}, | |||
| Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||
| Keyword4: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.EndTime), 0).Format("2006-01-02 15:04:05")}, | |||
| Remark: TemplateValue{Value: setting.CloudbrainStoppedRemark}, | |||
| } | |||
| } | |||
| func (CloudbrainStopMsg) ShouldSend(ctx *TemplateContext) bool { | |||
| if len(setting.CloudbrainStoppedNotifyList) == 0 { | |||
| return false | |||
| } | |||
| for _, v := range setting.CloudbrainStoppedNotifyList { | |||
| if v == ctx.Cloudbrain.JobType { | |||
| if ctx.Cloudbrain.Duration > 0 && ctx.Cloudbrain.EndTime > 0 { | |||
| return true | |||
| } | |||
| break | |||
| } | |||
| } | |||
| return false | |||
| } | |||
| func (CloudbrainStopMsg) MsgId(ctx *TemplateContext) string { | |||
| return string(JobOperateTypeStop) + "_" + fmt.Sprint(ctx.Cloudbrain.ID) | |||
| } | |||
| func (CloudbrainStopMsg) Url(ctx *TemplateContext) string { | |||
| repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID) | |||
| if err != nil { | |||
| log.Error("CloudbrainStopMsg GetRepositoryByID error,%v", err) | |||
| return "" | |||
| } | |||
| return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo) | |||
| } | |||
| func (CloudbrainStopMsg) TemplateId(ctx *TemplateContext) string { | |||
| return setting.CloudbrainStoppedTemplateId | |||
| } | |||
| var startMsg = &CloudbrainStartMsg{} | |||
| var stopMsg = &CloudbrainStopMsg{} | |||
| func GetTemplateFromOperateType(operate JobOperateType) Template { | |||
| switch operate { | |||
| case JobOperateTypeStart: | |||
| return startMsg | |||
| case JobOperateTypeStop: | |||
| return stopMsg | |||
| } | |||
| return nil | |||
| } | |||
| func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType { | |||
| if cloudbrain.IsTerminal() { | |||
| return JobOperateTypeStop | |||
| } | |||
| if cloudbrain.IsRunning() { | |||
| return JobOperateTypeStart | |||
| } | |||
| return "" | |||
| } | |||
| func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string { | |||
| url := setting.AppURL + repo.FullName() | |||
| switch cloudbrain.JobType { | |||
| case string(models.JobTypeDebug): | |||
| if cloudbrain.ComputeResource == "CPU/GPU" { | |||
| url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID) | |||
| } else { | |||
| url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID) | |||
| } | |||
| case string(models.JobTypeBenchmark): | |||
| url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID) | |||
| case string(models.JobTypeTrain): | |||
| if cloudbrain.Type == models.TypeCloudBrainOne { | |||
| url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } else if cloudbrain.Type == models.TypeCloudBrainTwo { | |||
| url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } else if cloudbrain.Type == models.TypeC2Net { | |||
| url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } | |||
| case string(models.JobTypeInference): | |||
| url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } | |||
| return url | |||
| } | |||
| func getJobTypeDisplayName(jobType string) string { | |||
| switch jobType { | |||
| case string(models.JobTypeDebug): | |||
| return "调试任务" | |||
| case string(models.JobTypeBenchmark): | |||
| return "评测任务" | |||
| case string(models.JobTypeTrain): | |||
| return "训练任务" | |||
| case string(models.JobTypeInference): | |||
| return "推理任务" | |||
| } | |||
| return "" | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "errors" | |||
| "fmt" | |||
| ) | |||
| type Template interface { | |||
| ShouldSend(ctx *TemplateContext) bool | |||
| Data(ctx *TemplateContext) *DefaultWechatTemplate | |||
| MsgId(ctx *TemplateContext) string | |||
| Url(ctx *TemplateContext) string | |||
| TemplateId(ctx *TemplateContext) string | |||
| } | |||
| type TemplateContext struct { | |||
| Cloudbrain *models.Cloudbrain | |||
| } | |||
| func SendTemplateMsg(template Template, ctx *TemplateContext, userId int64) error { | |||
| defer func() { | |||
| if err := recover(); err != nil { | |||
| combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) | |||
| log.Error("PANIC:", combinedErr) | |||
| } | |||
| }() | |||
| if !template.ShouldSend(ctx) { | |||
| log.Info("SendTemplateMsg should not Send.jobId=%d jobType=%s", ctx.Cloudbrain.ID, ctx.Cloudbrain.JobType) | |||
| return nil | |||
| } | |||
| openId := models.GetUserWechatOpenId(userId) | |||
| if openId == "" { | |||
| log.Error("Wechat openId not exist,userId=%d", userId) | |||
| return errors.New("Wechat openId not exist") | |||
| } | |||
| req := TemplateMsgRequest{ | |||
| ToUser: openId, | |||
| TemplateId: template.TemplateId(ctx), | |||
| Url: template.Url(ctx), | |||
| ClientMsgId: template.MsgId(ctx), | |||
| Data: template.Data(ctx), | |||
| } | |||
| err, retryFlag := sendTemplateMsg(req) | |||
| if retryFlag { | |||
| log.Info("SendTemplateMsg calling") | |||
| refreshAccessToken() | |||
| err, _ = sendTemplateMsg(req) | |||
| if err != nil { | |||
| log.Error("SendTemplateMsg err. %v", err) | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| if err != nil { | |||
| log.Error("SendTemplateMsg err. %v", err) | |||
| return err | |||
| } | |||
| log.Info("SendTemplateMsg success") | |||
| return nil | |||
| } | |||
| @@ -3,6 +3,7 @@ package cloudbrain | |||
| import ( | |||
| "encoding/json" | |||
| "errors" | |||
| "os" | |||
| "strconv" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| @@ -17,7 +18,7 @@ import ( | |||
| ) | |||
| const ( | |||
| Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"` | |||
| //Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"` | |||
| //CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"` | |||
| CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"` | |||
| CodeMountPath = "/code" | |||
| @@ -37,12 +38,15 @@ const ( | |||
| Success = "S000" | |||
| DefaultBranchName = "master" | |||
| ResultPath = "/result" | |||
| ) | |||
| var ( | |||
| ResourceSpecs *models.ResourceSpecs | |||
| TrainResourceSpecs *models.ResourceSpecs | |||
| SpecialPools *models.SpecialPools | |||
| ResourceSpecs *models.ResourceSpecs | |||
| TrainResourceSpecs *models.ResourceSpecs | |||
| InferenceResourceSpecs *models.ResourceSpecs | |||
| SpecialPools *models.SpecialPools | |||
| ) | |||
| type GenerateCloudBrainTaskReq struct { | |||
| @@ -57,7 +61,6 @@ type GenerateCloudBrainTaskReq struct { | |||
| Snn4ImageNetPath string | |||
| BrainScorePath string | |||
| JobType string | |||
| GpuQueue string | |||
| Description string | |||
| BranchName string | |||
| BootFile string | |||
| @@ -68,7 +71,18 @@ type GenerateCloudBrainTaskReq struct { | |||
| DatasetInfos map[string]models.DatasetInfo | |||
| BenchmarkTypeID int | |||
| BenchmarkChildTypeID int | |||
| ResourceSpecId int | |||
| ResultPath string | |||
| TrainUrl string | |||
| ModelName string | |||
| ModelVersion string | |||
| CkptName string | |||
| LabelName string | |||
| Spec *models.Specification | |||
| } | |||
| func GetCloudbrainDebugCommand() string { | |||
| var command = `pip3 install jupyterlab==3 -i https://pypi.tuna.tsinghua.edu.cn/simple;pip3 install -U "nbclassic>=0.2.8" -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --ServerApp.shutdown_no_activity_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_inactive_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_idle_timeout=` + setting.CullIdleTimeout + ` --MappingKernelManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_connected=True --MappingKernelManager.cull_busy=True --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --ServerApp.token="" --LabApp.token="" --ServerApp.allow_origin="self https://cloudbrain.pcl.ac.cn" ` | |||
| return command | |||
| } | |||
| func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
| @@ -127,8 +141,8 @@ func isAdminOrImageCreater(ctx *context.Context, image *models.Image, err error) | |||
| func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(ID) | |||
| var id = ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(id) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByID failed:%v", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| @@ -143,8 +157,8 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| func AdminOrJobCreaterRight(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(ID) | |||
| var id = ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(id) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByID failed:%v", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| @@ -212,54 +226,9 @@ func AdminOrImageCreaterRight(ctx *context.Context) { | |||
| } | |||
| func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| var resourceSpec *models.ResourceSpec | |||
| var versionCount int | |||
| if req.JobType == string(models.JobTypeTrain) { | |||
| versionCount = 1 | |||
| if TrainResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.TrainResourceSpecs), &TrainResourceSpecs) | |||
| } | |||
| for _, spec := range TrainResourceSpecs.ResourceSpec { | |||
| if req.ResourceSpecId == spec.Id { | |||
| resourceSpec = spec | |||
| break | |||
| } | |||
| } | |||
| } else { | |||
| if ResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) | |||
| } | |||
| for _, spec := range ResourceSpecs.ResourceSpec { | |||
| if req.ResourceSpecId == spec.Id { | |||
| resourceSpec = spec | |||
| break | |||
| } | |||
| } | |||
| } | |||
| //如果没有匹配到spec信息,尝试从专属资源池获取 | |||
| if resourceSpec == nil && SpecialPools != nil { | |||
| for _, specialPool := range SpecialPools.Pools { | |||
| if resourceSpec != nil { | |||
| break | |||
| } | |||
| if specialPool.ResourceSpec != nil { | |||
| if IsElementExist(specialPool.JobType, req.JobType) && IsQueueInSpecialtPool(specialPool.Pool, req.GpuQueue) { | |||
| for _, spec := range specialPool.ResourceSpec { | |||
| if req.ResourceSpecId == spec.Id { | |||
| resourceSpec = spec | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if resourceSpec == nil { | |||
| log.Error("no such resourceSpecId(%d)", req.ResourceSpecId, req.Ctx.Data["MsgID"]) | |||
| return errors.New("no such resourceSpec") | |||
| } | |||
| volumes := []models.Volume{ | |||
| @@ -298,6 +267,13 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| ReadOnly: true, | |||
| }, | |||
| }, | |||
| { | |||
| HostPath: models.StHostPath{ | |||
| Path: req.ResultPath, | |||
| MountPath: ResultPath, | |||
| ReadOnly: false, | |||
| }, | |||
| }, | |||
| } | |||
| if len(req.DatasetInfos) == 1 { | |||
| @@ -308,7 +284,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| ReadOnly: true, | |||
| }, | |||
| }) | |||
| } else { | |||
| } else if len(req.DatasetInfos) > 1 { | |||
| for _, dataset := range req.DatasetInfos { | |||
| volumes = append(volumes, models.Volume{ | |||
| HostPath: models.StHostPath{ | |||
| @@ -324,7 +300,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| jobResult, err := CreateJob(req.JobName, models.CreateJobParams{ | |||
| JobName: req.JobName, | |||
| RetryCount: 1, | |||
| GpuType: req.GpuQueue, | |||
| GpuType: req.Spec.QueueCode, | |||
| Image: req.Image, | |||
| TaskRoles: []models.TaskRole{ | |||
| { | |||
| @@ -332,10 +308,10 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| TaskNumber: 1, | |||
| MinSucceededTaskCount: 1, | |||
| MinFailedTaskCount: 1, | |||
| CPUNumber: resourceSpec.CpuNum, | |||
| GPUNumber: resourceSpec.GpuNum, | |||
| MemoryMB: resourceSpec.MemMiB, | |||
| ShmMB: resourceSpec.ShareMemMiB, | |||
| CPUNumber: req.Spec.CpuCores, | |||
| GPUNumber: req.Spec.AccCardsNum, | |||
| MemoryMB: int(req.Spec.MemGiB * 1024), | |||
| ShmMB: int(req.Spec.ShareMemGiB * 1024), | |||
| Command: req.Command, | |||
| NeedIBDevice: false, | |||
| IsMainRole: false, | |||
| @@ -366,8 +342,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| Type: models.TypeCloudBrainOne, | |||
| Uuid: req.Uuids, | |||
| Image: req.Image, | |||
| GpuQueue: req.GpuQueue, | |||
| ResourceSpecId: req.ResourceSpecId, | |||
| GpuQueue: req.Spec.QueueCode, | |||
| ComputeResource: models.GPUResource, | |||
| BenchmarkTypeID: req.BenchmarkTypeID, | |||
| BenchmarkChildTypeID: req.BenchmarkChildTypeID, | |||
| @@ -378,9 +353,16 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| BootFile: req.BootFile, | |||
| DatasetName: req.DatasetNames, | |||
| Parameters: req.Params, | |||
| TrainUrl: req.TrainUrl, | |||
| ModelName: req.ModelName, | |||
| ModelVersion: req.ModelVersion, | |||
| CkptName: req.CkptName, | |||
| ResultUrl: req.ResultPath, | |||
| LabelName: req.LabelName, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| CommitID: req.CommitID, | |||
| Spec: req.Spec, | |||
| }) | |||
| if err != nil { | |||
| @@ -392,12 +374,15 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||
| log.Error("GetCloudbrainByJobID failed: %v", err.Error()) | |||
| return err | |||
| } | |||
| stringId := strconv.FormatInt(task.ID, 10) | |||
| if IsBenchmarkJob(req.JobType) { | |||
| notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateBenchMarkTask) | |||
| } else if string(models.JobTypeTrain) == req.JobType { | |||
| notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateGPUTrainTask) | |||
| } else if string(models.JobTypeInference) == req.JobType { | |||
| notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateInferenceTask) | |||
| } else { | |||
| notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateDebugGPUTask) | |||
| } | |||
| @@ -409,30 +394,29 @@ func IsBenchmarkJob(jobType string) bool { | |||
| return string(models.JobTypeBenchmark) == jobType || string(models.JobTypeBrainScore) == jobType || string(models.JobTypeSnn4imagenet) == jobType | |||
| } | |||
| func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...models.JobType) int64 { | |||
| num, err := models.GetWaitingCloudbrainCount(cloudbrainType, computeResource, jobTypes...) | |||
| if err != nil { | |||
| log.Warn("Get waiting count err", err) | |||
| num = 0 | |||
| } | |||
| return num | |||
| } | |||
| func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) error { | |||
| jobName := task.JobName | |||
| var resourceSpec *models.ResourceSpec | |||
| if ResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) | |||
| } | |||
| for _, spec := range ResourceSpecs.ResourceSpec { | |||
| if task.ResourceSpecId == spec.Id { | |||
| resourceSpec = spec | |||
| spec := task.Spec | |||
| var datasetInfos map[string]models.DatasetInfo | |||
| if task.Uuid != "" { | |||
| var err error | |||
| datasetInfos, _, err = models.GetDatasetInfo(task.Uuid) | |||
| if err != nil { | |||
| log.Error("GetDatasetInfo failed:%v", err, ctx.Data["MsgID"]) | |||
| return err | |||
| } | |||
| } | |||
| if resourceSpec == nil { | |||
| log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"]) | |||
| return errors.New("no such resourceSpec") | |||
| } | |||
| datasetInfos, _, err := models.GetDatasetInfo(task.Uuid) | |||
| if err != nil { | |||
| log.Error("GetDatasetInfo failed:%v", err, ctx.Data["MsgID"]) | |||
| return err | |||
| } | |||
| volumes := []models.Volume{ | |||
| { | |||
| HostPath: models.StHostPath{ | |||
| @@ -470,24 +454,25 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| }, | |||
| }, | |||
| } | |||
| if len(datasetInfos) == 1 { | |||
| volumes = append(volumes, models.Volume{ | |||
| HostPath: models.StHostPath{ | |||
| Path: datasetInfos[task.Uuid].DataLocalPath, | |||
| MountPath: DataSetMountPath, | |||
| ReadOnly: true, | |||
| }, | |||
| }) | |||
| } else { | |||
| for _, dataset := range datasetInfos { | |||
| if datasetInfos != nil { | |||
| if len(datasetInfos) == 1 { | |||
| volumes = append(volumes, models.Volume{ | |||
| HostPath: models.StHostPath{ | |||
| Path: dataset.DataLocalPath, | |||
| MountPath: DataSetMountPath + "/" + dataset.Name, | |||
| Path: datasetInfos[task.Uuid].DataLocalPath, | |||
| MountPath: DataSetMountPath, | |||
| ReadOnly: true, | |||
| }, | |||
| }) | |||
| } else { | |||
| for _, dataset := range datasetInfos { | |||
| volumes = append(volumes, models.Volume{ | |||
| HostPath: models.StHostPath{ | |||
| Path: dataset.DataLocalPath, | |||
| MountPath: DataSetMountPath + "/" + dataset.Name, | |||
| ReadOnly: true, | |||
| }, | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| @@ -503,11 +488,11 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| TaskNumber: 1, | |||
| MinSucceededTaskCount: 1, | |||
| MinFailedTaskCount: 1, | |||
| CPUNumber: resourceSpec.CpuNum, | |||
| GPUNumber: resourceSpec.GpuNum, | |||
| MemoryMB: resourceSpec.MemMiB, | |||
| ShmMB: resourceSpec.ShareMemMiB, | |||
| Command: Command, | |||
| CPUNumber: spec.CpuCores, | |||
| GPUNumber: spec.AccCardsNum, | |||
| MemoryMB: int(spec.MemGiB * 1024), | |||
| ShmMB: int(spec.ShareMemGiB * 1024), | |||
| Command: GetCloudbrainDebugCommand(), //Command, | |||
| NeedIBDevice: false, | |||
| IsMainRole: false, | |||
| UseNNI: false, | |||
| @@ -544,6 +529,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| BranchName: task.BranchName, | |||
| Spec: spec, | |||
| } | |||
| err = models.RestartCloudbrain(task, newTask) | |||
| @@ -560,6 +546,63 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| return nil | |||
| } | |||
| func geMatchResourceSpec(jobType string, gpuQueue string, resourceSpecId int) *models.ResourceSpec { | |||
| for _, specialPool := range SpecialPools.Pools { | |||
| if specialPool.ResourceSpec != nil { | |||
| if IsElementExist(specialPool.JobType, jobType) && IsQueueInSpecialtPool(specialPool.Pool, gpuQueue) { | |||
| for _, spec := range specialPool.ResourceSpec { | |||
| if resourceSpecId == spec.Id { | |||
| return spec | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func DelCloudBrainJob(jobId string) string { | |||
| task, err := models.GetCloudbrainByJobID(jobId) | |||
| if err != nil { | |||
| log.Error("get cloud brain err:", err) | |||
| return "cloudbrain.Delete_failed" | |||
| } | |||
| if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) && task.Status != string(models.JobSucceeded) { | |||
| log.Error("the job(%s) has not been stopped", task.JobName) | |||
| return "cloudbrain.Not_Stopped" | |||
| } | |||
| err = models.DeleteJob(task) | |||
| if err != nil { | |||
| log.Error("DeleteJob failed:", err) | |||
| return "cloudbrain.Delete_failed" | |||
| } | |||
| deleteJobStorage(task.JobName) | |||
| return "" | |||
| } | |||
| func deleteJobStorage(jobName string) error { | |||
| //delete local | |||
| localJobPath := setting.JobPath + jobName | |||
| err := os.RemoveAll(localJobPath) | |||
| if err != nil { | |||
| log.Error("RemoveAll(%s) failed:%v", localJobPath, err) | |||
| } | |||
| dirPath := setting.CBCodePathPrefix + jobName + "/" | |||
| err = storage.Attachments.DeleteDir(dirPath) | |||
| if err != nil { | |||
| log.Error("DeleteDir(%s) failed:%v", localJobPath, err) | |||
| } | |||
| return nil | |||
| } | |||
| func InitSpecialPool() { | |||
| if SpecialPools == nil && setting.SpecialPools != "" { | |||
| json.Unmarshal([]byte(setting.SpecialPools), &SpecialPools) | |||
| @@ -29,8 +29,10 @@ const ( | |||
| Public = "public" | |||
| Custom = "custom" | |||
| LogPageSize = 500 | |||
| errInvalidToken = "S401" | |||
| LogPageTokenExpired = "5m" | |||
| pageSize = 15 | |||
| QueuesDetailUrl = "/rest-server/api/v2/queuesdetail" | |||
| ) | |||
| func getRestyClient() *resty.Client { | |||
| @@ -59,7 +61,7 @@ func loginCloudbrain() error { | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetBody(map[string]interface{}{"username": username, "password": password, "expiration": "604800"}). | |||
| SetBody(map[string]interface{}{"username": username, "password": password, "expiration": conf.Expiration}). | |||
| SetResult(&loginResult). | |||
| Post(HOST + "/rest-server/api/v1/token") | |||
| if err != nil { | |||
| @@ -74,12 +76,51 @@ func loginCloudbrain() error { | |||
| return nil | |||
| } | |||
| func GetQueuesDetail() (*map[string]int, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var jobResult models.QueueDetailResult | |||
| var result = make(map[string]int, 0) | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&jobResult). | |||
| Get(HOST + QueuesDetailUrl) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty get queues detail failed: %s", err) | |||
| } | |||
| if jobResult.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| } | |||
| if jobResult.Code != Success { | |||
| return nil, fmt.Errorf("jobResult err: %s", res.String()) | |||
| } | |||
| for k, v := range jobResult.Payload { | |||
| result[k] = v.JobScheduleInfo.Pending | |||
| } | |||
| return &result, nil | |||
| } | |||
| func CreateJob(jobName string, createJobParams models.CreateJobParams) (*models.CreateJobResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var jobResult models.CreateJobResult | |||
| retry := 0 | |||
| reqPara, _ := json.Marshal(createJobParams) | |||
| log.Warn("job req:", string(reqPara[:])) | |||
| sendjob: | |||
| res, err := client.R(). | |||
| @@ -90,16 +131,12 @@ sendjob: | |||
| Post(HOST + "/rest-server/api/v1/jobs/") | |||
| if err != nil { | |||
| if res != nil { | |||
| var response models.CloudBrainResult | |||
| json.Unmarshal(res.Body(), &response) | |||
| log.Error("code(%s), msg(%s)", response.Code, response.Msg) | |||
| return nil, fmt.Errorf(response.Msg) | |||
| } | |||
| return nil, fmt.Errorf("resty create job: %s", err) | |||
| } | |||
| if jobResult.Code == "S401" && retry < 1 { | |||
| var response models.CloudBrainResult | |||
| json.Unmarshal(res.Body(), &response) | |||
| if response.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| @@ -131,7 +168,9 @@ sendjob: | |||
| return nil, fmt.Errorf("resty GetJob: %v", err) | |||
| } | |||
| if getJobResult.Code == "S401" && retry < 1 { | |||
| var response models.CloudBrainResult | |||
| json.Unmarshal(res.Body(), &response) | |||
| if response.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| @@ -144,16 +183,6 @@ sendjob: | |||
| return &getJobResult, nil | |||
| } | |||
| func GetImages() (*models.GetImagesResult, error) { | |||
| return GetImagesPageable(1, 100, Custom, "") | |||
| } | |||
| func GetPublicImages() (*models.GetImagesResult, error) { | |||
| return GetImagesPageable(1, 100, Public, "") | |||
| } | |||
| func GetImagesPageable(page int, size int, imageType string, name string) (*models.GetImagesResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| @@ -174,13 +203,8 @@ sendjob: | |||
| } | |||
| var response models.CloudBrainResult | |||
| err = json.Unmarshal(res.Body(), &response) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed: %s", err.Error()) | |||
| return &getImagesResult, fmt.Errorf("json.Unmarshal failed: %s", err.Error()) | |||
| } | |||
| if response.Code == "S401" && retry < 1 { | |||
| json.Unmarshal(res.Body(), &response) | |||
| if response.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| @@ -268,7 +292,9 @@ sendjob: | |||
| return fmt.Errorf("resty CommitImage: %v", err) | |||
| } | |||
| if result.Code == "S401" && retry < 1 { | |||
| var response models.CloudBrainResult | |||
| json.Unmarshal(res.Body(), &response) | |||
| if response.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| @@ -290,6 +316,7 @@ sendjob: | |||
| } | |||
| err = models.WithTx(func(ctx models.DBContext) error { | |||
| models.UpdateAutoIncrementIndex() | |||
| if dbImage != nil { | |||
| dbImage.IsPrivate = params.IsPrivate | |||
| dbImage.Description = params.ImageDescription | |||
| @@ -423,7 +450,9 @@ sendjob: | |||
| return fmt.Errorf("resty StopJob: %v", err) | |||
| } | |||
| if result.Code == "S401" && retry < 1 { | |||
| var response models.CloudBrainResult | |||
| json.Unmarshal(res.Body(), &response) | |||
| if response.Code == errInvalidToken && retry < 1 { | |||
| retry++ | |||
| _ = loginCloudbrain() | |||
| goto sendjob | |||
| @@ -6,7 +6,6 @@ | |||
| package context | |||
| import ( | |||
| "code.gitea.io/gitea/routers/notice" | |||
| "html" | |||
| "html/template" | |||
| "io" | |||
| @@ -16,6 +15,8 @@ import ( | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/routers/notice" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -0,0 +1,43 @@ | |||
| package context | |||
| import ( | |||
| "net/http" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "gitea.com/macaron/macaron" | |||
| ) | |||
| func RequireRepoReaderJson(unitType models.UnitType) macaron.Handler { | |||
| return func(ctx *Context) { | |||
| if !ctx.Repo.CanRead(unitType) { | |||
| if log.IsTrace() { | |||
| if ctx.IsSigned { | |||
| log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+ | |||
| "User in Repo has Permissions: %-+v", | |||
| ctx.User, | |||
| unitType, | |||
| ctx.Repo.Repository, | |||
| ctx.Repo.Permission) | |||
| } else { | |||
| log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+ | |||
| "Anonymous user in Repo has Permissions: %-+v", | |||
| unitType, | |||
| ctx.Repo.Repository, | |||
| ctx.Repo.Permission) | |||
| } | |||
| } | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("error.no_right"))) | |||
| return | |||
| } | |||
| } | |||
| } | |||
| func RequireRepoWriterJson(unitType models.UnitType) macaron.Handler { | |||
| return func(ctx *Context) { | |||
| if !ctx.Repo.CanWrite(unitType) { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("error.no_right"))) | |||
| return | |||
| } | |||
| } | |||
| } | |||
| @@ -6,6 +6,8 @@ package cron | |||
| import ( | |||
| "code.gitea.io/gitea/services/reward" | |||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||
| "code.gitea.io/gitea/modules/modelarts" | |||
| "context" | |||
| "time" | |||
| @@ -230,6 +232,28 @@ func registerCloudbrainPointDeductTask() { | |||
| }) | |||
| } | |||
| func registerSyncResourceSpecs() { | |||
| RegisterTaskFatal("sync_grampus_specs", &BaseConfig{ | |||
| Enabled: true, | |||
| RunAtStart: true, | |||
| Schedule: "0 0 1 * * ?", | |||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||
| resource.SyncGrampusQueueAndSpecs() | |||
| return nil | |||
| }) | |||
| } | |||
| func registerSyncModelArtsTempJobs() { | |||
| RegisterTaskFatal("sync_model_arts_temp_jobs", &BaseConfig{ | |||
| Enabled: true, | |||
| RunAtStart: false, | |||
| Schedule: "@every 1m", | |||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||
| modelarts.SyncTempStatusJob() | |||
| return nil | |||
| }) | |||
| } | |||
| func initBasicTasks() { | |||
| registerUpdateMirrorTask() | |||
| registerRepoHealthCheck() | |||
| @@ -250,6 +274,8 @@ func initBasicTasks() { | |||
| registerSyncCloudbrainStatus() | |||
| registerHandleOrgStatistic() | |||
| registerSyncResourceSpecs() | |||
| registerSyncModelArtsTempJobs() | |||
| //registerRewardPeriodTask() | |||
| registerCloudbrainPointDeductTask() | |||
| @@ -1,5 +1,7 @@ | |||
| package dataset | |||
| import "code.gitea.io/gitea/models" | |||
| func GetResourceType(cloudbrainType int) string { | |||
| if cloudbrainType == 0 { | |||
| return "CPU/GPU" | |||
| @@ -15,3 +17,19 @@ func GetStatusText(isPrivate bool) string { | |||
| return "dataset.public" | |||
| } | |||
| } | |||
| func IsShowDataSetOfCurrentRepo(repoID int64) bool { | |||
| repo := models.Repository{ | |||
| ID: repoID, | |||
| } | |||
| dataset, _ := models.GetDatasetByRepo(&repo) | |||
| if dataset != nil { | |||
| return true | |||
| } | |||
| if models.HasReferenceDataset(repoID) { | |||
| return false | |||
| } | |||
| return true | |||
| } | |||
| @@ -62,7 +62,7 @@ func GetUserKPIStats(repoPath string, startTime time.Time, endTime time.Time) (m | |||
| after := startTime.Format(time.RFC3339) | |||
| until := endTime.Format(time.RFC3339) | |||
| args := []string{"log", "--numstat", "--no-merges", "--branches=*", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--after='%s'", after), fmt.Sprintf("--until=='%s'", until)} | |||
| args := []string{"log", "--numstat", "--no-merges", "--branches=*", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--after='%s'", after), fmt.Sprintf("--until='%s'", until)} | |||
| stdout, err := NewCommand(args...).RunInDirBytes(repoPath) | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -23,9 +23,7 @@ const ( | |||
| NpuWorkDir = "/cache/" | |||
| CommandPrepareScript = ";mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" + | |||
| "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;" | |||
| //CommandPrepareScript = "pwd;cd /cache;mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" + | |||
| // "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;" | |||
| "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_npu downloader_for_minio uploader_for_gpu;" | |||
| CodeArchiveName = "master.zip" | |||
| ) | |||
| @@ -39,11 +37,10 @@ var ( | |||
| ) | |||
| type GenerateTrainJobReq struct { | |||
| JobName string | |||
| Command string | |||
| ResourceSpecId string | |||
| ImageUrl string //与image_id二选一,都有的情况下优先image_url | |||
| ImageId string | |||
| JobName string | |||
| Command string | |||
| ImageUrl string //与image_id二选一,都有的情况下优先image_url | |||
| ImageId string | |||
| DisplayJobName string | |||
| Uuid string | |||
| @@ -60,7 +57,6 @@ type GenerateTrainJobReq struct { | |||
| BranchName string | |||
| PreVersionId int64 | |||
| PreVersionName string | |||
| FlavorName string | |||
| VersionCount int | |||
| EngineName string | |||
| TotalVersionCount int | |||
| @@ -68,6 +64,7 @@ type GenerateTrainJobReq struct { | |||
| ProcessType string | |||
| DatasetName string | |||
| Params string | |||
| Spec *models.Specification | |||
| } | |||
| func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | |||
| @@ -81,7 +78,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| { | |||
| Name: req.JobName, | |||
| Command: req.Command, | |||
| ResourceSpecId: req.ResourceSpecId, | |||
| ResourceSpecId: req.Spec.SourceSpecId, | |||
| ImageId: req.ImageId, | |||
| ImageUrl: req.ImageUrl, | |||
| CenterID: centerID, | |||
| @@ -116,15 +113,14 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| Parameters: req.Params, | |||
| BootFile: req.BootFile, | |||
| DataUrl: req.DataUrl, | |||
| FlavorCode: req.ResourceSpecId, | |||
| Description: req.Description, | |||
| WorkServerNumber: req.WorkServerNumber, | |||
| FlavorName: req.FlavorName, | |||
| EngineName: req.EngineName, | |||
| VersionCount: req.VersionCount, | |||
| TotalVersionCount: req.TotalVersionCount, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| Spec: req.Spec, | |||
| }) | |||
| if err != nil { | |||
| @@ -23,6 +23,7 @@ const ( | |||
| urlGetToken = urlOpenApiV1 + "token" | |||
| urlTrainJob = urlOpenApiV1 + "trainjob" | |||
| urlGetResourceSpecs = urlOpenApiV1 + "resourcespec" | |||
| urlGetAiCenter = urlOpenApiV1 + "sharescreen/aicenter" | |||
| urlGetImages = urlOpenApiV1 + "image" | |||
| errorIllegalToken = 1005 | |||
| @@ -275,3 +276,35 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func GetAiCenters(pageIndex, pageSize int) (*models.GetGrampusAiCentersResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.GetGrampusAiCentersResult | |||
| retry := 0 | |||
| sendjob: | |||
| _, err := client.R(). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Get(HOST + urlGetAiCenter + "?pageIndex=" + fmt.Sprint(pageIndex) + "&pageSize=" + fmt.Sprint(pageSize)) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty GetAiCenters: %v", err) | |||
| } | |||
| if result.ErrorCode == errorIllegalToken && retry < 1 { | |||
| retry++ | |||
| log.Info("retry get token") | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if result.ErrorCode != 0 { | |||
| log.Error("GetAiCenters failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf("GetAiCenters failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| @@ -7,6 +7,7 @@ package markdown | |||
| import ( | |||
| "bytes" | |||
| "strings" | |||
| "sync" | |||
| "code.gitea.io/gitea/modules/log" | |||
| @@ -14,6 +15,8 @@ import ( | |||
| "code.gitea.io/gitea/modules/markup/common" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| giteautil "code.gitea.io/gitea/modules/util" | |||
| chromahtml "github.com/alecthomas/chroma/formatters/html" | |||
| highlighting "github.com/yuin/goldmark-highlighting" | |||
| "github.com/yuin/goldmark" | |||
| meta "github.com/yuin/goldmark-meta" | |||
| @@ -42,16 +45,48 @@ func NewGiteaParseContext(urlPrefix string, isWiki bool) parser.Context { | |||
| func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte { | |||
| once.Do(func() { | |||
| converter = goldmark.New( | |||
| goldmark.WithExtensions(extension.Table, | |||
| goldmark.WithExtensions( | |||
| extension.NewTable( | |||
| extension.WithTableCellAlignMethod(extension.TableCellAlignAttribute)), | |||
| extension.Strikethrough, | |||
| extension.TaskList, | |||
| extension.DefinitionList, | |||
| common.FootnoteExtension, | |||
| extension.NewTypographer( | |||
| extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{ | |||
| extension.EnDash: nil, | |||
| extension.EmDash: nil, | |||
| extension.Ellipsis: nil, | |||
| highlighting.NewHighlighting( | |||
| highlighting.WithFormatOptions( | |||
| chromahtml.WithClasses(true), | |||
| chromahtml.PreventSurroundingPre(true), | |||
| ), | |||
| highlighting.WithWrapperRenderer(func(w util.BufWriter, c highlighting.CodeBlockContext, entering bool) { | |||
| if entering { | |||
| language, _ := c.Language() | |||
| if language == nil { | |||
| language = []byte("text") | |||
| } | |||
| languageStr := string(language) | |||
| preClasses := []string{"code-block"} | |||
| if languageStr == "mermaid" { | |||
| preClasses = append(preClasses, "is-loading") | |||
| } | |||
| _, err := w.WriteString(`<pre class="` + strings.Join(preClasses, " ") + `">`) | |||
| if err != nil { | |||
| return | |||
| } | |||
| // include language-x class as part of commonmark spec | |||
| _, err = w.WriteString(`<code class="chroma language-` + string(language) + `">`) | |||
| if err != nil { | |||
| return | |||
| } | |||
| } else { | |||
| _, err := w.WriteString("</code></pre>") | |||
| if err != nil { | |||
| return | |||
| } | |||
| } | |||
| }), | |||
| ), | |||
| meta.Meta, | |||
| @@ -6,8 +6,7 @@ import ( | |||
| "fmt" | |||
| "path" | |||
| "strconv" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "strings" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| @@ -15,18 +14,19 @@ import ( | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/storage" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| const ( | |||
| //notebook | |||
| storageTypeOBS = "obs" | |||
| autoStopDuration = 4 * 60 * 60 | |||
| autoStopDurationMs = 4 * 60 * 60 * 1000 | |||
| DataSetMountPath = "/home/ma-user/work" | |||
| NotebookEnv = "Python3" | |||
| NotebookType = "Ascend" | |||
| FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||
| storageTypeOBS = "obs" | |||
| autoStopDuration = 4 * 60 * 60 | |||
| autoStopDurationMs = 4 * 60 * 60 * 1000 | |||
| MORDELART_USER_IMAGE_ENGINE_ID = -1 | |||
| DataSetMountPath = "/home/ma-user/work" | |||
| NotebookEnv = "Python3" | |||
| NotebookType = "Ascend" | |||
| FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||
| //train-job | |||
| // ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}" | |||
| @@ -59,7 +59,7 @@ const ( | |||
| PerPage = 10 | |||
| IsLatestVersion = "1" | |||
| NotLatestVersion = "0" | |||
| VersionCount = 1 | |||
| VersionCountOne = 1 | |||
| SortByCreateTime = "create_time" | |||
| ConfigTypeCustom = "custom" | |||
| @@ -67,9 +67,11 @@ const ( | |||
| ) | |||
| var ( | |||
| poolInfos *models.PoolInfos | |||
| FlavorInfos *models.FlavorInfos | |||
| ImageInfos *models.ImageInfosModelArts | |||
| poolInfos *models.PoolInfos | |||
| FlavorInfos *models.FlavorInfos | |||
| ImageInfos *models.ImageInfosModelArts | |||
| TrainFlavorInfos *Flavor | |||
| SpecialPools *models.SpecialPools | |||
| ) | |||
| type GenerateTrainJobReq struct { | |||
| @@ -82,7 +84,6 @@ type GenerateTrainJobReq struct { | |||
| BootFileUrl string | |||
| DataUrl string | |||
| TrainUrl string | |||
| FlavorCode string | |||
| LogUrl string | |||
| PoolID string | |||
| WorkServerNumber int | |||
| @@ -94,11 +95,15 @@ type GenerateTrainJobReq struct { | |||
| BranchName string | |||
| PreVersionId int64 | |||
| PreVersionName string | |||
| FlavorCode string | |||
| FlavorName string | |||
| VersionCount int | |||
| EngineName string | |||
| TotalVersionCount int | |||
| UserImageUrl string | |||
| UserCommand string | |||
| DatasetName string | |||
| Spec *models.Specification | |||
| } | |||
| type GenerateInferenceJobReq struct { | |||
| @@ -111,7 +116,6 @@ type GenerateInferenceJobReq struct { | |||
| BootFileUrl string | |||
| DataUrl string | |||
| TrainUrl string | |||
| FlavorCode string | |||
| LogUrl string | |||
| PoolID string | |||
| WorkServerNumber int | |||
| @@ -130,12 +134,15 @@ type GenerateInferenceJobReq struct { | |||
| ModelVersion string | |||
| CkptName string | |||
| ResultUrl string | |||
| Spec *models.Specification | |||
| DatasetName string | |||
| } | |||
| type VersionInfo struct { | |||
| Version []struct { | |||
| ID int `json:"id"` | |||
| Value string `json:"value"` | |||
| Url string `json:"url"` | |||
| } `json:"version"` | |||
| } | |||
| @@ -252,7 +259,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||
| return nil | |||
| } | |||
| func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, flavor, imageId string) error { | |||
| func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error { | |||
| if poolInfos == nil { | |||
| json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | |||
| } | |||
| @@ -266,7 +273,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| jobResult, err := createNotebook2(models.CreateNotebook2Params{ | |||
| JobName: jobName, | |||
| Description: description, | |||
| Flavor: flavor, | |||
| Flavor: spec.SourceSpecId, | |||
| Duration: autoStopDurationMs, | |||
| ImageID: imageId, | |||
| PoolID: poolInfos.PoolInfo[0].PoolId, | |||
| @@ -280,15 +287,30 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| }) | |||
| if err != nil { | |||
| log.Error("createNotebook2 failed: %v", err.Error()) | |||
| if strings.HasPrefix(err.Error(), UnknownErrorPrefix) { | |||
| log.Info("(%s)unknown error, set temp status", displayJobName) | |||
| errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{ | |||
| JobID: models.TempJobId, | |||
| VersionID: models.TempVersionId, | |||
| Status: models.TempJobStatus, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobName: jobName, | |||
| JobType: string(models.JobTypeDebug), | |||
| }) | |||
| if errTemp != nil { | |||
| log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | |||
| return errTemp | |||
| } | |||
| } | |||
| return err | |||
| } | |||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| task := &models.Cloudbrain{ | |||
| Status: jobResult.Status, | |||
| UserID: ctx.User.ID, | |||
| RepoID: ctx.Repo.Repository.ID, | |||
| JobID: jobResult.ID, | |||
| JobName: jobName, | |||
| FlavorCode: flavor, | |||
| FlavorCode: spec.SourceSpecId, | |||
| DisplayJobName: displayJobName, | |||
| JobType: string(models.JobTypeDebug), | |||
| Type: models.TypeCloudBrainTwo, | |||
| @@ -298,16 +320,14 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| Description: description, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| Spec: spec, | |||
| } | |||
| task, err := models.GetCloudbrainByName(jobName) | |||
| err = models.CreateCloudbrain(task) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByName failed: %v", err.Error()) | |||
| return err | |||
| } | |||
| stringId := strconv.FormatInt(task.ID, 10) | |||
| notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) | |||
| return nil | |||
| @@ -315,32 +335,71 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createTrainJob(models.CreateTrainJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| Config: models.Config{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| EngineID: req.EngineID, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.FlavorCode, | |||
| var jobResult *models.CreateTrainJobResult | |||
| var createErr error | |||
| if req.EngineID < 0 { | |||
| jobResult, createErr = createTrainJobUserImage(models.CreateUserImageTrainJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| Config: models.UserImageConfig{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.Spec.SourceSpecId, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| UserImageUrl: req.UserImageUrl, | |||
| UserCommand: req.UserCommand, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| }, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateJob failed: %v", err.Error()) | |||
| return err | |||
| }) | |||
| } else { | |||
| jobResult, createErr = createTrainJob(models.CreateTrainJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| Config: models.Config{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| EngineID: req.EngineID, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.Spec.SourceSpecId, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| }, | |||
| }) | |||
| } | |||
| if createErr != nil { | |||
| log.Error("createTrainJob failed: %v", createErr.Error()) | |||
| if strings.HasPrefix(createErr.Error(), UnknownErrorPrefix) { | |||
| log.Info("(%s)unknown error, set temp status", req.DisplayJobName) | |||
| errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{ | |||
| JobID: models.TempJobId, | |||
| VersionID: models.TempVersionId, | |||
| Status: models.TempJobStatus, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobName: req.JobName, | |||
| JobType: string(models.JobTypeTrain), | |||
| }) | |||
| if errTemp != nil { | |||
| log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | |||
| return errTemp | |||
| } | |||
| } | |||
| return createErr | |||
| } | |||
| jobId := strconv.FormatInt(jobResult.JobID, 10) | |||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| createErr = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| Status: TransTrainJobStatus(jobResult.Status), | |||
| UserID: ctx.User.ID, | |||
| RepoID: ctx.Repo.Repository.ID, | |||
| @@ -363,7 +422,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| BootFile: req.BootFile, | |||
| DataUrl: req.DataUrl, | |||
| LogUrl: req.LogUrl, | |||
| FlavorCode: req.FlavorCode, | |||
| FlavorCode: req.Spec.SourceSpecId, | |||
| Description: req.Description, | |||
| WorkServerNumber: req.WorkServerNumber, | |||
| FlavorName: req.FlavorName, | |||
| @@ -372,57 +431,122 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| TotalVersionCount: req.TotalVersionCount, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| Spec: req.Spec, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, err.Error()) | |||
| return err | |||
| if createErr != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, createErr.Error()) | |||
| return createErr | |||
| } | |||
| notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobId, req.DisplayJobName, models.ActionCreateTrainTask) | |||
| return nil | |||
| } | |||
| func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||
| func GenerateModelConvertTrainJob(req *GenerateTrainJobReq) (*models.CreateTrainJobResult, error) { | |||
| return createTrainJobUserImage(models.CreateUserImageTrainJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| Config: models.TrainJobVersionConfig{ | |||
| Config: models.UserImageConfig{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| EngineID: req.EngineID, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.FlavorCode, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| PreVersionId: req.PreVersionId, | |||
| UserImageUrl: req.UserImageUrl, | |||
| UserCommand: req.UserCommand, | |||
| }, | |||
| }, jobId) | |||
| if err != nil { | |||
| log.Error("CreateJob failed: %v", err.Error()) | |||
| return err | |||
| }) | |||
| } | |||
| func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| var jobResult *models.CreateTrainJobResult | |||
| var createErr error | |||
| if req.EngineID < 0 { | |||
| jobResult, createErr = createTrainJobVersionUserImage(models.CreateTrainJobVersionUserImageParams{ | |||
| Description: req.Description, | |||
| Config: models.TrainJobVersionUserImageConfig{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| Flavor: models.Flavor{ | |||
| Code: req.Spec.SourceSpecId, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| PreVersionId: req.PreVersionId, | |||
| UserImageUrl: req.UserImageUrl, | |||
| UserCommand: req.UserCommand, | |||
| }, | |||
| }, jobId) | |||
| } else { | |||
| jobResult, createErr = createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||
| Description: req.Description, | |||
| Config: models.TrainJobVersionConfig{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| EngineID: req.EngineID, | |||
| TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| Flavor: models.Flavor{ | |||
| Code: req.Spec.SourceSpecId, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| PreVersionId: req.PreVersionId, | |||
| }, | |||
| }, jobId) | |||
| } | |||
| if createErr != nil { | |||
| log.Error("createTrainJobVersion failed: %v", createErr.Error()) | |||
| if strings.HasPrefix(createErr.Error(), UnknownErrorPrefix) { | |||
| log.Info("(%s)unknown error, set temp status", req.DisplayJobName) | |||
| errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{ | |||
| JobID: jobId, | |||
| VersionID: models.TempVersionId, | |||
| Status: models.TempJobStatus, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobName: req.JobName, | |||
| JobType: string(models.JobTypeTrain), | |||
| }) | |||
| if errTemp != nil { | |||
| log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | |||
| return errTemp | |||
| } | |||
| } | |||
| return createErr | |||
| } | |||
| var jobTypes []string | |||
| jobTypes = append(jobTypes, string(models.JobTypeTrain)) | |||
| repo := ctx.Repo.Repository | |||
| VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
| VersionTaskList, VersionListCount, createErr := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Cloudbrain", err) | |||
| return err | |||
| if createErr != nil { | |||
| ctx.ServerError("Cloudbrain", createErr) | |||
| return createErr | |||
| } | |||
| //将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount | |||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| createErr = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| Status: TransTrainJobStatus(jobResult.Status), | |||
| UserID: ctx.User.ID, | |||
| RepoID: ctx.Repo.Repository.ID, | |||
| @@ -447,7 +571,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||
| DataUrl: req.DataUrl, | |||
| LogUrl: req.LogUrl, | |||
| PreVersionId: req.PreVersionId, | |||
| FlavorCode: req.FlavorCode, | |||
| FlavorCode: req.Spec.SourceSpecId, | |||
| Description: req.Description, | |||
| WorkServerNumber: req.WorkServerNumber, | |||
| FlavorName: req.FlavorName, | |||
| @@ -456,20 +580,21 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||
| VersionCount: VersionListCount + 1, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| Spec: req.Spec, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error()) | |||
| return err | |||
| if createErr != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error()) | |||
| return createErr | |||
| } | |||
| //将训练任务的上一版本的isLatestVersion设置为"0" | |||
| err = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount) | |||
| if err != nil { | |||
| ctx.ServerError("Update IsLatestVersion failed", err) | |||
| return err | |||
| createErr = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCountOne, NotLatestVersion, TotalVersionCount) | |||
| if createErr != nil { | |||
| ctx.ServerError("Update IsLatestVersion failed", createErr) | |||
| return createErr | |||
| } | |||
| return err | |||
| return createErr | |||
| } | |||
| func TransTrainJobStatus(status int) string { | |||
| @@ -546,21 +671,36 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.FlavorCode, | |||
| Code: req.Spec.SourceSpecId, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| }, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateJob failed: %v", err.Error()) | |||
| log.Error("createInferenceJob failed: %v", err.Error()) | |||
| if strings.HasPrefix(err.Error(), UnknownErrorPrefix) { | |||
| log.Info("(%s)unknown error, set temp status", req.DisplayJobName) | |||
| err = models.InsertCloudbrainTemp(&models.CloudbrainTemp{ | |||
| JobID: models.TempJobId, | |||
| VersionID: models.TempVersionId, | |||
| Status: models.TempJobStatus, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobName: req.JobName, | |||
| JobType: string(models.JobTypeInference), | |||
| }) | |||
| if err != nil { | |||
| log.Error("InsertCloudbrainTemp failed: %v", err.Error()) | |||
| return err | |||
| } | |||
| } | |||
| return err | |||
| } | |||
| attach, err := models.GetAttachmentByUUID(req.Uuid) | |||
| if err != nil { | |||
| log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | |||
| return err | |||
| } | |||
| // attach, err := models.GetAttachmentByUUID(req.Uuid) | |||
| // if err != nil { | |||
| // log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | |||
| // return err | |||
| // } | |||
| jobID := strconv.FormatInt(jobResult.JobID, 10) | |||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | |||
| Status: TransTrainJobStatus(jobResult.Status), | |||
| @@ -574,7 +714,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e | |||
| VersionID: jobResult.VersionID, | |||
| VersionName: jobResult.VersionName, | |||
| Uuid: req.Uuid, | |||
| DatasetName: attach.Name, | |||
| DatasetName: req.DatasetName, | |||
| CommitID: req.CommitID, | |||
| EngineID: req.EngineID, | |||
| TrainUrl: req.TrainUrl, | |||
| @@ -583,7 +723,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e | |||
| BootFile: req.BootFile, | |||
| DataUrl: req.DataUrl, | |||
| LogUrl: req.LogUrl, | |||
| FlavorCode: req.FlavorCode, | |||
| FlavorCode: req.Spec.SourceSpecId, | |||
| Description: req.Description, | |||
| WorkServerNumber: req.WorkServerNumber, | |||
| FlavorName: req.FlavorName, | |||
| @@ -599,6 +739,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e | |||
| ResultUrl: req.ResultUrl, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| Spec: req.Spec, | |||
| }) | |||
| if err != nil { | |||
| @@ -631,3 +772,461 @@ func GetNotebookImageName(imageId string) (string, error) { | |||
| return imageName, nil | |||
| } | |||
| func InitSpecialPool() { | |||
| if SpecialPools == nil && setting.ModelArtsSpecialPools != "" { | |||
| json.Unmarshal([]byte(setting.ModelArtsSpecialPools), &SpecialPools) | |||
| } | |||
| } | |||
| func HandleTrainJobInfo(task *models.Cloudbrain) error { | |||
| result, err := GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) | |||
| if err != nil { | |||
| log.Error("GetTrainJob(%s) failed:%v", task.DisplayJobName, err) | |||
| return err | |||
| } | |||
| if result != nil { | |||
| oldStatus := task.Status | |||
| task.Status = TransTrainJobStatus(result.IntStatus) | |||
| task.Duration = result.Duration / 1000 | |||
| task.TrainJobDuration = result.TrainJobDuration | |||
| if task.StartTime == 0 && result.StartTime > 0 { | |||
| task.StartTime = timeutil.TimeStamp(result.StartTime / 1000) | |||
| } | |||
| task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | |||
| if task.EndTime == 0 && models.IsTrainJobTerminal(task.Status) && task.StartTime > 0 { | |||
| task.EndTime = task.StartTime.Add(task.Duration) | |||
| } | |||
| task.CorrectCreateUnix() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func HandleNotebookInfo(task *models.Cloudbrain) error { | |||
| result, err := GetNotebook2(task.JobID) | |||
| if err != nil { | |||
| log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err) | |||
| return err | |||
| } | |||
| if result != nil { | |||
| oldStatus := task.Status | |||
| task.Status = result.Status | |||
| if task.StartTime == 0 && result.Lease.UpdateTime > 0 { | |||
| task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) | |||
| } | |||
| if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.CorrectCreateUnix() | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| if task.FlavorCode == "" { | |||
| task.FlavorCode = result.Flavor | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func SyncTempStatusJob() { | |||
| jobs, err := models.GetCloudBrainTempJobs() | |||
| if err != nil { | |||
| log.Error("GetCloudBrainTempJobs failed:%v", err.Error()) | |||
| return | |||
| } | |||
| for _, temp := range jobs { | |||
| log.Info("start to handle record: %s", temp.JobName) | |||
| if temp.Type == models.TypeCloudBrainTwo { | |||
| if temp.JobType == string(models.JobTypeDebug) { | |||
| err = handleNotebook(temp) | |||
| if err != nil { | |||
| log.Error("handleNotebook falied:%v", err) | |||
| break | |||
| } | |||
| } else if temp.JobType == string(models.JobTypeTrain) || temp.JobType == string(models.JobTypeInference) { | |||
| _, err = models.GetCloudbrainByJobID(temp.JobID) | |||
| if err != nil { | |||
| //one version | |||
| err = handleTrainJob(temp) | |||
| if err != nil { | |||
| log.Error("handleTrainJob falied:%v", err) | |||
| break | |||
| } | |||
| } else { | |||
| //multi version | |||
| err = handleTrainJobMultiVersion(temp) | |||
| if err != nil { | |||
| log.Error("handleTrainJobMultiVersion falied:%v", err) | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| func handleNotebook(temp *models.CloudbrainTemp) error { | |||
| if temp.Status == models.TempJobStatus { | |||
| err := handleTempNotebook(temp) | |||
| if err != nil { | |||
| log.Error("handleTempNotebook failed:%v", err) | |||
| return err | |||
| } | |||
| } else if temp.Status == string(models.ModelArtsStopping) { | |||
| res, err := GetNotebook2(temp.JobID) | |||
| if err != nil { | |||
| log.Error("GetNotebook2 failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = res.Status | |||
| if temp.Status == string(models.ModelArtsStopped) { | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| _, err := DelNotebook2(temp.JobID) | |||
| if err != nil { | |||
| log.Error("DelNotebook2 failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = string(models.ModelArtsDeleted) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func handleTempNotebook(temp *models.CloudbrainTemp) error { | |||
| var err error | |||
| var isExist bool | |||
| for { | |||
| result, err := GetNotebookList(1000, 0, "createTime", "DESC", temp.JobName) | |||
| if err != nil { | |||
| log.Error("GetNotebookList failed:%v", err) | |||
| break | |||
| } | |||
| temp.QueryTimes++ | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| } | |||
| if result != nil { | |||
| for _, notebook := range result.NotebookList { | |||
| if temp.JobID == models.TempJobId { | |||
| //new notebook | |||
| if notebook.JobName == temp.JobName { | |||
| isExist = true | |||
| temp.Status = notebook.Status | |||
| temp.JobID = notebook.JobID | |||
| break | |||
| } | |||
| } else { | |||
| //restart: always can find one record | |||
| if notebook.JobName == temp.JobName { | |||
| if notebook.Status != string(models.ModelArtsStopped) { | |||
| isExist = true | |||
| temp.Status = notebook.Status | |||
| temp.JobID = notebook.JobID | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if isExist { | |||
| log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status) | |||
| if temp.Status == string(models.ModelArtsCreateFailed) { | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| break | |||
| } | |||
| _, err := DelNotebook2(temp.JobID) | |||
| if err != nil { | |||
| log.Error("DelNotebook2(%s) failed:%v", temp.JobName, err) | |||
| break | |||
| } | |||
| temp.Status = string(models.ModelArtsDeleted) | |||
| } else { | |||
| _, err := ManageNotebook2(temp.JobID, models.NotebookAction{Action: models.ActionStop}) | |||
| if err != nil { | |||
| log.Error("ManageNotebook2(%s) failed:%v", temp.JobName, err) | |||
| break | |||
| } | |||
| temp.Status = string(models.ModelArtsStopping) | |||
| } | |||
| models.UpdateCloudbrainTemp(temp) | |||
| } else { | |||
| log.Error("can not find the record(%s) till now", temp.JobName) | |||
| err = errors.New("not found") | |||
| break | |||
| } | |||
| } else { | |||
| log.Error("can not find the record(%s) till now", temp.JobName) | |||
| err = errors.New("not found") | |||
| break | |||
| } | |||
| break | |||
| } | |||
| if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist { | |||
| log.Info("reach MaxTempQueryTimes, set the job failed") | |||
| temp.Status = string(models.ModelArtsTrainJobFailed) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err) | |||
| return err | |||
| } | |||
| } | |||
| return err | |||
| } | |||
| func handleTrainJob(temp *models.CloudbrainTemp) error { | |||
| if temp.Status == models.TempJobStatus { | |||
| err := handleTempTrainJob(temp) | |||
| if err != nil { | |||
| log.Error("handleTempTrainJob failed:%v", err) | |||
| return err | |||
| } | |||
| } else if temp.Status == string(models.ModelArtsTrainJobKilling) { | |||
| res, err := GetTrainJob(temp.JobID, temp.VersionID) | |||
| if err != nil { | |||
| log.Error("GetTrainJob failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = TransTrainJobStatus(res.IntStatus) | |||
| if temp.Status == string(models.ModelArtsTrainJobKilled) { | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| _, err := DelTrainJob(temp.JobID) | |||
| if err != nil { | |||
| log.Error("DelTrainJob failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = string(models.ModelArtsDeleted) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func handleTrainJobMultiVersion(temp *models.CloudbrainTemp) error { | |||
| if temp.Status == models.TempJobStatus { | |||
| err := handleTempTrainJobMultiVersion(temp) | |||
| if err != nil { | |||
| log.Error("handleTempTrainJobMultiVersion failed:%v", err) | |||
| return err | |||
| } | |||
| } else if temp.Status == string(models.ModelArtsTrainJobKilling) { | |||
| res, err := GetTrainJob(temp.JobID, temp.VersionID) | |||
| if err != nil { | |||
| log.Error("GetTrainJob failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = TransTrainJobStatus(res.IntStatus) | |||
| if temp.Status == string(models.ModelArtsTrainJobKilled) { | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| _, err := DelTrainJobVersion(temp.JobID, temp.VersionID) | |||
| if err != nil { | |||
| log.Error("DelTrainJob failed:%v", err) | |||
| return err | |||
| } | |||
| temp.Status = string(models.ModelArtsDeleted) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func handleTempTrainJobMultiVersion(temp *models.CloudbrainTemp) error { | |||
| var err error | |||
| var isExist bool | |||
| for { | |||
| result, err := GetTrainJobVersionList(1000, 1, temp.JobID) | |||
| if err != nil { | |||
| log.Error("GetTrainJobVersionList failed:%v", err) | |||
| break | |||
| } | |||
| temp.QueryTimes++ | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| } | |||
| if result != nil { | |||
| count, _ := models.GetCloudbrainCountByJobName(temp.JobName, temp.JobType, temp.Type) | |||
| if result.VersionCount == int64(count+1) { | |||
| isExist = true | |||
| temp.Status = TransTrainJobStatus(result.JobVersionList[0].IntStatus) | |||
| temp.VersionID = strconv.FormatInt(result.JobVersionList[0].VersionID, 10) | |||
| log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status) | |||
| _, err := StopTrainJob(temp.JobID, temp.VersionID) | |||
| if err != nil { | |||
| log.Error("StopTrainJob failed:%v", err) | |||
| break | |||
| } | |||
| temp.Status = string(models.ModelArtsTrainJobKilling) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err) | |||
| break | |||
| } | |||
| } else { | |||
| log.Error("can not find the record(%s) till now", temp.JobName) | |||
| err = errors.New("not found") | |||
| break | |||
| } | |||
| } | |||
| break | |||
| } | |||
| if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist { | |||
| log.Info("reach MaxTempQueryTimes, set the job failed") | |||
| temp.Status = string(models.ModelArtsTrainJobFailed) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err) | |||
| return err | |||
| } | |||
| } | |||
| return err | |||
| } | |||
| func handleTempTrainJob(temp *models.CloudbrainTemp) error { | |||
| var err error | |||
| var isExist bool | |||
| for { | |||
| result, err := GetTrainJobList(1000, 1, "create_time", "desc", temp.JobName) | |||
| if err != nil { | |||
| log.Error("GetTrainJobList failed:%v", err) | |||
| break | |||
| } | |||
| temp.QueryTimes++ | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp failed:%v", err) | |||
| } | |||
| if result != nil { | |||
| for _, job := range result.JobList { | |||
| if temp.JobName == job.JobName && TransTrainJobStatus(job.IntStatus) != string(models.ModelArtsTrainJobFailed) { | |||
| isExist = true | |||
| temp.Status = TransTrainJobStatus(job.IntStatus) | |||
| temp.JobID = strconv.FormatInt(job.JobID, 10) | |||
| temp.VersionID = strconv.FormatInt(job.VersionID, 10) | |||
| log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status) | |||
| _, err = StopTrainJob(temp.JobID, temp.VersionID) | |||
| if err != nil { | |||
| log.Error("StopTrainJob(%s) failed:%v", temp.JobName, err) | |||
| break | |||
| } | |||
| temp.Status = string(models.ModelArtsTrainJobKilling) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err) | |||
| break | |||
| } | |||
| } | |||
| } | |||
| if !isExist { | |||
| log.Error("can not find the record(%s) till now", temp.JobName) | |||
| err = errors.New("not found") | |||
| break | |||
| } | |||
| } | |||
| break | |||
| } | |||
| if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist { | |||
| log.Info("reach MaxTempQueryTimes, set the job failed") | |||
| temp.Status = string(models.ModelArtsTrainJobFailed) | |||
| err = models.UpdateCloudbrainTemp(temp) | |||
| if err != nil { | |||
| log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err) | |||
| return err | |||
| } | |||
| } | |||
| return err | |||
| } | |||
| @@ -37,6 +37,7 @@ const ( | |||
| NotebookNotFound = "ModelArts.6404" | |||
| NotebookNoPermission = "ModelArts.6407" | |||
| NotebookInvalid = "ModelArts.6400" | |||
| UnknownErrorPrefix = "UNKNOWN:" | |||
| ) | |||
| func getRestyClient() *resty.Client { | |||
| @@ -298,6 +299,10 @@ sendjob: | |||
| return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error()) | |||
| } | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| if len(response.ErrorCode) != 0 { | |||
| log.Error("ManageNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| if response.ErrorCode == modelartsIllegalToken && retry < 1 { | |||
| @@ -472,7 +477,7 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) { | |||
| func createTrainJobUserImage(createJobParams models.CreateUserImageTrainJobParams) (*models.CreateTrainJobResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.CreateTrainJobResult | |||
| @@ -500,6 +505,63 @@ sendjob: | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| bootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'." | |||
| dataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'." | |||
| if temp.ErrorMsg == bootFileErrorMsg { | |||
| log.Error("启动文件错误!createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("启动文件错误!") | |||
| } | |||
| if temp.ErrorMsg == dataSetErrorMsg { | |||
| log.Error("数据集错误!createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("数据集错误!") | |||
| } | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } else { | |||
| return &result, fmt.Errorf("createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| } | |||
| if !result.IsSuccess { | |||
| log.Error("createTrainJobUserImage failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf("createTrainJobUserImage failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.CreateTrainJobResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetBody(createJobParams). | |||
| SetResult(&result). | |||
| Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty create train-job: %s", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| @@ -507,17 +569,21 @@ sendjob: | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'." | |||
| DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'." | |||
| if temp.ErrorMsg == BootFileErrorMsg { | |||
| bootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'." | |||
| dataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'." | |||
| if temp.ErrorMsg == bootFileErrorMsg { | |||
| log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("启动文件错误!") | |||
| } | |||
| if temp.ErrorMsg == DataSetErrorMsg { | |||
| if temp.ErrorMsg == dataSetErrorMsg { | |||
| log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("数据集错误!") | |||
| } | |||
| return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } else { | |||
| return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| } | |||
| if !result.IsSuccess { | |||
| @@ -535,6 +601,64 @@ func createTrainJobVersion(createJobVersionParams models.CreateTrainJobVersionPa | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetBody(createJobVersionParams). | |||
| SetResult(&result). | |||
| Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions") | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty create train-job version: %s", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| bootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'." | |||
| dataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'." | |||
| if temp.ErrorMsg == bootFileErrorMsg { | |||
| log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("启动文件错误!") | |||
| } | |||
| if temp.ErrorMsg == dataSetErrorMsg { | |||
| log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("数据集错误!") | |||
| } | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } else { | |||
| return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| } | |||
| if !result.IsSuccess { | |||
| log.Error("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func createTrainJobVersionUserImage(createJobVersionParams models.CreateTrainJobVersionUserImageParams, jobID string) (*models.CreateTrainJobResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.CreateTrainJobResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| @@ -650,9 +774,6 @@ sendjob: | |||
| goto sendjob | |||
| } | |||
| //temp, _ := json.Marshal(req) | |||
| //log.Info("%s", temp) | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| @@ -1061,7 +1182,11 @@ sendjob: | |||
| log.Error("数据集错误!createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("数据集错误!") | |||
| } | |||
| return &result, fmt.Errorf("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } else { | |||
| return &result, fmt.Errorf("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| } | |||
| if !result.IsSuccess { | |||
| @@ -1101,7 +1226,11 @@ sendjob: | |||
| err = json.Unmarshal(res.Body(), &response) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed: %s", err.Error()) | |||
| return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed: %s", err.Error()) | |||
| } | |||
| if res.StatusCode() == http.StatusBadGateway { | |||
| return &result, fmt.Errorf(UnknownErrorPrefix+"createNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| if len(response.ErrorCode) != 0 { | |||
| @@ -1160,3 +1289,139 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func GetTrainJobList(perPage, page int, sortBy, order, searchContent string) (*models.GetTrainJobListResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.GetTrainJobListResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetQueryParams(map[string]string{ | |||
| "per_page": strconv.Itoa(perPage), | |||
| "page": strconv.Itoa(page), | |||
| "sortBy": sortBy, | |||
| "order": order, | |||
| "search_content": searchContent, | |||
| }). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Get(HOST + "/v1/" + setting.ProjectID + urlTrainJob) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty GetTrainJobList: %v", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("GetTrainJobList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf(temp.ErrorMsg) | |||
| } | |||
| if !result.IsSuccess { | |||
| log.Error("GetTrainJobList failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf(result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func GetTrainJobVersionList(perPage, page int, jobID string) (*models.GetTrainJobVersionListResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.GetTrainJobVersionListResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetQueryParams(map[string]string{ | |||
| "per_page": strconv.Itoa(perPage), | |||
| "page": strconv.Itoa(page), | |||
| }). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Get(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions") | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty GetTrainJobVersionList: %v", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("GetTrainJobVersionList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf(temp.ErrorMsg) | |||
| } | |||
| if !result.IsSuccess { | |||
| log.Error("GetTrainJobVersionList failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf(result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func GetNotebookList(limit, offset int, sortBy, order, searchContent string) (*models.GetNotebookListResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.GetNotebookListResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetQueryParams(map[string]string{ | |||
| "limit": strconv.Itoa(limit), | |||
| "offset": strconv.Itoa(offset), | |||
| "name": searchContent, | |||
| "sort_key": sortBy, | |||
| "sort_dir": order, | |||
| }). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Get(HOST + "/v1/" + setting.ProjectID + urlNotebook2) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty GetNotebookList: %v", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| if res.StatusCode() != http.StatusOK { | |||
| var temp models.ErrorResult | |||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("GetNotebookList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf(temp.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| @@ -62,4 +62,6 @@ type Notifier interface { | |||
| NotifyCreateImage(doer *models.User, image models.Image) | |||
| NotifyImageRecommend(optUser *models.User, image *models.Image, action string) | |||
| NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) | |||
| NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) | |||
| } | |||
| @@ -176,3 +176,7 @@ func (*NullNotifier) NotifyImageRecommend(optUser *models.User, image *models.Im | |||
| func (*NullNotifier) NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| } | |||
| func (*NullNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| } | |||
| @@ -13,6 +13,7 @@ import ( | |||
| "code.gitea.io/gitea/modules/notification/mail" | |||
| "code.gitea.io/gitea/modules/notification/ui" | |||
| "code.gitea.io/gitea/modules/notification/webhook" | |||
| wechatNotifier "code.gitea.io/gitea/modules/notification/wechat" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| ) | |||
| @@ -36,6 +37,7 @@ func NewContext() { | |||
| RegisterNotifier(indexer.NewNotifier()) | |||
| RegisterNotifier(webhook.NewNotifier()) | |||
| RegisterNotifier(action.NewNotifier()) | |||
| RegisterNotifier(wechatNotifier.NewNotifier()) | |||
| } | |||
| // NotifyUploadAttachment notifies attachment upload message to notifiers | |||
| @@ -305,3 +307,10 @@ func NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| notifier.NotifyChangeUserAvatar(user, form) | |||
| } | |||
| } | |||
| // NotifyChangeCloudbrainStatus | |||
| func NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyChangeCloudbrainStatus(cloudbrain, oldStatus) | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth/wechat" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/notification/base" | |||
| ) | |||
| type wechatNotifier struct { | |||
| base.NullNotifier | |||
| } | |||
| var ( | |||
| _ base.Notifier = &wechatNotifier{} | |||
| ) | |||
| // NewNotifier create a new wechatNotifier notifier | |||
| func NewNotifier() base.Notifier { | |||
| return &wechatNotifier{} | |||
| } | |||
| func (*wechatNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| log.Info("NotifyChangeCloudbrainStatus cloudbrain.id=%d cloudbrain.status=%s oldStatus=%s", cloudbrain.ID, cloudbrain.Status, oldStatus) | |||
| operateType := wechat.GetJobOperateTypeFromCloudbrainStatus(cloudbrain) | |||
| if operateType == "" { | |||
| log.Info("NotifyChangeCloudbrainStatus operateType is incorrect") | |||
| return | |||
| } | |||
| template := wechat.GetTemplateFromOperateType(operateType) | |||
| go wechat.SendTemplateMsg(template, &wechat.TemplateContext{Cloudbrain: cloudbrain}, cloudbrain.UserID) | |||
| } | |||
| @@ -5,6 +5,7 @@ type CloudbrainLoginConfig struct { | |||
| Password string | |||
| Host string | |||
| ImageURLPrefix string | |||
| Expiration string | |||
| } | |||
| var ( | |||
| @@ -17,5 +18,6 @@ func GetCloudbrainConfig() CloudbrainLoginConfig { | |||
| Cloudbrain.Password = cloudbrainSec.Key("PASSWORD").MustString("") | |||
| Cloudbrain.Host = cloudbrainSec.Key("REST_SERVER_HOST").MustString("") | |||
| Cloudbrain.ImageURLPrefix = cloudbrainSec.Key("IMAGE_URL_PREFIX").MustString("") | |||
| Cloudbrain.Expiration = cloudbrainSec.Key("EXPIRATION").MustString("604800") | |||
| return Cloudbrain | |||
| } | |||
| @@ -193,8 +193,9 @@ var ( | |||
| Wiki: []string{"never"}, | |||
| }, | |||
| } | |||
| RepoRootPath string | |||
| ScriptType = "bash" | |||
| RepoRootPath string | |||
| RepoMaxReferenceDatasetNum int | |||
| ScriptType = "bash" | |||
| ) | |||
| func newRepository() { | |||
| @@ -210,6 +211,8 @@ func newRepository() { | |||
| Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool() | |||
| Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) | |||
| RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gitea-repositories")) | |||
| RepoMaxReferenceDatasetNum = sec.Key("MAX_REF_DATASET_NUM").MustInt(20) | |||
| forcePathSeparator(RepoRootPath) | |||
| if !filepath.IsAbs(RepoRootPath) { | |||
| RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath) | |||
| @@ -7,6 +7,7 @@ package setting | |||
| import ( | |||
| "encoding/base64" | |||
| "encoding/json" | |||
| "fmt" | |||
| "io" | |||
| "io/ioutil" | |||
| @@ -64,7 +65,16 @@ const ( | |||
| ReCaptcha = "recaptcha" | |||
| ) | |||
| // settings | |||
| type C2NetSequenceInfo struct { | |||
| ID int `json:"id"` | |||
| Name string `json:"name"` | |||
| Content string `json:"content"` | |||
| } | |||
| type C2NetSqInfos struct { | |||
| C2NetSqInfo []*C2NetSequenceInfo `json:"sequence"` | |||
| } | |||
| var ( | |||
| // AppVer settings | |||
| AppVer string | |||
| @@ -456,20 +466,26 @@ var ( | |||
| DecompressOBSTaskName string | |||
| //cloudbrain config | |||
| CBAuthUser string | |||
| CBAuthPassword string | |||
| RestServerHost string | |||
| JobPath string | |||
| CBCodePathPrefix string | |||
| JobType string | |||
| GpuTypes string | |||
| SpecialPools string | |||
| DebugServerHost string | |||
| ResourceSpecs string | |||
| MaxDuration int64 | |||
| TrainGpuTypes string | |||
| TrainResourceSpecs string | |||
| MaxDatasetNum int | |||
| CBAuthUser string | |||
| CBAuthPassword string | |||
| RestServerHost string | |||
| JobPath string | |||
| CBCodePathPrefix string | |||
| JobType string | |||
| GpuTypes string | |||
| SpecialPools string | |||
| DebugServerHost string | |||
| ResourceSpecs string | |||
| MaxDuration int64 | |||
| TrainGpuTypes string | |||
| TrainResourceSpecs string | |||
| InferenceGpuTypes string | |||
| InferenceResourceSpecs string | |||
| MaxModelSize float64 | |||
| MaxDatasetNum int | |||
| CullIdleTimeout string | |||
| CullInterval string | |||
| //benchmark config | |||
| IsBenchmarkEnabled bool | |||
| @@ -526,22 +542,27 @@ var ( | |||
| DebugHost string | |||
| ImageInfos string | |||
| Capacity int | |||
| MaxTempQueryTimes int | |||
| //train-job | |||
| ResourcePools string | |||
| Engines string | |||
| EngineVersions string | |||
| FlavorInfos string | |||
| TrainJobFLAVORINFOS string | |||
| ResourcePools string | |||
| Engines string | |||
| EngineVersions string | |||
| FlavorInfos string | |||
| TrainJobFLAVORINFOS string | |||
| ModelArtsSpecialPools string | |||
| //grampus config | |||
| Grampus = struct { | |||
| Env string | |||
| Host string | |||
| UserName string | |||
| Password string | |||
| SpecialPools string | |||
| Env string | |||
| Host string | |||
| UserName string | |||
| Password string | |||
| SpecialPools string | |||
| C2NetSequence string | |||
| }{} | |||
| C2NetInfos *C2NetSqInfos | |||
| //elk config | |||
| ElkUrl string | |||
| ElkUser string | |||
| @@ -573,6 +594,16 @@ var ( | |||
| TreePathOfAutoMsgReply string | |||
| TreePathOfSubscribe string | |||
| //wechat template msg config | |||
| CloudbrainStartedTemplateId string | |||
| CloudbrainStartedNotifyList []string | |||
| CloudbrainStartedTitle string | |||
| CloudbrainStartedRemark string | |||
| CloudbrainStoppedTemplateId string | |||
| CloudbrainStoppedNotifyList []string | |||
| CloudbrainStoppedTitle string | |||
| CloudbrainStoppedRemark string | |||
| //nginx proxy | |||
| PROXYURL string | |||
| RadarMap = struct { | |||
| @@ -623,6 +654,24 @@ var ( | |||
| OrgName string | |||
| TeamName string | |||
| }{} | |||
| ModelConvert = struct { | |||
| GPU_PYTORCH_IMAGE string | |||
| GpuQueue string | |||
| GPU_TENSORFLOW_IMAGE string | |||
| NPU_MINDSPORE_16_IMAGE string | |||
| PytorchOnnxBootFile string | |||
| PytorchTrTBootFile string | |||
| MindsporeBootFile string | |||
| TensorFlowNpuBootFile string | |||
| TensorFlowGpuBootFile string | |||
| ConvertRepoPath string | |||
| GPU_Resource_Specs_ID int | |||
| NPU_FlavorCode string | |||
| NPU_PoolID string | |||
| NPU_MINDSPORE_IMAGE_ID int | |||
| NPU_TENSORFLOW_IMAGE_ID int | |||
| }{} | |||
| ) | |||
| // DateLang transforms standard language locale name to corresponding value in datetime plugin. | |||
| @@ -1322,9 +1371,14 @@ func NewContext() { | |||
| MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) | |||
| TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") | |||
| TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") | |||
| MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500) | |||
| InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") | |||
| InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") | |||
| SpecialPools = sec.Key("SPECIAL_POOL").MustString("") | |||
| MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) | |||
| CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900") | |||
| CullInterval = sec.Key("CULL_INTERVAL").MustString("60") | |||
| sec = Cfg.Section("benchmark") | |||
| IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) | |||
| @@ -1381,11 +1435,13 @@ func NewContext() { | |||
| Flavor = sec.Key("FLAVOR").MustString("") | |||
| ImageInfos = sec.Key("IMAGE_INFOS").MustString("") | |||
| Capacity = sec.Key("IMAGE_INFOS").MustInt(100) | |||
| MaxTempQueryTimes = sec.Key("MAX_TEMP_QUERY_TIMES").MustInt(30) | |||
| ResourcePools = sec.Key("Resource_Pools").MustString("") | |||
| Engines = sec.Key("Engines").MustString("") | |||
| EngineVersions = sec.Key("Engine_Versions").MustString("") | |||
| FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("") | |||
| TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | |||
| ModelArtsSpecialPools = sec.Key("SPECIAL_POOL").MustString("") | |||
| sec = Cfg.Section("elk") | |||
| ElkUrl = sec.Key("ELKURL").MustString("") | |||
| @@ -1400,7 +1456,7 @@ func NewContext() { | |||
| WechatApiHost = sec.Key("HOST").MustString("https://api.weixin.qq.com") | |||
| WechatApiTimeoutSeconds = sec.Key("TIMEOUT_SECONDS").MustInt(3) | |||
| WechatAppId = sec.Key("APP_ID").MustString("wxba77b915a305a57d") | |||
| WechatAppSecret = sec.Key("APP_SECRET").MustString("e48e13f315adc32749ddc7057585f198") | |||
| WechatAppSecret = sec.Key("APP_SECRET").MustString("") | |||
| WechatQRCodeExpireSeconds = sec.Key("QR_CODE_EXPIRE_SECONDS").MustInt(120) | |||
| WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(false) | |||
| UserNameOfWechatReply = sec.Key("AUTO_REPLY_USER_NAME").MustString("OpenIOSSG") | |||
| @@ -1409,6 +1465,14 @@ func NewContext() { | |||
| TreePathOfAutoMsgReply = sec.Key("AUTO_REPLY_TREE_PATH").MustString("wechat/auto_reply.json") | |||
| TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") | |||
| WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(false) | |||
| CloudbrainStartedTemplateId = sec.Key("CLOUDBRAIN_STARTED_TEMPLATE_ID").MustString("") | |||
| CloudbrainStartedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STARTED_NOTIFY_LIST").MustString("DEBUG"), ",") | |||
| CloudbrainStartedTitle = sec.Key("CLOUDBRAIN_STARTED_TITLE").MustString("您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。") | |||
| CloudbrainStartedRemark = sec.Key("CLOUDBRAIN_STARTED_REMARK").MustString("感谢您的耐心等待。") | |||
| CloudbrainStoppedTemplateId = sec.Key("CLOUDBRAIN_STOPPED_TEMPLATE_ID").MustString("") | |||
| CloudbrainStoppedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STOPPED_NOTIFY_LIST").MustString("TRAIN"), ",") | |||
| CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,请您关注运行结果。") | |||
| CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。") | |||
| sec = Cfg.Section("point") | |||
| CloudBrainPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false) | |||
| @@ -1426,6 +1490,27 @@ func NewContext() { | |||
| Course.TeamName = sec.Key("team_name").MustString("") | |||
| GetGrampusConfig() | |||
| getModelConvertConfig() | |||
| } | |||
| func getModelConvertConfig() { | |||
| sec := Cfg.Section("model_convert") | |||
| ModelConvert.GPU_PYTORCH_IMAGE = sec.Key("GPU_PYTORCH_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap") | |||
| ModelConvert.GpuQueue = sec.Key("GpuQueue").MustString("openidgx") | |||
| ModelConvert.GPU_TENSORFLOW_IMAGE = sec.Key("GPU_TENSORFLOW_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx") | |||
| ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend") | |||
| ModelConvert.PytorchOnnxBootFile = sec.Key("PytorchOnnxBootFile").MustString("convert_pytorch.py") | |||
| ModelConvert.PytorchTrTBootFile = sec.Key("PytorchTrTBootFile").MustString("convert_pytorch_tensorrt.py") | |||
| ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py") | |||
| ModelConvert.TensorFlowNpuBootFile = sec.Key("TensorFlowNpuBootFile").MustString("convert_tensorflow.py") | |||
| ModelConvert.TensorFlowGpuBootFile = sec.Key("TensorFlowGpuBootFile").MustString("convert_tensorflow_gpu.py") | |||
| ModelConvert.ConvertRepoPath = sec.Key("ConvertRepoPath").MustString("https://git.openi.org.cn/zouap/npu_test") | |||
| ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1) | |||
| ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1") | |||
| ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a") | |||
| ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(121) | |||
| ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | |||
| } | |||
| func GetGrampusConfig() { | |||
| @@ -1436,7 +1521,12 @@ func GetGrampusConfig() { | |||
| Grampus.UserName = sec.Key("USERNAME").MustString("") | |||
| Grampus.Password = sec.Key("PASSWORD").MustString("") | |||
| Grampus.SpecialPools = sec.Key("SPECIAL_POOL").MustString("") | |||
| Grampus.C2NetSequence = sec.Key("C2NET_SEQUENCE").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\"}]}") | |||
| if Grampus.C2NetSequence != "" { | |||
| if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil { | |||
| log.Error("Unmarshal(C2NetSequence) failed:%v", err) | |||
| } | |||
| } | |||
| } | |||
| func SetRadarMapConfig() { | |||
| @@ -179,31 +179,39 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel | |||
| output, err := core.ListObjects(bucket, Prefix, "", "", 1000) | |||
| fileInfos := make([]FileInfo, 0) | |||
| prefixLen := len(Prefix) | |||
| fileMap := make(map[string]bool, 0) | |||
| if err == nil { | |||
| for _, val := range output.Contents { | |||
| log.Info("val key=" + val.Key) | |||
| var isDir bool | |||
| var fileName string | |||
| if val.Key == Prefix { | |||
| continue | |||
| } | |||
| if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||
| fileName = val.Key[prefixLen:] | |||
| log.Info("fileName =" + fileName) | |||
| files := strings.Split(fileName, "/") | |||
| if fileMap[files[0]] { | |||
| continue | |||
| } else { | |||
| fileMap[files[0]] = true | |||
| } | |||
| if strings.HasSuffix(val.Key, "/") { | |||
| ParenDir := relativePath | |||
| fileName = files[0] | |||
| if len(files) > 1 { | |||
| isDir = true | |||
| fileName = val.Key[prefixLen : len(val.Key)-1] | |||
| relativePath += val.Key[prefixLen:] | |||
| ParenDir += fileName + "/" | |||
| } else { | |||
| isDir = false | |||
| fileName = val.Key[prefixLen:] | |||
| } | |||
| fileInfo := FileInfo{ | |||
| ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||
| FileName: fileName, | |||
| Size: val.Size, | |||
| IsDir: isDir, | |||
| ParenDir: relativePath, | |||
| ParenDir: ParenDir, | |||
| } | |||
| fileInfos = append(fileInfos, fileInfo) | |||
| } | |||
| @@ -217,6 +225,49 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel | |||
| } | |||
| func MinioGetFilesSize(bucketName string, Files []string) int64 { | |||
| _, core, err := getClients() | |||
| var fileTotalSize int64 | |||
| fileTotalSize = 0 | |||
| if err != nil { | |||
| log.Error("getClients failed:", err.Error()) | |||
| return fileTotalSize | |||
| } | |||
| for _, file := range Files { | |||
| log.Info("file=" + file) | |||
| meta, err := core.StatObject(bucketName, file, miniov6.StatObjectOptions{}) | |||
| if err != nil { | |||
| log.Info("Get file error:" + err.Error()) | |||
| } | |||
| fileTotalSize += meta.Size | |||
| } | |||
| return fileTotalSize | |||
| } | |||
| func MinioCopyFiles(bucketName string, srcPath string, destPath string, Files []string) (int64, error) { | |||
| _, core, err := getClients() | |||
| var fileTotalSize int64 | |||
| fileTotalSize = 0 | |||
| if err != nil { | |||
| log.Error("getClients failed:", err.Error()) | |||
| return fileTotalSize, err | |||
| } | |||
| for _, file := range Files { | |||
| srcObjectName := srcPath + file | |||
| destObjectName := destPath + file | |||
| log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName) | |||
| meta, err := core.StatObject(bucketName, srcObjectName, miniov6.StatObjectOptions{}) | |||
| if err != nil { | |||
| log.Info("Get file error:" + err.Error()) | |||
| } | |||
| core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, meta.UserMetadata) | |||
| fileTotalSize += meta.Size | |||
| } | |||
| return fileTotalSize, nil | |||
| } | |||
| func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { | |||
| _, core, err := getClients() | |||
| var fileTotalSize int64 | |||
| @@ -264,7 +264,47 @@ func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) { | |||
| } | |||
| } | |||
| func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) { | |||
| func ObsGetFilesSize(srcBucket string, Files []string) int64 { | |||
| var fileTotalSize int64 | |||
| for _, file := range Files { | |||
| log.Info("file=" + file) | |||
| out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{ | |||
| Bucket: srcBucket, | |||
| Key: file, | |||
| }) | |||
| if err != nil { | |||
| log.Info("Get File error, error=" + err.Error()) | |||
| continue | |||
| } | |||
| fileTotalSize += out.ContentLength | |||
| } | |||
| return fileTotalSize | |||
| } | |||
| func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string, Files []string) (int64, error) { | |||
| var fileTotalSize int64 | |||
| for _, file := range Files { | |||
| srcKey := srcPath + file | |||
| destKey := destPath + file | |||
| log.Info("srcKey=" + srcKey + " destKey=" + destKey) | |||
| out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{ | |||
| Bucket: srcBucket, | |||
| Key: srcKey, | |||
| }) | |||
| if err != nil { | |||
| log.Info("Get File error, error=" + err.Error()) | |||
| continue | |||
| } | |||
| obsCopyFile(srcBucket, srcKey, destBucket, destKey) | |||
| fileTotalSize += out.ContentLength | |||
| } | |||
| return fileTotalSize, nil | |||
| } | |||
| func ObsCopyAllFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) { | |||
| input := &obs.ListObjectsInput{} | |||
| input.Bucket = srcBucket | |||
| // 设置每页100个对象 | |||
| @@ -330,6 +370,7 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative | |||
| output, err := ObsCli.ListObjects(input) | |||
| fileInfos := make([]FileInfo, 0) | |||
| prefixLen := len(input.Prefix) | |||
| fileMap := make(map[string]bool, 0) | |||
| if err == nil { | |||
| for _, val := range output.Contents { | |||
| log.Info("val key=" + val.Key) | |||
| @@ -338,23 +379,28 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative | |||
| if val.Key == input.Prefix { | |||
| continue | |||
| } | |||
| if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||
| fileName = val.Key[prefixLen:] | |||
| log.Info("fileName =" + fileName) | |||
| files := strings.Split(fileName, "/") | |||
| if fileMap[files[0]] { | |||
| continue | |||
| } else { | |||
| fileMap[files[0]] = true | |||
| } | |||
| if strings.HasSuffix(val.Key, "/") { | |||
| ParenDir := relativePath | |||
| fileName = files[0] | |||
| if len(files) > 1 { | |||
| isDir = true | |||
| fileName = val.Key[prefixLen : len(val.Key)-1] | |||
| relativePath += val.Key[prefixLen:] | |||
| ParenDir += fileName + "/" | |||
| } else { | |||
| isDir = false | |||
| fileName = val.Key[prefixLen:] | |||
| } | |||
| fileInfo := FileInfo{ | |||
| ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||
| FileName: fileName, | |||
| Size: val.Size, | |||
| IsDir: isDir, | |||
| ParenDir: relativePath, | |||
| ParenDir: ParenDir, | |||
| } | |||
| fileInfos = append(fileInfos, fileInfo) | |||
| } | |||
| @@ -424,6 +470,7 @@ func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]Fil | |||
| input := &obs.ListObjectsInput{} | |||
| input.Bucket = setting.Bucket | |||
| input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/") | |||
| log.Info("bucket=" + input.Bucket + " Prefix=" + input.Prefix) | |||
| strPrefix := strings.Split(input.Prefix, "/") | |||
| output, err := ObsCli.ListObjects(input) | |||
| fileInfos := make([]FileInfo, 0) | |||
| @@ -575,6 +622,8 @@ func GetObsLogFileName(prefix string) (string, error) { | |||
| log.Error("PutObject failed:", err.Error()) | |||
| return "", err | |||
| } | |||
| if output == nil || len(output.Contents) == 0 { | |||
| return "", errors.New("obs log files not exist") | |||
| } | |||
| return output.Contents[0].Key, nil | |||
| } | |||
| @@ -97,23 +97,24 @@ func NewFuncMap() []template.FuncMap { | |||
| "AllowedReactions": func() []string { | |||
| return setting.UI.Reactions | |||
| }, | |||
| "AvatarLink": models.AvatarLink, | |||
| "Safe": Safe, | |||
| "SafeJS": SafeJS, | |||
| "Str2html": Str2html, | |||
| "subOne": subOne, | |||
| "TimeSince": timeutil.TimeSince, | |||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | |||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||
| "AttachmentResourceType": dataset.GetResourceType, | |||
| "AttachmentStatus": dataset.GetStatusText, | |||
| "TimeSinceUnixShort": timeutil.TimeSinceUnixShort, | |||
| "RawTimeSince": timeutil.RawTimeSince, | |||
| "FileSize": base.FileSize, | |||
| "PrettyNumber": base.PrettyNumber, | |||
| "Subtract": base.Subtract, | |||
| "EntryIcon": base.EntryIcon, | |||
| "MigrationIcon": MigrationIcon, | |||
| "AvatarLink": models.AvatarLink, | |||
| "Safe": Safe, | |||
| "SafeJS": SafeJS, | |||
| "Str2html": Str2html, | |||
| "subOne": subOne, | |||
| "TimeSince": timeutil.TimeSince, | |||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | |||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||
| "AttachmentResourceType": dataset.GetResourceType, | |||
| "AttachmentStatus": dataset.GetStatusText, | |||
| "IsShowDataSetOfCurrentRepo": dataset.IsShowDataSetOfCurrentRepo, | |||
| "TimeSinceUnixShort": timeutil.TimeSinceUnixShort, | |||
| "RawTimeSince": timeutil.RawTimeSince, | |||
| "FileSize": base.FileSize, | |||
| "PrettyNumber": base.PrettyNumber, | |||
| "Subtract": base.Subtract, | |||
| "EntryIcon": base.EntryIcon, | |||
| "MigrationIcon": MigrationIcon, | |||
| "Add": func(a, b int) int { | |||
| return a + b | |||
| }, | |||
| @@ -357,13 +358,15 @@ func NewTextFuncMap() []texttmpl.FuncMap { | |||
| "AppDomain": func() string { | |||
| return setting.Domain | |||
| }, | |||
| "TimeSince": timeutil.TimeSince, | |||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | |||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||
| "TimeSinceUnixShort": timeutil.TimeSinceUnixShort, | |||
| "RawTimeSince": timeutil.RawTimeSince, | |||
| "AttachmentResourceType": dataset.GetResourceType, | |||
| "AttachmentStatus": dataset.GetStatusText, | |||
| "TimeSince": timeutil.TimeSince, | |||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | |||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||
| "TimeSinceUnixShort": timeutil.TimeSinceUnixShort, | |||
| "RawTimeSince": timeutil.RawTimeSince, | |||
| "AttachmentResourceType": dataset.GetResourceType, | |||
| "AttachmentStatus": dataset.GetStatusText, | |||
| "IsShowDataSetOfCurrentRepo": dataset.IsShowDataSetOfCurrentRepo, | |||
| "DateFmtLong": func(t time.Time) string { | |||
| return t.Format(time.RFC1123Z) | |||
| }, | |||
| @@ -99,6 +99,7 @@ error500= Sorry, the site has encountered some problems, we are trying to <stron | |||
| [error] | |||
| occurred = An error has occurred | |||
| report_message = An error has occurred | |||
| no_right=You have no right to do the operation. | |||
| [install] | |||
| install = Installation | |||
| @@ -253,13 +254,16 @@ page_dev_env_desc2_title=Model Management and Sharing | |||
| page_dev_env_desc2_desc=Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. | |||
| page_dev_env_desc3_title=Once Configuration, Multiple Reuse | |||
| page_dev_env_desc3_desc=Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. | |||
| page_dev_yunlao=PengCheng Cloudbrain Open Source Collaboration | |||
| page_dev_yunlao_desc1=The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks. | |||
| page_dev_yunlao_desc2=Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors. | |||
| page_dev_yunlao_desc3=Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments. | |||
| page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately. | |||
| page_dev_yunlao=OpenI AI Collaboration Platform | |||
| page_dev_yunlao_desc1=OpenI AI collaboration platform has cooperated with Pengcheng cloud brain and China computing power network (C²NET) can be used to complete AI development tasks by using the rich computing resources of Pengcheng cloud brain and China computing network. | |||
| page_dev_yunlao_desc2=Pengcheng CloudBrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure consists of GPU servers equipped with NVIDIA Tesla V100 and A100, and Atlas 900 AI clusters equipped with Kunpeng and shengteng processors. | |||
| page_dev_yunlao_desc3=China computing power network (C²NET) phase I can realize high-speed network interconnection between different artificial intelligence computing centers, and realize reasonable scheduling of computing power and flexible allocation of resources. At present, 11 intelligent computing centers have been connected, and the total scale of computing power is 1924p OPS@FP16. OpenI AI collaboration platform has been connected to Pengcheng Cloud Computing Institute, Chengdu Intelligent Computing Center, Zhongyuan Intelligent Computing Center, Hefei brain and other nodes. | |||
| page_dev_yunlao_desc4=Developers can freely select the corresponding computing resources according to the use needs, and can test the adaptability, performance, stability, etc. of the model in different hardware environments. | |||
| page_dev_yunlao_desc5=If your model requires more computing resources, you can also apply for it separately. | |||
| page_dev_yunlao_apply=Apply Separately | |||
| c2net_title=China Computing Network | |||
| c2net_desc=The artificial intelligence computing power network promotion alliance has access to 11 intelligent computing centers, with a total scale of 1924p. | |||
| c2net_center=Center | |||
| search=Search | |||
| search_repo=Repository | |||
| search_dataset=DataSet | |||
| @@ -560,6 +564,7 @@ static.CollectImage=Collect Image Count | |||
| static.CollectedImage=Collected Image Count | |||
| static.RecommendImage=Recommended Image Count | |||
| static.email=Email | |||
| static.phone=Phone | |||
| static.location=Location | |||
| static.all=All | |||
| static.public.user_business_analysis_current_month=Current_Month | |||
| @@ -821,6 +826,9 @@ title_format_err=Name can only contain number,letter,'-','_' or '.', and can be | |||
| description = Description | |||
| description_format_err=Description's length can be up to %s characters long. | |||
| create_dataset = Create Dataset | |||
| download_url=Download Url | |||
| download_oper=Operation | |||
| download_copy=Copy URL | |||
| create_dataset_fail=Failed to create dataset. | |||
| query_dataset_fail=Failed to query dataset. | |||
| edit_attachment_fail=Failed to update description. | |||
| @@ -831,6 +839,8 @@ category = Category | |||
| no_category = No Category | |||
| task = Task | |||
| no_task = No Task | |||
| reference_dataset_fail=Failed to reference dataset, please try again later. | |||
| cancel_reference_dataset_fail=Failed to cancel reference dataset, please try again later. | |||
| license = License | |||
| no_license = No License | |||
| file = Dataset File | |||
| @@ -914,9 +924,10 @@ select_task = Select Research Direction/Application Area | |||
| dataset_name_tooltips = Please enter letters, numbers, _ and - up to 100 characters. | |||
| dataset_no_create = No dataset has been created yet | |||
| dataset_explain = Dataset: CloudBrain I provides CPU/GPU resources, Cloudbrain II provides Ascend NPU resources, and the data set used for debugging also needs to be uploaded to the corresponding environment; | |||
| dataset_instructions_for_use = Instructions for use: You can refer to Qizhi AI Collaboration Platform | |||
| dataset_camp_course = Newcomer Training Camp Course; | |||
| dataset_instructions_for_use = Instructions for use: You can refer to Openi AI Collaboration Platform | |||
| dataset_camp_course = Newcomer Training Camp Course; | |||
| dataset_upload = Upload | |||
| dataset_upload_status= Upload Status | |||
| dataset_file_name = File Name | |||
| dataset_available_clusters = Available Clusters | |||
| dataset_upload_time = Upload Time | |||
| @@ -943,6 +954,13 @@ unzip_failed=Unzip Failed | |||
| unzip_stared=Unzipping | |||
| unzip_status=Unzip Status | |||
| collection_num=Collection Nums | |||
| current_dataset=Current Dataset | |||
| linked_dataset=Linked Dataset | |||
| unfavorite=Unlike | |||
| favorite=Like | |||
| disassociate=Disassociate | |||
| benchmark_dataset_tip=Note: first use the dataset function to upload the model, and then select the model from the dataset list. | |||
| [repo] | |||
| owner = Owner | |||
| repo_name = Repository Name | |||
| @@ -1007,7 +1025,7 @@ cloudbrain.time.starttime=Start run time | |||
| cloudbrain.time.endtime=End run time | |||
| cloudbrain.datasetdownload=Dataset download url | |||
| model_manager = Model | |||
| model_noright=No right | |||
| model_noright=You have no right to do the operation. | |||
| model_rename=Duplicate model name, please modify model name. | |||
| date=Date | |||
| @@ -1037,8 +1055,9 @@ image_delete_fail=Failed to delete image, please try again later. | |||
| image_overwrite=You had submitted the same name image before, are you sure to overwrite the original image? | |||
| download=Download | |||
| score=Score | |||
| wait_count_start = There are currently | |||
| wait_count_end = tasks queued | |||
| file_limit_100 = Display up to 100 files or folders in a single directory | |||
| images.name = Image Tag | |||
| images.name_placerholder = Please enter the image name | |||
| image.label_tooltips = Example Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 | |||
| @@ -1072,6 +1091,7 @@ cloudbrain_operate = Operate | |||
| cloudbrain_status_createtime = Status/Createtime | |||
| cloudbrain_status_runtime = Running Time | |||
| cloudbrain_jobname_err=Name must start with a lowercase letter or number,can include lowercase letter,number,_ and -,can not end with _, and can be up to 36 characters long. | |||
| cloudbrain_bootfile_err=The bootfile does not exist in the repository | |||
| cloudbrain_query_fail=Failed to query cloudbrain information. | |||
| cloudbrain.mirror_tag = Mirror Tag | |||
| cloudbrain.mirror_description = Mirror Description | |||
| @@ -1096,7 +1116,11 @@ modelarts.status=Status | |||
| modelarts.createtime=CreateTime | |||
| modelarts.version_nums = Version Nums | |||
| modelarts.version = Version | |||
| modelarts.computing_resources=compute Resources | |||
| modelarts.computing_resources=Compute Resources | |||
| modelarts.cluster.computing_resources=Cluster/Compute Resources | |||
| modelarts.ai_center=Ai Center | |||
| modelarts.card_type=Card Type | |||
| modelarts.cluster=Cluster | |||
| modelarts.notebook=Debug Task | |||
| modelarts.train_job=Train Task | |||
| modelarts.train_job.new_debug= New Debug Task | |||
| @@ -1186,7 +1210,7 @@ modelarts.infer_job_model_file = Model File | |||
| modelarts.infer_job = Inference Job | |||
| modelarts.infer_job.model_version = Model/Version | |||
| modelarts.infer_job.select_model = Select Model | |||
| modelarts.infer_job.boot_file_helper=The startup file is the entry file for your program execution and must end in.py.Such as inference.py, main.py, example/inference. Py, case/main.py. | |||
| modelarts.infer_job.boot_file_helper=The startup file is the entry file for your program execution and must end in.py.Such as inference.py, main.py, example/inference.py, case/main.py. | |||
| modelarts.infer_job.tooltip = The model has been deleted and cannot be viewed. | |||
| modelarts.download_log=Download log file | |||
| @@ -1198,7 +1222,7 @@ model_Evaluation_not_created = Model evaluation has not been created | |||
| repo_not_initialized = Code version: You have not initialized the code repository, please <a href="%s"> initialized </a> first ; | |||
| debug_task_running_limit =Running time: no more than 4 hours, it will automatically stop if it exceeds 4 hours; | |||
| dataset_desc = Dataset: Cloud Brain 1 provides CPU/GPU,Cloud Brain 2 provides Ascend NPU.And dataset also needs to be uploaded to the corresponding environment; | |||
| platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning">Xiaobai training camp </a> course of Qizhi AI collaboration platform. | |||
| platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning">Xiaobai training camp </a> course of Openi AI collaboration platform. | |||
| model_not_exist = Model file: You do not have a model file yet, please generate and <a href="%s/modelmanage/show_model">export the model</a> through the <a href="%s/modelarts/train-job">training task</a> first ; | |||
| benchmark_leaderboards = Benchmark leaderboards | |||
| @@ -1209,7 +1233,7 @@ model.manage.version = Version | |||
| model.manage.label = Label | |||
| model.manage.size = Size | |||
| model.manage.create_time = Create Time | |||
| model.manage.Description = Description | |||
| model.manage.description = Description | |||
| model.manage.Accuracy = Accuracy | |||
| model.manage.F1 = F1 | |||
| model.manage.Precision = Precision | |||
| @@ -1217,6 +1241,57 @@ model.manage.Recall = Recall | |||
| model.manage.sava_model = Sava Model | |||
| model.manage.model_manage = ModelManage | |||
| model.manage.model_accuracy = Model Accuracy | |||
| model.convert=Model Transformation | |||
| model.list=Model List | |||
| model.manage.create_new_convert_task=Create Model Transformation Task | |||
| model.manage.notcreatemodel=No model has been created. | |||
| model.manage.init1=Code version: You have not initialized the code repository, please | |||
| model.manage.init2=initialized first ; | |||
| model.manage.createtrainjob_tip=Training task: you haven't created a training task, please create it first | |||
| model.manage.createtrainjob=Training task | |||
| model.manage.delete=Delete Model | |||
| model.manage.delete_confirm=Are you sure to delete this model? Once this model is deleted, it cannot be restored. | |||
| model.manage.select.trainjob=Select train task | |||
| model.manage.select.version=Select version | |||
| model.manage.engine=Model engine | |||
| model.manage.select.engine=Select model engine | |||
| model.manage.modelfile=Model file | |||
| model.manage.modellabel=Model label | |||
| model.manage.modeldesc=Model description | |||
| model.manage.baseinfo=Base Information | |||
| modelconvert.notcreate=No model conversion task has been created. | |||
| modelconvert.importfirst1=Please import first | |||
| modelconvert.importfirst2=download model | |||
| modelconvert.importfirst3=, then converts it. | |||
| modelconvert.download=Download | |||
| modelconvert.taskname=Task name | |||
| modelconvert.modelname=Model name | |||
| modelconvert.selectmodel=Select model | |||
| modelconvert.modelversion=Model version | |||
| modelconvert.selectversion=Select version | |||
| modelconvert.selectmodelfile=Select model file | |||
| modelconvert.taskstatus=Status | |||
| modelconvert.srcengine=Source model engine | |||
| modelconvert.outputformat=Output format | |||
| modelconvert.createtime=Created time | |||
| modelconvert.inputdataformat=Input data format | |||
| modelconvert.inputshape=Input tensor shape | |||
| modelconvert.inputshapetip=For example: 1,1,32,32, corresponding to the input data format. | |||
| modelconvert.netoutputdata=Network output data type | |||
| modelconvert.taskdesc=Task description | |||
| modelconvert.newtask=New | |||
| modelconvert.createtask=Create model transformation task | |||
| modelconvert.taskurlname=Model transformation task | |||
| log_scroll_start=Scroll to top | |||
| log_scroll_end=Scroll to bottom | |||
| modelconvert.tasknameempty=Please enter a task name. | |||
| modelconvert.inputshapeerror=Format input error, please input such as: 1,1,32,32, corresponding to the input data format. | |||
| modelconvert.manage.create_error1=A model transformation task with the same name already exists. | |||
| modelconvert.manage.create_error2=Only one running model transformation task can be created. | |||
| modelconvert.manage.model_not_exist=The model does not exist. | |||
| modelconvert.manage.no_operate_right=You have no right to do the operation. | |||
| grampus.train_job.ai_center = AI Center | |||
| grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 | |||
| @@ -2309,7 +2384,7 @@ topic.count_prompt = You can not select more than 25 topics | |||
| topic.format_prompt = Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long. | |||
| imagetopic.format_prompt = Topics can be up to 35 characters long. | |||
| use_repo_agreement=I promise that the content of this warehouse does not violate any national laws and regulations. During the use of the warehouse, I will abide by the OpenI community management regulations and platform usage rules, and will not conduct malicious attacks, mining, or any other illegal or disruptive platform order. Information release and related behaviors. For more information please refer to | |||
| openi_use_agreement=OpenI Qizhi Community Platform Use Agreement. | |||
| openi_use_agreement=OpenI Openi Community Platform Use Agreement. | |||
| [org] | |||
| org_name_holder = Organization Name | |||
| org_full_name_holder = Organization Full Name | |||
| @@ -2950,6 +3025,13 @@ notices.desc = Description | |||
| notices.op = Op. | |||
| notices.delete_success = The system notices have been deleted. | |||
| user_management = User Management | |||
| resource_management = Resource Management | |||
| resource_pool = Resource Pool(queue) | |||
| resource_price = Resource Price | |||
| application_scenario = Application Scenario | |||
| system_configuration = System Configuration | |||
| [action] | |||
| create_repo = created repository <a href="%s">%s</a> | |||
| rename_repo = renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a> | |||
| @@ -2976,15 +3058,15 @@ mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href= | |||
| approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| upload_dataset=`upload dataset <a href="%s/datasets">%s</a>` | |||
| task_gpudebugjob=`created CPU/GPU type debugging task<a href="%s/cloudbrain/%s">%s</a>` | |||
| task_gpudebugjob=`created CPU/GPU type debugging task <a href="%s/cloudbrain/%s">%s</a>` | |||
| task_npudebugjob=`created NPU type debugging task <a href="%s/modelarts/notebook/%s">%s</a>` | |||
| task_nputrainjob=`created NPU training task<a href="%s/modelarts/train-job/%s">%s</a>` | |||
| task_nputrainjob=`created NPU training task <a href="%s/modelarts/train-job/%s">%s</a>` | |||
| task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>` | |||
| task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>` | |||
| task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>` | |||
| task_gputrainjob=`created CPU/GPU training task<a href="%s/cloudbrain/train-job/%s">%s</a>` | |||
| task_c2netnputrainjob=`created NPU training task<a href="%s/grampus/train-job/%s">%s</a>` | |||
| task_c2netgputrainjob=`created CPU/GPU training task<a href="%s/grampus/train-job/%s">%s</a>` | |||
| task_gputrainjob=`created CPU/GPU training task <a href="%s/cloudbrain/train-job/%s">%s</a>` | |||
| task_c2netnputrainjob=`created NPU training task <a href="%s/grampus/train-job/%s">%s</a>` | |||
| task_c2netgputrainjob=`created CPU/GPU training task <a href="%s/grampus/train-job/%s">%s</a>` | |||
| [tool] | |||
| ago = %s ago | |||
| @@ -3073,9 +3155,13 @@ Platform_Tutorial = Tutorial | |||
| foot.advice_feedback = Feedback | |||
| [cloudbrain] | |||
| all_resource_cluster=All Cluster | |||
| all_ai_center=All Computing NET | |||
| resource_cluster = Resource Cluster | |||
| resource_cluster_openi = OpenI Resource Cluster | |||
| resource_cluster_c2net = China Computing NET | |||
| resource_cluster_openi_simple = OpenI | |||
| resource_cluster_c2net_simple = C²NET | |||
| compute_resource = Computing resources | |||
| task_name = Task name | |||
| task_type = Task type | |||
| @@ -3096,13 +3182,17 @@ select_dataset = select dataset | |||
| specification = specification | |||
| select_specification = select specification | |||
| description = description | |||
| wrong_specification=You cannot use this specification, please choose another item. | |||
| resource_use=Resource Occupancy | |||
| job_name_rule = Please enter letters, numbers, _ and - up to 64 characters and cannot end with a dash (-). | |||
| dataset_path_rule = The dataset location is stored in the environment variable data_url, and the training output path is stored in the environment variable train_url. | |||
| train_dataset_path_rule = The dataset location is stored in the environment variable <strong style="color:#010101">data_url</strong>, and the output path is stored in the environment variable <strong style="color:#010101">train_url</strong>. | |||
| infer_dataset_path_rule = The dataset location is stored in the environment variable <strong style="color:#010101">data_url</strong>, and the output path is stored in the environment variable <strong style="color:#010101">result_url</strong>. | |||
| view_sample = View sample | |||
| inference_output_path_rule = The inference output path is stored in the environment variable result_url. | |||
| model_file_path_rule=The model file location is stored in the environment variable ckpt_url | |||
| model_file_postfix_rule = The supported format of the model file is [ckpt, pb, h5, json, pkl, pth, t7, pdparams, onnx, pbtxt, keras, mlmodel, cfg, pt] | |||
| model_convert_postfix_rule = The supported format of the model file is [.pth, .pkl, .onnx, .mindir, .ckpt, .pb] | |||
| delete_task = Delete task | |||
| task_delete_confirm = Are you sure you want to delete this task? Once this task is deleted, it cannot be recovered. | |||
| operate_confirm = confirm | |||
| @@ -3112,6 +3202,9 @@ gpu_num = GPU | |||
| cpu_num = CPU | |||
| memory = Memory | |||
| shared_memory = Shared Memory | |||
| gpu_memory = GPU Memory | |||
| free = Free | |||
| point_hr = Point/hr | |||
| DEBUG = DEBUG | |||
| @@ -3122,7 +3215,16 @@ INFERENCE = INFERENCE | |||
| BENCHMARK = BENCHMARK | |||
| brain_area = Brain Area | |||
| Delete_failed=Fail to delete the job, please try again later. | |||
| Not_Stopped=The job is not stopped, can not be deleted. | |||
| Already_stopped=The job is already stopped. | |||
| Stopped_failed=Fail to stop the job, please try again later. | |||
| Stopped_success_update_status_fail=Succeed in stopping th job, but failed to update the job status and duration time. | |||
| load_code_failed=Fail to load code, please check if the right branch is selected. | |||
| error.dataset_select = dataset select error:the count exceed the limit or has same name | |||
| new_train_gpu_tooltips = The code is storaged in <strong style="color:#010101">%s</strong>, the dataset is storaged in <strong style="color:#010101">%s</strong>, and please put your model into <strong style="color:#010101">%s</strong> then you can download it online | |||
| new_infer_gpu_tooltips = The dataset is stored in <strong style="color:#010101">%s</strong>, the model file is stored in <strong style="color:#010101">%s</strong>, please store the inference output in <strong style="color:#010101">%s</strong> for subsequent downloads. | |||
| [points] | |||
| points = points | |||
| @@ -100,6 +100,7 @@ error500=抱歉,站点遇到一些问题,我们正尝试<strong>修复网页 | |||
| [error] | |||
| occurred=发生错误 | |||
| report_message=发生错误 | |||
| no_right=您没有权限执行本操作。 | |||
| [install] | |||
| install=安装页面 | |||
| @@ -255,13 +256,16 @@ page_dev_env_desc2_title=模型管理与共享 | |||
| page_dev_env_desc2_desc=将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈 | |||
| page_dev_env_desc3_title=一次配置,多次使用 | |||
| page_dev_env_desc3_desc=提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境 | |||
| page_dev_yunlao=鹏城云脑开源协同 | |||
| page_dev_yunlao_desc1=平台已经与鹏城云脑打通,可以利用鹏城云脑的丰富算力资源,完成AI开发任务 | |||
| page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 的GPU服务器和搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成 | |||
| page_dev_yunlao_desc3=开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等 | |||
| page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请 | |||
| page_dev_yunlao=启智AI协作平台 | |||
| page_dev_yunlao_desc1=启智AI协作平台已经与鹏城云脑、中国算力网(C²NET)一期打通,可以利用鹏城云脑和中国算力网的丰富算力资源,完成AI开发任务。 | |||
| page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 和A100 的GPU服务器,以及搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成。 | |||
| page_dev_yunlao_desc3=中国算力网(C²NET)一期可实现不同人工智能计算中心之间高速网络互联,实现算力合理调度和资源弹性分配。目前已接入11家智算中心,算力总规模1924P OPS@FP16。启智AI协作平台已接入其中的鹏城云计算所、成都智算中心、中原智算中心、合肥类脑等节点。 | |||
| page_dev_yunlao_desc4=开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等。 | |||
| page_dev_yunlao_desc5=如果您的模型需要更多的计算资源,也可以单独申请。 | |||
| page_dev_yunlao_apply=单独申请 | |||
| c2net_title=智算网络 | |||
| c2net_desc=人工智能算力网络推进联盟已接入11家智算中心,算力总规模1924P | |||
| c2net_center=中心 | |||
| search=搜索 | |||
| search_repo=项目 | |||
| search_dataset=数据集 | |||
| @@ -565,6 +569,7 @@ static.CollectImage=收藏镜像数 | |||
| static.CollectedImage=被收藏镜像数 | |||
| static.RecommendImage=被推荐镜像数 | |||
| static.email=Email | |||
| static.phone=电话 | |||
| static.location=所在地区 | |||
| static.all=所有 | |||
| static.public.user_business_analysis_current_month=本月 | |||
| @@ -830,6 +835,12 @@ create_dataset_fail=创建数据集失败。 | |||
| query_dataset_fail=查询数据集失败。 | |||
| edit_attachment_fail=修改描述失败。 | |||
| reference_dataset_fail=关联数据集失败,请稍后再试。 | |||
| cancel_reference_dataset_fail=取消关联数据集失败,请稍后再试。 | |||
| download_url=数据集下载地址 | |||
| download_copy=复制链接 | |||
| download_oper=操作 | |||
| show_dataset=数据集 | |||
| edit_dataset=编辑数据集 | |||
| update_dataset=更新数据集 | |||
| @@ -922,6 +933,7 @@ dataset_explain = 数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Asc | |||
| dataset_instructions_for_use = 使用说明:可以参考启智AI协作平台 | |||
| dataset_camp_course = 小白训练营课程 | |||
| dataset_upload = 上传 | |||
| dataset_upload_status = 上传状态 | |||
| dataset_file_name = 文件名称 | |||
| dataset_available_clusters = 可用集群 | |||
| dataset_upload_time = 上传时间 | |||
| @@ -948,6 +960,13 @@ unzip_failed=解压失败 | |||
| unzip_stared=解压中 | |||
| unzip_status=解压状态 | |||
| collection_num=收藏数量 | |||
| current_dataset=当前数据集 | |||
| linked_dataset=关联数据集 | |||
| unfavorite=取消收藏 | |||
| favorite=收藏 | |||
| disassociate=取消关联 | |||
| benchmark_dataset_tip=说明:先使用数据集功能上传模型,然后从数据集列表选模型。 | |||
| [repo] | |||
| owner=拥有者 | |||
| repo_name=项目名称 | |||
| @@ -1006,7 +1025,7 @@ datasets.desc=数据集功能 | |||
| cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||
| model_manager = 模型 | |||
| model_noright=无权限操作 | |||
| model_noright=您没有操作权限。 | |||
| model_rename=模型名称重复,请修改模型名称 | |||
| @@ -1037,8 +1056,9 @@ image_delete_fail=删除镜像失败,请稍后再试。 | |||
| image_overwrite=您已经提交过相同名称的镜像,您确定要覆盖原来提交的镜像吗? | |||
| download=模型下载 | |||
| score=评分 | |||
| wait_count_start = 当前有 | |||
| wait_count_end = 个任务正在排队 | |||
| file_limit_100 = 单目录下最多显示100个文件或文件夹 | |||
| images.name = 镜像Tag | |||
| images.name_placerholder = 请输入镜像Tag | |||
| image.label_tooltips = 如Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 | |||
| @@ -1075,6 +1095,7 @@ cloudbrain_operate=操作 | |||
| cloudbrain_status_createtime=状态/创建时间 | |||
| cloudbrain_status_runtime = 运行时长 | |||
| cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | |||
| cloudbrain_bootfile_err=仓库中不存在启动文件 | |||
| cloudbrain_query_fail=查询云脑任务失败。 | |||
| cloudbrain.mirror_tag = 镜像标签 | |||
| cloudbrain.mirror_description = 镜像描述 | |||
| @@ -1107,6 +1128,10 @@ modelarts.deletetime=删除时间 | |||
| modelarts.version_nums=版本数 | |||
| modelarts.version=版本 | |||
| modelarts.computing_resources=计算资源 | |||
| modelarts.cluster.computing_resources=集群/计算资源 | |||
| modelarts.ai_center=智算中心 | |||
| modelarts.card_type=卡类型 | |||
| modelarts.cluster=集群 | |||
| modelarts.notebook=调试任务 | |||
| modelarts.train_job=训练任务 | |||
| modelarts.train_job.new_debug=新建调试任务 | |||
| @@ -1229,6 +1254,58 @@ model.manage.Recall = 召回率 | |||
| model.manage.sava_model = 保存模型 | |||
| model.manage.model_manage = 模型管理 | |||
| model.manage.model_accuracy = 模型精度 | |||
| model.convert=模型转换任务 | |||
| model.list=模型列表 | |||
| model.manage.create_new_convert_task=创建模型转换任务 | |||
| model.manage.notcreatemodel=未创建过模型 | |||
| model.manage.init1=代码版本:您还没有初始化代码仓库,请先 | |||
| model.manage.init2=创建代码版本; | |||
| model.manage.createtrainjob_tip=训练任务:您还没创建过训练任务,请先创建 | |||
| model.manage.createtrainjob=训练任务 | |||
| model.manage.delete=删除模型 | |||
| model.manage.delete_confirm=你确认删除该模型么?此模型一旦删除不可恢复。 | |||
| model.manage.select.trainjob=选择训练任务 | |||
| model.manage.select.version=选择版本 | |||
| model.manage.engine=模型框架 | |||
| model.manage.select.engine=选择模型框架 | |||
| model.manage.modelfile=模型文件 | |||
| model.manage.modellabel=模型标签 | |||
| model.manage.modeldesc=模型描述 | |||
| model.manage.baseinfo=基本信息 | |||
| modelconvert.notcreate=未创建过模型转换任务 | |||
| modelconvert.importfirst1=请您先导入 | |||
| modelconvert.importfirst2=模型下载 | |||
| modelconvert.importfirst3=,然后再对其进行转换。 | |||
| modelconvert.download=下载 | |||
| modelconvert.taskname=任务名称 | |||
| modelconvert.modelname=模型名称 | |||
| modelconvert.selectmodel=选择模型 | |||
| modelconvert.modelversion=模型版本 | |||
| modelconvert.selectversion=选择版本 | |||
| modelconvert.selectmodelfile=选择模型文件 | |||
| modelconvert.taskstatus=状态 | |||
| modelconvert.srcengine=原模型框架 | |||
| modelconvert.outputformat=转换后格式 | |||
| modelconvert.createtime=创建时间 | |||
| modelconvert.inputdataformat=输入数据格式 | |||
| modelconvert.inputshape=输入张量形状 | |||
| modelconvert.inputshapetip=如:1,1,32,32,与输入数据格式对应。 | |||
| modelconvert.netoutputdata=网络输出数据类型 | |||
| modelconvert.taskdesc=任务描述 | |||
| modelconvert.newtask=新建任务 | |||
| modelconvert.createtask=创建模型转换任务 | |||
| modelconvert.taskurlname=模型转换任务 | |||
| log_scroll_start=滚动到顶部 | |||
| log_scroll_end=滚动到底部 | |||
| modelconvert.tasknameempty=请输入任务名称。 | |||
| modelconvert.inputshapeerror=格式输入错误,请输入如:1,1,32,32,与输入数据格式对应。 | |||
| modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。 | |||
| modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。 | |||
| modelconvert.manage.model_not_exist=选择的模型不存在。 | |||
| modelconvert.manage.no_operate_right=您没有操作权限。 | |||
| grampus.train_job.ai_center=智算中心 | |||
| grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 | |||
| @@ -2964,6 +3041,13 @@ notices.desc=提示描述 | |||
| notices.op=操作 | |||
| notices.delete_success=系统通知已被删除。 | |||
| user_management = 用户管理 | |||
| resource_management = 资源管理 | |||
| resource_pool = 资源池(队列) | |||
| resource_price = 资源规格单价 | |||
| application_scenario = 应用场景 | |||
| system_configuration = 系统配置 | |||
| [action] | |||
| create_repo=创建了项目 <a href="%s">%s</a> | |||
| rename_repo=重命名项目 <code>%[1]s</code> 为 <a href="%[2]s">%[3]s</a> | |||
| @@ -3087,9 +3171,13 @@ Platform_Tutorial=新手指引 | |||
| foot.advice_feedback = 意见反馈 | |||
| [cloudbrain] | |||
| all_resource_cluster=全部集群 | |||
| all_ai_center=全部智算中心 | |||
| resource_cluster = 算力集群 | |||
| resource_cluster_openi = 启智集群 | |||
| resource_cluster_c2net = 智算网络集群 | |||
| resource_cluster_openi_simple = 启智 | |||
| resource_cluster_c2net_simple = 智算网络 | |||
| compute_resource = 计算资源 | |||
| task_name = 任务名称 | |||
| task_type = 任务类型 | |||
| @@ -3110,23 +3198,31 @@ select_dataset = 选择数据集 | |||
| specification = 规格 | |||
| select_specification = 选择资源规格 | |||
| description = 描述 | |||
| card_duration = 运行卡时 | |||
| card_type = 卡类型 | |||
| wrong_specification=您目前不能使用这个资源规格,请选择其他资源规格。 | |||
| job_name_rule = 请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。 | |||
| dataset_path_rule = 数据集位置存储在环境变量data_url中,训练输出路径存储在环境变量train_url中。 | |||
| train_dataset_path_rule = 数据集位置存储在环境变量<strong style="color:#010101">data_url</strong>中,训练输出路径存储在环境变量<strong style="color:#010101">train_url</strong>中。 | |||
| infer_dataset_path_rule = 数据集位置存储在环境变量<strong style="color:#010101">data_url</strong>中,推理输出路径存储在环境变量<strong style="color:#010101">result_url</strong>中。 | |||
| view_sample = 查看样例 | |||
| inference_output_path_rule = 推理输出路径存储在环境变量result_url中。 | |||
| model_file_path_rule = 模型文件位置存储在环境变量ckpt_url中。 | |||
| model_file_postfix_rule = 模型文件支持的格式为 [ckpt, pb, h5, json, pkl, pth, t7, pdparams, onnx, pbtxt, keras, mlmodel, cfg, pt] | |||
| model_convert_postfix_rule = 模型文件支持的格式为 [.pth, .pkl, .onnx, .mindir, .ckpt, .pb] | |||
| delete_task = 删除任务 | |||
| task_delete_confirm = 你确认删除该任务么?此任务一旦删除不可恢复。 | |||
| operate_confirm = 确定操作 | |||
| operate_cancel = 取消操作 | |||
| resource_use=资源占用情况 | |||
| gpu_num = GPU数 | |||
| cpu_num = CPU数 | |||
| memory = 内存 | |||
| shared_memory = 共享内存 | |||
| gpu_memory = 显存 | |||
| free = 免费 | |||
| point_hr = 积分/时 | |||
| DEBUG = 调试任务 | |||
| SNN4IMAGENET = 评测任务 | |||
| @@ -3136,6 +3232,14 @@ INFERENCE = 推理任务 | |||
| BENCHMARK = 评测任务 | |||
| brain_area = 脑区 | |||
| Delete_failed=任务删除失败,请稍后再试。 | |||
| Not_Stopped=任务还未终止,不能删除。 | |||
| Already_stopped=任务已停止。 | |||
| Stopped_failed=任务停止失败,请稍后再试。 | |||
| Stopped_success_update_status_fail=任务停止成功,状态及运行时间更新失败。 | |||
| load_code_failed=代码加载失败,请确认选择了正确的分支。 | |||
| error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 | |||
| [points] | |||
| @@ -3147,3 +3251,6 @@ hours = 小时 | |||
| expected_time = ,预计可用 | |||
| points_acquisition_instructions = 积分获取说明 | |||
| insufficient_points_balance = 积分余额不足 | |||
| new_train_gpu_tooltips =训练脚本存储在<strong style="color:#010101">%s</strong>中,数据集存储在<strong style="color:#010101">%s</strong>中,训练输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||
| new_infer_gpu_tooltips = 数据集存储在<strong style="color:#010101">%s</strong>中,模型文件存储在<strong style="color:#010101">%s</strong>中,推理输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||
| @@ -4395,6 +4395,7 @@ | |||
| "version": "3.0.0", | |||
| "resolved": "https://registry.npm.taobao.org/date-format/download/date-format-3.0.0.tgz", | |||
| "integrity": "sha1-64eANlx9KxURB4+0keZHl4DzrZU=", | |||
| "deprecated": "3.x is no longer supported. Please upgrade to 4.x or higher.", | |||
| "engines": { | |||
| "node": ">=4.0" | |||
| } | |||
| @@ -15641,6 +15642,7 @@ | |||
| "version": "2.2.4", | |||
| "resolved": "https://registry.npm.taobao.org/streamroller/download/streamroller-2.2.4.tgz", | |||
| "integrity": "sha1-wZjO1C25QIamGTYIGHzoCl8rDlM=", | |||
| "deprecated": "2.x is no longer supported. Please upgrade to 3.x or higher.", | |||
| "dependencies": { | |||
| "date-format": "^2.1.0", | |||
| "debug": "^4.1.1", | |||
| @@ -15654,6 +15656,7 @@ | |||
| "version": "2.1.0", | |||
| "resolved": "https://registry.npm.taobao.org/date-format/download/date-format-2.1.0.tgz", | |||
| "integrity": "sha1-MdW16iEc9f12TNOLr50DPffhJc8=", | |||
| "deprecated": "2.x is no longer supported. Please upgrade to 4.x or higher.", | |||
| "engines": { | |||
| "node": ">=4.0" | |||
| } | |||
| @@ -119,7 +119,6 @@ document.onreadystatechange = function () { | |||
| continue; | |||
| } | |||
| } | |||
| refresh3DInfo(record); | |||
| var recordPrefix = getMsg(record); | |||
| if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){ | |||
| html += recordPrefix + actionName; | |||
| @@ -208,29 +207,6 @@ function getTaskLink(record){ | |||
| return re; | |||
| } | |||
| function refresh3DInfo(record){ | |||
| if(record.OpType == "25" || record.OpType == "29" || record.OpType == "31"){ | |||
| //cloudbrain one | |||
| var lines = $('.rotation3D__line'); | |||
| var span = $('.rotation3D__line').find("span")[0]; | |||
| //console.log(span); | |||
| span.innerText =record.RefName; | |||
| //$('.rotation3D__line').find("span").eq(0).text(record.RefName) | |||
| //console.log("cloudbrain one line length=" + lines.length); | |||
| //lines[0].find("span").text(record.RefName); | |||
| }else if(record.OpType == "26" || record.OpType == "27" || record.OpType == "28"){ | |||
| //cloudbrain two | |||
| var lines = $('.rotation3D__line'); | |||
| //console.log("cloudbrain two line length=" + lines.length); | |||
| var span = $('.rotation3D__line').find("span")[1]; | |||
| //console.log(span); | |||
| if(span != null){ | |||
| span.innerText =record.RefName; | |||
| } | |||
| } | |||
| } | |||
| function getMsg(record){ | |||
| var html =""; | |||
| html += "<div class=\"swiper-slide item\">"; | |||
| @@ -1,6 +1,7 @@ | |||
| .nb-notebook { | |||
| line-height: 1.5; | |||
| margin-left: 7em; | |||
| margin-left: 6em; | |||
| } | |||
| .nb-stdout, .nb-stderr { | |||
| @@ -15,6 +16,7 @@ | |||
| .nb-cell + .nb-cell { | |||
| margin-top: 0.5em; | |||
| max-width: 100%; | |||
| } | |||
| .nb-output table { | |||
| @@ -40,6 +42,11 @@ | |||
| padding-left: 1em; | |||
| } | |||
| .nb-notebook img { | |||
| max-width: 80%; | |||
| padding: 3px; | |||
| } | |||
| .nb-cell { | |||
| position: relative; | |||
| } | |||
| @@ -60,7 +67,8 @@ | |||
| } | |||
| .nb-output img { | |||
| max-width: 100%; | |||
| max-width: 80%; | |||
| padding: 3px; | |||
| } | |||
| .nb-output:before, .nb-input:before { | |||
| @@ -123,13 +123,13 @@ function loadimg(uuid,filename){ | |||
| function loadimg(){ | |||
| var length = labeltastresult[fileindex].pic_image_field.length; | |||
| if(labeltastresult[fileindex].pic_image_field.substring(length - 5) == ".json" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".xml" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".txt" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".csv" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".md" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".py" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".sh"){ | |||
| if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".json" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".xml" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".txt" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".csv" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".md" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".py" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".sh"){ | |||
| //文本 | |||
| canvas.style.display="none"; | |||
| @@ -138,11 +138,11 @@ function loadimg(){ | |||
| $('#textcontent').height(canvas.height-40) | |||
| $("#textcontent").text(textContent); | |||
| }else{ | |||
| if(labeltastresult[fileindex].pic_image_field.substring(length - 5) == ".jpeg" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".jpg" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".bmp" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".gif" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".png"){ | |||
| if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".jpeg" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".jpg" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".bmp" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".gif" | |||
| || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".png"){ | |||
| canvas.style.display="block"; | |||
| document.getElementById("textcontent").style.display="none"; | |||
| img.src = ip + "/getgiteaimage?uuid=" + dataset_id + "&filename=" + labeltastresult[fileindex].pic_image_field; | |||
| @@ -0,0 +1,386 @@ | |||
| /*------------------------------------- | |||
| zTree Style using fontawesome instead of images | |||
| version: 1.1 | |||
| author: Mike King | |||
| email: mikkelking @ hotmail . com | |||
| website: http://code.google.com/p/jquerytree/ | |||
| -------------------------------------*/ | |||
| /* Definitions ----------------------*/ | |||
| /* End of Definitions ---------------*/ | |||
| /* Imports -------------------------*/ | |||
| /* End of Imports ------------------*/ | |||
| .ztree * { | |||
| padding: 0; | |||
| margin: 0; | |||
| font-size: 12px; | |||
| font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; | |||
| background-color: #af0000; | |||
| } | |||
| .ztree { | |||
| margin: 0; | |||
| padding: 5px; | |||
| color: #ffffff; | |||
| background-color: #af0000; | |||
| } | |||
| .ztree li { | |||
| padding: 0; | |||
| margin: 0; | |||
| list-style: none; | |||
| line-height: 17px; | |||
| text-align: left; | |||
| white-space: nowrap; | |||
| outline: 0; | |||
| } | |||
| .ztree li ul { | |||
| margin: 0px; | |||
| padding: 0 0 0 18px; | |||
| } | |||
| .ztree li a { | |||
| padding-right: 3px; | |||
| margin: 0; | |||
| cursor: pointer; | |||
| height: 17px; | |||
| color: #ffffff; | |||
| background-color: transparent; | |||
| text-decoration: none; | |||
| vertical-align: top; | |||
| display: inline-block; | |||
| } | |||
| .ztree li a input.rename { | |||
| height: 14px; | |||
| width: 80px; | |||
| padding: 0; | |||
| margin: 0; | |||
| color: #af0000; | |||
| background-color: #ffffff; | |||
| font-size: 12px; | |||
| border: 1px #585956 solid; | |||
| *border: 0px; | |||
| } | |||
| .ztree li a:hover { | |||
| text-decoration: underline; | |||
| } | |||
| .ztree li a.curSelectedNode { | |||
| padding-top: 0px; | |||
| background-color: #af4040; | |||
| color: #ffff00; | |||
| height: 17px; | |||
| opacity: 0.8; | |||
| } | |||
| .ztree li a.curSelectedNode_Edit { | |||
| padding-top: 0px; | |||
| background-color: transparent; | |||
| color: #ffff00; | |||
| height: 17px; | |||
| border: 1px #666 solid; | |||
| opacity: 0.8; | |||
| } | |||
| .ztree li a.tmpTargetNode_inner { | |||
| padding-top: 0px; | |||
| background-color: #aaa; | |||
| color: #ffff00; | |||
| height: 17px; | |||
| border: 1px #666 solid; | |||
| opacity: 0.8; | |||
| filter: alpha(opacity=80); | |||
| } | |||
| .ztree li span { | |||
| line-height: 17px; | |||
| margin-right: 2px; | |||
| background-color: transparent; | |||
| } | |||
| .ztree li span.button { | |||
| line-height: 0; | |||
| margin: 0; | |||
| padding: 0; | |||
| width: 15px; | |||
| height: 17px; | |||
| display: inline-block; | |||
| vertical-align: top; | |||
| border: 0px solid; | |||
| cursor: pointer; | |||
| outline: none; | |||
| background-color: transparent; | |||
| background-repeat: no-repeat; | |||
| background-attachment: scroll; | |||
| } | |||
| .ztree li span.button::before { | |||
| color: #ffffff; | |||
| font-family: FontAwesome; | |||
| padding-top: 10px; | |||
| } | |||
| .ztree li span.button.chk { | |||
| margin: 0px; | |||
| cursor: auto; | |||
| width: 12px; | |||
| display: inline-block; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| } | |||
| .ztree li span.button.chk.checkbox_false_full::before { | |||
| content: "\f096"; | |||
| } | |||
| .ztree li span.button.chk.checkbox_false_full_focus::before { | |||
| content: "\f096"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.checkbox_false_part::before { | |||
| content: "\f096"; | |||
| color: #aaaaaa; | |||
| } | |||
| .ztree li span.button.chk.checkbox_false_part_focus::before { | |||
| content: "\f096"; | |||
| color: #cad96c; | |||
| } | |||
| .ztree li span.button.chk.checkbox_false_disable::before { | |||
| content: "\f096"; | |||
| color: #808080; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_full::before { | |||
| content: "\f046"; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_full_focus::before { | |||
| content: "\f046"; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_part::before { | |||
| content: "\f14a"; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_part_focus::before { | |||
| content: "\f14a"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_full_focus::before { | |||
| content: "\f046"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_part::before { | |||
| content: "\f046"; | |||
| color: #aaaaaa; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_part_focus::before { | |||
| content: "\f046"; | |||
| color: #cad96c; | |||
| } | |||
| .ztree li span.button.chk.checkbox_true_disable::before { | |||
| content: "\f046"; | |||
| color: #808080; | |||
| } | |||
| .ztree li span.button.chk.radio_false_full::before { | |||
| content: "\f10c"; | |||
| } | |||
| .ztree li span.button.chk.radio_false_full_focus::before { | |||
| content: "\f10c"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.radio_false_part::before { | |||
| content: "\f10c"; | |||
| color: #aaaaaa; | |||
| } | |||
| .ztree li span.button.chk.radio_false_part_focus::before { | |||
| content: "\f10c"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.radio_false_disable::before { | |||
| content: "\f1db"; | |||
| color: #808080; | |||
| } | |||
| .ztree li span.button.chk.radio_true_full::before { | |||
| content: "\f192"; | |||
| } | |||
| .ztree li span.button.chk.radio_true_full_focus::before { | |||
| content: "\f192"; | |||
| color: #ffff00; | |||
| } | |||
| .ztree li span.button.chk.radio_true_part::before { | |||
| content: "\f192"; | |||
| color: #aaaaaa; | |||
| } | |||
| .ztree li span.button.chk.radio_true_part_focus::before { | |||
| content: "\f192"; | |||
| color: #aaaaaa; | |||
| } | |||
| .ztree li span.button.chk.radio_true_disable::before { | |||
| content: "\f1db"; | |||
| color: #808080; | |||
| } | |||
| .ztree li span.button.switch { | |||
| width: 15px; | |||
| height: 17px; | |||
| } | |||
| .ztree li span.button.root_open::before { | |||
| content: "\f078"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.root_close::before { | |||
| content: "\f054"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.roots_open::before { | |||
| content: "\f078"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.roots_close::before { | |||
| content: "\f054"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.center_open::before { | |||
| content: "\f078"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.center_close::before { | |||
| content: "\f054"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.bottom_open::before { | |||
| content: "\f078"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.bottom_close::before { | |||
| content: "\f054"; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| } | |||
| .ztree li span.button.root_docu { | |||
| background: none; | |||
| } | |||
| .ztree li span.button.roots_docu::before { | |||
| content: "\f022"; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.center_docu::before { | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.bottom_docu::before { | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.noline_docu { | |||
| background: none; | |||
| } | |||
| .ztree li span.button.ico_open::before { | |||
| content: "\f115"; | |||
| font-family: FontAwesome; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.ico_close::before { | |||
| content: "\f114"; | |||
| font-family: FontAwesome; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.ico_docu::before { | |||
| content: "\f022"; | |||
| font-family: FontAwesome; | |||
| padding-top: 10px; | |||
| padding-left: 2px; | |||
| display: inline-block; | |||
| color: #ffffff; | |||
| } | |||
| .ztree li span.button.edit { | |||
| margin-left: 4px; | |||
| margin-right: -1px; | |||
| vertical-align: top; | |||
| *vertical-align: middle; | |||
| padding-top: 10px; | |||
| } | |||
| .ztree li span.button.edit::before { | |||
| content: "\f044"; | |||
| font-family: FontAwesome; | |||
| } | |||
| .ztree li span.button.remove { | |||
| margin-left: 4px; | |||
| margin-right: -1px; | |||
| vertical-align: top; | |||
| *vertical-align: middle; | |||
| padding-top: 10px; | |||
| } | |||
| .ztree li span.button.remove::before { | |||
| content: "\f1f8"; | |||
| font-family: FontAwesome; | |||
| } | |||
| .ztree li span.button.add { | |||
| margin-left: 4px; | |||
| margin-right: -1px; | |||
| vertical-align: top; | |||
| *vertical-align: middle; | |||
| padding-top: 10px; | |||
| } | |||
| .ztree li span.button.add::before { | |||
| content: "\f067"; | |||
| font-family: FontAwesome; | |||
| } | |||
| .ztree li span.button.ico_loading { | |||
| margin-right: 2px; | |||
| background: url(./img/loading.gif) no-repeat scroll 0 0 transparent; | |||
| vertical-align: top; | |||
| *vertical-align: middle; | |||
| } | |||
| ul.tmpTargetzTree { | |||
| background-color: #FFE6B0; | |||
| opacity: 0.8; | |||
| filter: alpha(opacity=80); | |||
| } | |||
| span.tmpzTreeMove_arrow { | |||
| width: 16px; | |||
| height: 17px; | |||
| display: inline-block; | |||
| padding: 0; | |||
| margin: 2px 0 0 1px; | |||
| border: 0 none; | |||
| position: absolute; | |||
| background-color: transparent; | |||
| background-attachment: scroll; | |||
| } | |||
| span.tmpzTreeMove_arrow::before { | |||
| content: "\f04b"; | |||
| font-family: FontAwesome; | |||
| color: #ffff00; | |||
| } | |||
| ul.ztree.zTreeDragUL { | |||
| margin: 0; | |||
| padding: 0; | |||
| position: absolute; | |||
| width: auto; | |||
| height: auto; | |||
| overflow: hidden; | |||
| background-color: #cfcfcf; | |||
| border: 1px #ffff00 dotted; | |||
| opacity: 0.8; | |||
| filter: alpha(opacity=80); | |||
| } | |||
| .ztreeMask { | |||
| z-index: 10000; | |||
| background-color: #cfcfcf; | |||
| opacity: 0.0; | |||
| filter: alpha(opacity=0); | |||
| position: absolute; | |||
| } | |||
| @@ -0,0 +1,146 @@ | |||
| /*------------------------------------- | |||
| zTree Style using fontawesome instead of images | |||
| version: 1.1 | |||
| author: Mike King | |||
| email: mikkelking @ hotmail . com | |||
| website: http://code.google.com/p/jquerytree/ | |||
| -------------------------------------*/ | |||
| /* Definitions ----------------------*/ | |||
| @font-size: 12px; | |||
| // Regular icon and text color is white, which suits any medium -> dark background | |||
| @color-normal: white; | |||
| // Background color | |||
| @color-bg: #af0000; | |||
| // Highlight color | |||
| @color-highlight: yellow; | |||
| // Partially selected (checkboxes, radio buttons) | |||
| @color-partial: #aaaaaa; | |||
| // Partially selected and focused (checkboxes, radio buttons) | |||
| @color-partfocus: #cad96c; | |||
| // Disabled altogether | |||
| @color-disabled: #808080; | |||
| // Editing color | |||
| @color-edit: yellow; | |||
| @w: 15px; | |||
| @h: 17px; | |||
| @pad-left: 2px; | |||
| @pad-top: 10px; | |||
| /* End of Definitions ---------------*/ | |||
| /* Imports -------------------------*/ | |||
| @import "fa.less"; | |||
| /* End of Imports ------------------*/ | |||
| .ztree * {padding:0; margin:0; font-size:@font-size; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; background-color: @color-bg;} | |||
| .ztree { | |||
| margin:0; padding:5px; color:@color-normal; background-color: @color-bg; | |||
| li { | |||
| padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0; | |||
| ul { | |||
| margin: 0px; padding:0 0 0 18px; | |||
| } | |||
| ul.line { } | |||
| a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent; | |||
| text-decoration:none; vertical-align:top; display: inline-block; | |||
| input.rename {height:14px; width:80px; padding:0; margin:0; | |||
| color: @color-bg; background-color: @color-normal; | |||
| font-size:@font-size; border:1px #585956 solid; *border:0px} | |||
| } | |||
| a:hover {text-decoration:underline} | |||
| a.curSelectedNode {padding-top:0px; background-color:#af4040; color:@color-highlight; height:@h; opacity:0.8;} | |||
| a.curSelectedNode_Edit {padding-top:0px; background-color:transparent; color:@color-highlight; height:@h; border:1px #666 solid; opacity:0.8;} | |||
| a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:@color-highlight; height:@h; border:1px #666 solid; | |||
| opacity:0.8; filter:alpha(opacity=80)} | |||
| a.tmpTargetNode_prev {} | |||
| a.tmpTargetNode_next {} | |||
| span {line-height:@h; margin-right:2px; background-color:transparent;} | |||
| span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top; | |||
| border:0px solid; cursor: pointer;outline:none; | |||
| background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||
| &::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;} | |||
| &.chk { margin:0px; cursor: auto; width: 12px; | |||
| display: inline-block;padding-top:@pad-top;padding-left:@pad-left; | |||
| &.checkbox_false_full::before {content: @fa-square-o;} | |||
| &.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;} | |||
| &.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;} | |||
| &.checkbox_false_part_focus::before {content: @fa-square-o; color:@color-partfocus;} | |||
| &.checkbox_false_disable::before {content: @fa-square-o; color:@color-disabled;} | |||
| &.checkbox_true_full::before {content: @fa-check-square-o;} | |||
| &.checkbox_true_full_focus::before {content: @fa-check-square-o;} | |||
| &.checkbox_true_part::before {content: @fa-check-square;} | |||
| &.checkbox_true_part_focus::before {content: @fa-check-square; color: @color-highlight} | |||
| &.checkbox_true_full_focus::before {content: @fa-check-square-o; color: @color-highlight} | |||
| &.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial} | |||
| &.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;} | |||
| &.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled} | |||
| &.radio_false_full::before {content: @fa-circle-o;} | |||
| &.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight} | |||
| &.radio_false_part::before {content: @fa-circle-o;color: @color-partial} | |||
| &.radio_false_part_focus::before {content: @fa-circle-o;color: @color-highlight} | |||
| &.radio_false_disable::before {content: @fa-circle-thin;color: @color-disabled} | |||
| &.radio_true_full::before {content: @fa-dot-circle-o;} | |||
| &.radio_true_full_focus::before {content: @fa-dot-circle-o;color: @color-highlight} | |||
| &.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial} | |||
| &.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;} | |||
| &.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled} | |||
| } | |||
| &.switch {width:@w; height:@h} | |||
| &.root_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.root_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.roots_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.roots_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.center_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.center_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.bottom_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.bottom_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} | |||
| &.noline_open{} | |||
| &.noline_close{} | |||
| &.root_docu{ background:none;} | |||
| &.roots_docu::before{content: @fa-list-alt;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.noline_docu{ background:none;} | |||
| &.ico_open::before {content: @fa-folder-open-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.ico_close::before {content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} | |||
| &.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||
| &.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;} | |||
| &.remove {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||
| &.remove::before{content: @fa-trash;font-family: FontAwesome;} | |||
| &.add {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} | |||
| &.add::before{content: @fa-plus;font-family: FontAwesome;} | |||
| &.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||
| } | |||
| } | |||
| } | |||
| ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||
| // this is the arrow that moves | |||
| span.tmpzTreeMove_arrow{width:16px; height:@h; display: inline-block; | |||
| padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||
| background-color:transparent; background-attachment: scroll; | |||
| } | |||
| span.tmpzTreeMove_arrow::before{content: @fa-play;font-family: FontAwesome;color: @color-highlight; | |||
| } | |||
| // outline | |||
| ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; | |||
| background-color:#cfcfcf; border:1px @color-highlight dotted; opacity:0.8; filter:alpha(opacity=80)} | |||
| .ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} | |||
| @@ -0,0 +1,480 @@ | |||
| @fa-glass: "\f000"; | |||
| @fa-music: "\f001"; | |||
| @fa-search: "\f002"; | |||
| @fa-envelope-o: "\f003"; | |||
| @fa-heart: "\f004"; | |||
| @fa-star: "\f005"; | |||
| @fa-star-o: "\f006"; | |||
| @fa-user: "\f007"; | |||
| @fa-film: "\f008"; | |||
| @fa-th-large: "\f009"; | |||
| @fa-th: "\f00a"; | |||
| @fa-th-list: "\f00b"; | |||
| @fa-check: "\f00c"; | |||
| @fa-times: "\f00d"; | |||
| @fa-search-plus: "\f00e"; | |||
| @fa-search-minus: "\f010"; | |||
| @fa-power-off: "\f011"; | |||
| @fa-signal: "\f012"; | |||
| @fa-cog: "\f013"; | |||
| @fa-trash-o: "\f014"; | |||
| @fa-home: "\f015"; | |||
| @fa-file-o: "\f016"; | |||
| @fa-clock-o: "\f017"; | |||
| @fa-road: "\f018"; | |||
| @fa-download: "\f019"; | |||
| @fa-arrow-circle-o-down: "\f01a"; | |||
| @fa-arrow-circle-o-up: "\f01b"; | |||
| @fa-inbox: "\f01c"; | |||
| @fa-play-circle-o: "\f01d"; | |||
| @fa-repeat: "\f01e"; | |||
| @fa-refresh: "\f021"; | |||
| @fa-list-alt: "\f022"; | |||
| @fa-lock: "\f023"; | |||
| @fa-flag: "\f024"; | |||
| @fa-headphones: "\f025"; | |||
| @fa-volume-off: "\f026"; | |||
| @fa-volume-down: "\f027"; | |||
| @fa-volume-up: "\f028"; | |||
| @fa-qrcode: "\f029"; | |||
| @fa-barcode: "\f02a"; | |||
| @fa-tag: "\f02b"; | |||
| @fa-tags: "\f02c"; | |||
| @fa-book: "\f02d"; | |||
| @fa-bookmark: "\f02e"; | |||
| @fa-print: "\f02f"; | |||
| @fa-camera: "\f030"; | |||
| @fa-font: "\f031"; | |||
| @fa-bold: "\f032"; | |||
| @fa-italic: "\f033"; | |||
| @fa-text-height: "\f034"; | |||
| @fa-text-width: "\f035"; | |||
| @fa-align-left: "\f036"; | |||
| @fa-align-center: "\f037"; | |||
| @fa-align-right: "\f038"; | |||
| @fa-align-justify: "\f039"; | |||
| @fa-list: "\f03a"; | |||
| @fa-outdent: "\f03b"; | |||
| @fa-indent: "\f03c"; | |||
| @fa-video-camera: "\f03d"; | |||
| @fa-picture-o: "\f03e"; | |||
| @fa-pencil: "\f040"; | |||
| @fa-map-marker: "\f041"; | |||
| @fa-adjust: "\f042"; | |||
| @fa-tint: "\f043"; | |||
| @fa-pencil-square-o: "\f044"; | |||
| @fa-share-square-o: "\f045"; | |||
| @fa-check-square-o: "\f046"; | |||
| @fa-arrows: "\f047"; | |||
| @fa-step-backward: "\f048"; | |||
| @fa-fast-backward: "\f049"; | |||
| @fa-backward: "\f04a"; | |||
| @fa-play: "\f04b"; | |||
| @fa-pause: "\f04c"; | |||
| @fa-stop: "\f04d"; | |||
| @fa-forward: "\f04e"; | |||
| @fa-fast-forward: "\f050"; | |||
| @fa-step-forward: "\f051"; | |||
| @fa-eject: "\f052"; | |||
| @fa-chevron-left: "\f053"; | |||
| @fa-chevron-right: "\f054"; | |||
| @fa-plus-circle: "\f055"; | |||
| @fa-minus-circle: "\f056"; | |||
| @fa-times-circle: "\f057"; | |||
| @fa-check-circle: "\f058"; | |||
| @fa-question-circle: "\f059"; | |||
| @fa-info-circle: "\f05a"; | |||
| @fa-crosshairs: "\f05b"; | |||
| @fa-times-circle-o: "\f05c"; | |||
| @fa-check-circle-o: "\f05d"; | |||
| @fa-ban: "\f05e"; | |||
| @fa-arrow-left: "\f060"; | |||
| @fa-arrow-right: "\f061"; | |||
| @fa-arrow-up: "\f062"; | |||
| @fa-arrow-down: "\f063"; | |||
| @fa-share: "\f064"; | |||
| @fa-expand: "\f065"; | |||
| @fa-compress: "\f066"; | |||
| @fa-plus: "\f067"; | |||
| @fa-minus: "\f068"; | |||
| @fa-asterisk: "\f069"; | |||
| @fa-exclamation-circle: "\f06a"; | |||
| @fa-gift: "\f06b"; | |||
| @fa-leaf: "\f06c"; | |||
| @fa-fire: "\f06d"; | |||
| @fa-eye: "\f06e"; | |||
| @fa-eye-slash: "\f070"; | |||
| @fa-exclamation-triangle: "\f071"; | |||
| @fa-plane: "\f072"; | |||
| @fa-calendar: "\f073"; | |||
| @fa-random: "\f074"; | |||
| @fa-comment: "\f075"; | |||
| @fa-magnet: "\f076"; | |||
| @fa-chevron-up: "\f077"; | |||
| @fa-chevron-down: "\f078"; | |||
| @fa-retweet: "\f079"; | |||
| @fa-shopping-cart: "\f07a"; | |||
| @fa-folder: "\f07b"; | |||
| @fa-folder-open: "\f07c"; | |||
| @fa-arrows-v: "\f07d"; | |||
| @fa-arrows-h: "\f07e"; | |||
| @fa-bar-chart: "\f080"; | |||
| @fa-twitter-square: "\f081"; | |||
| @fa-facebook-square: "\f082"; | |||
| @fa-camera-retro: "\f083"; | |||
| @fa-key: "\f084"; | |||
| @fa-cogs: "\f085"; | |||
| @fa-comments: "\f086"; | |||
| @fa-thumbs-o-up: "\f087"; | |||
| @fa-thumbs-o-down: "\f088"; | |||
| @fa-star-half: "\f089"; | |||
| @fa-heart-o: "\f08a"; | |||
| @fa-sign-out: "\f08b"; | |||
| @fa-linkedin-square: "\f08c"; | |||
| @fa-thumb-tack: "\f08d"; | |||
| @fa-external-link: "\f08e"; | |||
| @fa-sign-in: "\f090"; | |||
| @fa-trophy: "\f091"; | |||
| @fa-github-square: "\f092"; | |||
| @fa-upload: "\f093"; | |||
| @fa-lemon-o: "\f094"; | |||
| @fa-phone: "\f095"; | |||
| @fa-square-o: "\f096"; | |||
| @fa-bookmark-o: "\f097"; | |||
| @fa-phone-square: "\f098"; | |||
| @fa-twitter: "\f099"; | |||
| @fa-facebook: "\f09a"; | |||
| @fa-github: "\f09b"; | |||
| @fa-unlock: "\f09c"; | |||
| @fa-credit-card: "\f09d"; | |||
| @fa-rss: "\f09e"; | |||
| @fa-hdd-o: "\f0a0"; | |||
| @fa-bullhorn: "\f0a1"; | |||
| @fa-bell: "\f0f3"; | |||
| @fa-certificate: "\f0a3"; | |||
| @fa-hand-o-right: "\f0a4"; | |||
| @fa-hand-o-left: "\f0a5"; | |||
| @fa-hand-o-up: "\f0a6"; | |||
| @fa-hand-o-down: "\f0a7"; | |||
| @fa-arrow-circle-left: "\f0a8"; | |||
| @fa-arrow-circle-right: "\f0a9"; | |||
| @fa-arrow-circle-up: "\f0aa"; | |||
| @fa-arrow-circle-down: "\f0ab"; | |||
| @fa-globe: "\f0ac"; | |||
| @fa-wrench: "\f0ad"; | |||
| @fa-tasks: "\f0ae"; | |||
| @fa-filter: "\f0b0"; | |||
| @fa-briefcase: "\f0b1"; | |||
| @fa-arrows-alt: "\f0b2"; | |||
| @fa-users: "\f0c0"; | |||
| @fa-link: "\f0c1"; | |||
| @fa-cloud: "\f0c2"; | |||
| @fa-flask: "\f0c3"; | |||
| @fa-scissors: "\f0c4"; | |||
| @fa-files-o: "\f0c5"; | |||
| @fa-paperclip: "\f0c6"; | |||
| @fa-floppy-o: "\f0c7"; | |||
| @fa-square: "\f0c8"; | |||
| @fa-bars: "\f0c9"; | |||
| @fa-list-ul: "\f0ca"; | |||
| @fa-list-ol: "\f0cb"; | |||
| @fa-strikethrough: "\f0cc"; | |||
| @fa-underline: "\f0cd"; | |||
| @fa-table: "\f0ce"; | |||
| @fa-magic: "\f0d0"; | |||
| @fa-truck: "\f0d1"; | |||
| @fa-pinterest: "\f0d2"; | |||
| @fa-pinterest-square: "\f0d3"; | |||
| @fa-google-plus-square: "\f0d4"; | |||
| @fa-google-plus: "\f0d5"; | |||
| @fa-money: "\f0d6"; | |||
| @fa-caret-down: "\f0d7"; | |||
| @fa-caret-up: "\f0d8"; | |||
| @fa-caret-left: "\f0d9"; | |||
| @fa-caret-right: "\f0da"; | |||
| @fa-columns: "\f0db"; | |||
| @fa-sort: "\f0dc"; | |||
| @fa-sort-desc: "\f0dd"; | |||
| @fa-sort-asc: "\f0de"; | |||
| @fa-envelope: "\f0e0"; | |||
| @fa-linkedin: "\f0e1"; | |||
| @fa-undo: "\f0e2"; | |||
| @fa-gavel: "\f0e3"; | |||
| @fa-tachometer: "\f0e4"; | |||
| @fa-comment-o: "\f0e5"; | |||
| @fa-comments-o: "\f0e6"; | |||
| @fa-bolt: "\f0e7"; | |||
| @fa-sitemap: "\f0e8"; | |||
| @fa-umbrella: "\f0e9"; | |||
| @fa-clipboard: "\f0ea"; | |||
| @fa-lightbulb-o: "\f0eb"; | |||
| @fa-exchange: "\f0ec"; | |||
| @fa-cloud-download: "\f0ed"; | |||
| @fa-cloud-upload: "\f0ee"; | |||
| @fa-user-md: "\f0f0"; | |||
| @fa-stethoscope: "\f0f1"; | |||
| @fa-suitcase: "\f0f2"; | |||
| @fa-bell-o: "\f0a2"; | |||
| @fa-coffee: "\f0f4"; | |||
| @fa-cutlery: "\f0f5"; | |||
| @fa-file-text-o: "\f0f6"; | |||
| @fa-building-o: "\f0f7"; | |||
| @fa-hospital-o: "\f0f8"; | |||
| @fa-ambulance: "\f0f9"; | |||
| @fa-medkit: "\f0fa"; | |||
| @fa-fighter-jet: "\f0fb"; | |||
| @fa-beer: "\f0fc"; | |||
| @fa-h-square: "\f0fd"; | |||
| @fa-plus-square: "\f0fe"; | |||
| @fa-angle-double-left: "\f100"; | |||
| @fa-angle-double-right: "\f101"; | |||
| @fa-angle-double-up: "\f102"; | |||
| @fa-angle-double-down: "\f103"; | |||
| @fa-angle-left: "\f104"; | |||
| @fa-angle-right: "\f105"; | |||
| @fa-angle-up: "\f106"; | |||
| @fa-angle-down: "\f107"; | |||
| @fa-desktop: "\f108"; | |||
| @fa-laptop: "\f109"; | |||
| @fa-tablet: "\f10a"; | |||
| @fa-mobile: "\f10b"; | |||
| @fa-circle-o: "\f10c"; | |||
| @fa-quote-left: "\f10d"; | |||
| @fa-quote-right: "\f10e"; | |||
| @fa-spinner: "\f110"; | |||
| @fa-circle: "\f111"; | |||
| @fa-reply: "\f112"; | |||
| @fa-github-alt: "\f113"; | |||
| @fa-folder-o: "\f114"; | |||
| @fa-folder-open-o: "\f115"; | |||
| @fa-smile-o: "\f118"; | |||
| @fa-frown-o: "\f119"; | |||
| @fa-meh-o: "\f11a"; | |||
| @fa-gamepad: "\f11b"; | |||
| @fa-keyboard-o: "\f11c"; | |||
| @fa-flag-o: "\f11d"; | |||
| @fa-flag-checkered: "\f11e"; | |||
| @fa-terminal: "\f120"; | |||
| @fa-code: "\f121"; | |||
| @fa-reply-all: "\f122"; | |||
| @fa-star-half-o: "\f123"; | |||
| @fa-location-arrow: "\f124"; | |||
| @fa-crop: "\f125"; | |||
| @fa-code-fork: "\f126"; | |||
| @fa-chain-broken: "\f127"; | |||
| @fa-question: "\f128"; | |||
| @fa-info: "\f129"; | |||
| @fa-exclamation: "\f12a"; | |||
| @fa-superscript: "\f12b"; | |||
| @fa-subscript: "\f12c"; | |||
| @fa-eraser: "\f12d"; | |||
| @fa-puzzle-piece: "\f12e"; | |||
| @fa-microphone: "\f130"; | |||
| @fa-microphone-slash: "\f131"; | |||
| @fa-shield: "\f132"; | |||
| @fa-calendar-o: "\f133"; | |||
| @fa-fire-extinguisher: "\f134"; | |||
| @fa-rocket: "\f135"; | |||
| @fa-maxcdn: "\f136"; | |||
| @fa-chevron-circle-left: "\f137"; | |||
| @fa-chevron-circle-right: "\f138"; | |||
| @fa-chevron-circle-up: "\f139"; | |||
| @fa-chevron-circle-down: "\f13a"; | |||
| @fa-html5: "\f13b"; | |||
| @fa-css3: "\f13c"; | |||
| @fa-anchor: "\f13d"; | |||
| @fa-unlock-alt: "\f13e"; | |||
| @fa-bullseye: "\f140"; | |||
| @fa-ellipsis-h: "\f141"; | |||
| @fa-ellipsis-v: "\f142"; | |||
| @fa-rss-square: "\f143"; | |||
| @fa-play-circle: "\f144"; | |||
| @fa-ticket: "\f145"; | |||
| @fa-minus-square: "\f146"; | |||
| @fa-minus-square-o: "\f147"; | |||
| @fa-level-up: "\f148"; | |||
| @fa-level-down: "\f149"; | |||
| @fa-check-square: "\f14a"; | |||
| @fa-pencil-square: "\f14b"; | |||
| @fa-external-link-square: "\f14c"; | |||
| @fa-share-square: "\f14d"; | |||
| @fa-compass: "\f14e"; | |||
| @fa-caret-square-o-down: "\f150"; | |||
| @fa-caret-square-o-up: "\f151"; | |||
| @fa-caret-square-o-right: "\f152"; | |||
| @fa-eur: "\f153"; | |||
| @fa-gbp: "\f154"; | |||
| @fa-usd: "\f155"; | |||
| @fa-inr: "\f156"; | |||
| @fa-jpy: "\f157"; | |||
| @fa-rub: "\f158"; | |||
| @fa-krw: "\f159"; | |||
| @fa-btc: "\f15a"; | |||
| @fa-file: "\f15b"; | |||
| @fa-file-text: "\f15c"; | |||
| @fa-sort-alpha-asc: "\f15d"; | |||
| @fa-sort-alpha-desc: "\f15e"; | |||
| @fa-sort-amount-asc: "\f160"; | |||
| @fa-sort-amount-desc: "\f161"; | |||
| @fa-sort-numeric-asc: "\f162"; | |||
| @fa-sort-numeric-desc: "\f163"; | |||
| @fa-thumbs-up: "\f164"; | |||
| @fa-thumbs-down: "\f165"; | |||
| @fa-youtube-square: "\f166"; | |||
| @fa-youtube: "\f167"; | |||
| @fa-xing: "\f168"; | |||
| @fa-xing-square: "\f169"; | |||
| @fa-youtube-play: "\f16a"; | |||
| @fa-dropbox: "\f16b"; | |||
| @fa-stack-overflow: "\f16c"; | |||
| @fa-instagram: "\f16d"; | |||
| @fa-flickr: "\f16e"; | |||
| @fa-adn: "\f170"; | |||
| @fa-bitbucket: "\f171"; | |||
| @fa-bitbucket-square: "\f172"; | |||
| @fa-tumblr: "\f173"; | |||
| @fa-tumblr-square: "\f174"; | |||
| @fa-long-arrow-down: "\f175"; | |||
| @fa-long-arrow-up: "\f176"; | |||
| @fa-long-arrow-left: "\f177"; | |||
| @fa-long-arrow-right: "\f178"; | |||
| @fa-apple: "\f179"; | |||
| @fa-windows: "\f17a"; | |||
| @fa-android: "\f17b"; | |||
| @fa-linux: "\f17c"; | |||
| @fa-dribbble: "\f17d"; | |||
| @fa-skype: "\f17e"; | |||
| @fa-foursquare: "\f180"; | |||
| @fa-trello: "\f181"; | |||
| @fa-female: "\f182"; | |||
| @fa-male: "\f183"; | |||
| @fa-gittip: "\f184"; | |||
| @fa-sun-o: "\f185"; | |||
| @fa-moon-o: "\f186"; | |||
| @fa-archive: "\f187"; | |||
| @fa-bug: "\f188"; | |||
| @fa-vk: "\f189"; | |||
| @fa-weibo: "\f18a"; | |||
| @fa-renren: "\f18b"; | |||
| @fa-pagelines: "\f18c"; | |||
| @fa-stack-exchange: "\f18d"; | |||
| @fa-arrow-circle-o-right: "\f18e"; | |||
| @fa-arrow-circle-o-left: "\f190"; | |||
| @fa-caret-square-o-left: "\f191"; | |||
| @fa-dot-circle-o: "\f192"; | |||
| @fa-wheelchair: "\f193"; | |||
| @fa-vimeo-square: "\f194"; | |||
| @fa-try: "\f195"; | |||
| @fa-plus-square-o: "\f196"; | |||
| @fa-space-shuttle: "\f197"; | |||
| @fa-slack: "\f198"; | |||
| @fa-envelope-square: "\f199"; | |||
| @fa-wordpress: "\f19a"; | |||
| @fa-openid: "\f19b"; | |||
| @fa-university: "\f19c"; | |||
| @fa-graduation-cap: "\f19d"; | |||
| @fa-yahoo: "\f19e"; | |||
| @fa-google: "\f1a0"; | |||
| @fa-reddit: "\f1a1"; | |||
| @fa-reddit-square: "\f1a2"; | |||
| @fa-stumbleupon-circle: "\f1a3"; | |||
| @fa-stumbleupon: "\f1a4"; | |||
| @fa-delicious: "\f1a5"; | |||
| @fa-digg: "\f1a6"; | |||
| @fa-pied-piper: "\f1a7"; | |||
| @fa-pied-piper-alt: "\f1a8"; | |||
| @fa-drupal: "\f1a9"; | |||
| @fa-joomla: "\f1aa"; | |||
| @fa-language: "\f1ab"; | |||
| @fa-fax: "\f1ac"; | |||
| @fa-building: "\f1ad"; | |||
| @fa-child: "\f1ae"; | |||
| @fa-paw: "\f1b0"; | |||
| @fa-spoon: "\f1b1"; | |||
| @fa-cube: "\f1b2"; | |||
| @fa-cubes: "\f1b3"; | |||
| @fa-behance: "\f1b4"; | |||
| @fa-behance-square: "\f1b5"; | |||
| @fa-steam: "\f1b6"; | |||
| @fa-steam-square: "\f1b7"; | |||
| @fa-recycle: "\f1b8"; | |||
| @fa-car: "\f1b9"; | |||
| @fa-taxi: "\f1ba"; | |||
| @fa-tree: "\f1bb"; | |||
| @fa-spotify: "\f1bc"; | |||
| @fa-deviantart: "\f1bd"; | |||
| @fa-soundcloud: "\f1be"; | |||
| @fa-database: "\f1c0"; | |||
| @fa-file-pdf-o: "\f1c1"; | |||
| @fa-file-word-o: "\f1c2"; | |||
| @fa-file-excel-o: "\f1c3"; | |||
| @fa-file-powerpoint-o: "\f1c4"; | |||
| @fa-file-image-o: "\f1c5"; | |||
| @fa-file-archive-o: "\f1c6"; | |||
| @fa-file-audio-o: "\f1c7"; | |||
| @fa-file-video-o: "\f1c8"; | |||
| @fa-file-code-o: "\f1c9"; | |||
| @fa-vine: "\f1ca"; | |||
| @fa-codepen: "\f1cb"; | |||
| @fa-jsfiddle: "\f1cc"; | |||
| @fa-life-ring: "\f1cd"; | |||
| @fa-circle-o-notch: "\f1ce"; | |||
| @fa-rebel: "\f1d0"; | |||
| @fa-empire: "\f1d1"; | |||
| @fa-git-square: "\f1d2"; | |||
| @fa-git: "\f1d3"; | |||
| @fa-hacker-news: "\f1d4"; | |||
| @fa-tencent-weibo: "\f1d5"; | |||
| @fa-qq: "\f1d6"; | |||
| @fa-weixin: "\f1d7"; | |||
| @fa-paper-plane: "\f1d8"; | |||
| @fa-paper-plane-o: "\f1d9"; | |||
| @fa-history: "\f1da"; | |||
| @fa-circle-thin: "\f1db"; | |||
| @fa-header: "\f1dc"; | |||
| @fa-paragraph: "\f1dd"; | |||
| @fa-sliders: "\f1de"; | |||
| @fa-share-alt: "\f1e0"; | |||
| @fa-share-alt-square: "\f1e1"; | |||
| @fa-bomb: "\f1e2"; | |||
| @fa-futbol-o: "\f1e3"; | |||
| @fa-tty: "\f1e4"; | |||
| @fa-binoculars: "\f1e5"; | |||
| @fa-plug: "\f1e6"; | |||
| @fa-slideshare: "\f1e7"; | |||
| @fa-twitch: "\f1e8"; | |||
| @fa-yelp: "\f1e9"; | |||
| @fa-newspaper-o: "\f1ea"; | |||
| @fa-wifi: "\f1eb"; | |||
| @fa-calculator: "\f1ec"; | |||
| @fa-paypal: "\f1ed"; | |||
| @fa-google-wallet: "\f1ee"; | |||
| @fa-cc-visa: "\f1f0"; | |||
| @fa-cc-mastercard: "\f1f1"; | |||
| @fa-cc-discover: "\f1f2"; | |||
| @fa-cc-amex: "\f1f3"; | |||
| @fa-cc-paypal: "\f1f4"; | |||
| @fa-cc-stripe: "\f1f5"; | |||
| @fa-bell-slash: "\f1f6"; | |||
| @fa-bell-slash-o: "\f1f7"; | |||
| @fa-trash: "\f1f8"; | |||
| @fa-copyright: "\f1f9"; | |||
| @fa-at: "\f1fa"; | |||
| @fa-eyedropper: "\f1fb"; | |||
| @fa-paint-brush: "\f1fc"; | |||
| @fa-birthday-cake: "\f1fd"; | |||
| @fa-area-chart: "\f1fe"; | |||
| @fa-pie-chart: "\f200"; | |||
| @fa-line-chart: "\f201"; | |||
| @fa-lastfm: "\f202"; | |||
| @fa-lastfm-square: "\f203"; | |||
| @fa-toggle-off: "\f204"; | |||
| @fa-toggle-on: "\f205"; | |||
| @fa-bicycle: "\f206"; | |||
| @fa-bus: "\f207"; | |||
| @fa-ioxhost: "\f208"; | |||
| @fa-angellist: "\f209"; | |||
| @fa-cc: "\f20a"; | |||
| @fa-ils: "\f20b"; | |||
| @fa-meanpath: "\f20c"; | |||
| @@ -0,0 +1,33 @@ | |||
| html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { | |||
| margin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;} | |||
| body {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \9;} | |||
| h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;} | |||
| h1 {font-size: 24px;line-height: 34px;text-align: center;} | |||
| h2 {font-size: 14px;line-height: 24px;padding-top: 5px;} | |||
| h6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;} | |||
| a {color:#3C6E31;text-decoration: underline;} | |||
| a:hover {background-color:#3C6E31;color:white;} | |||
| input.radio {margin: 0 2px 0 8px;} | |||
| input.radio.first {margin-left:0;} | |||
| input.empty {color: lightgray;} | |||
| code {color: #2f332a;} | |||
| .highlight_red {color:#A60000;} | |||
| .highlight_green {color:#A7F43D;} | |||
| li {list-style: circle;font-size: 12px;} | |||
| li.title {list-style: none;} | |||
| ul.list {margin-left: 17px;} | |||
| div.content_wrap {width: 600px;height:380px;} | |||
| div.content_wrap div.left{float: left;width: 250px;} | |||
| div.content_wrap div.right{float: right;width: 340px;} | |||
| div.zTreeDemoBackground {width:250px;height:362px;text-align:left;} | |||
| ul.ztree {margin-top: 10px;border: 1px solid #617775;background: #f0f6e4;width:220px;height:360px;overflow-y:scroll;overflow-x:auto;} | |||
| ul.log {border: 1px solid #617775;background: #f0f6e4;width:300px;height:170px;overflow: hidden;} | |||
| ul.log.small {height:45px;} | |||
| ul.log li {color: #666666;list-style: none;padding-left: 10px;} | |||
| ul.log li.dark {background-color: #E3E3E3;} | |||
| /* ruler */ | |||
| div.ruler {height:20px; width:220px; background-color:#f0f6e4;border: 1px solid #333; margin-bottom: 5px; cursor: pointer} | |||
| div.ruler div.cursor {height:20px; width:30px; background-color:#3C6E31; color:white; text-align: right; padding-right: 5px; cursor: pointer} | |||
| @@ -0,0 +1,96 @@ | |||
| /*------------------------------------- | |||
| zTree Style | |||
| version: 3.4 | |||
| author: Hunter.z | |||
| email: hunter.z@263.net | |||
| website: http://code.google.com/p/jquerytree/ | |||
| -------------------------------------*/ | |||
| .ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} | |||
| .ztree {margin:0; padding:5px; color:#333} | |||
| .ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0} | |||
| .ztree li ul{ margin:0; padding:0 0 0 18px} | |||
| .ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;} | |||
| .ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block} | |||
| .ztree li a:hover {text-decoration:underline} | |||
| .ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;} | |||
| .ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;} | |||
| .ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid; | |||
| opacity:0.8; filter:alpha(opacity=80)} | |||
| .ztree li a.tmpTargetNode_prev {} | |||
| .ztree li a.tmpTargetNode_next {} | |||
| .ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; | |||
| font-size:12px; border:1px #585956 solid; *border:0px} | |||
| .ztree li span {line-height:21px; margin-right:2px} | |||
| .ztree li span.button {line-height:0; margin:0; padding: 0; width:21px; height:21px; display: inline-block; vertical-align:middle; | |||
| border:0 none; cursor: pointer;outline:none; | |||
| background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||
| background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")} | |||
| .ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto} | |||
| .ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;} | |||
| .ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;} | |||
| .ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;} | |||
| .ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;} | |||
| .ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;} | |||
| .ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;} | |||
| .ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;} | |||
| .ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;} | |||
| .ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;} | |||
| .ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;} | |||
| .ztree li span.button.chk.radio_false_full {background-position: -47px -5px;} | |||
| .ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;} | |||
| .ztree li span.button.chk.radio_false_part {background-position: -47px -47px;} | |||
| .ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;} | |||
| .ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;} | |||
| .ztree li span.button.chk.radio_true_full {background-position: -68px -5px;} | |||
| .ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;} | |||
| .ztree li span.button.chk.radio_true_part {background-position: -68px -47px;} | |||
| .ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;} | |||
| .ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;} | |||
| .ztree li span.button.switch {width:21px; height:21px} | |||
| .ztree li span.button.root_open{background-position:-105px -63px} | |||
| .ztree li span.button.root_close{background-position:-126px -63px} | |||
| .ztree li span.button.roots_open{background-position: -105px 0;} | |||
| .ztree li span.button.roots_close{background-position: -126px 0;} | |||
| .ztree li span.button.center_open{background-position: -105px -21px;} | |||
| .ztree li span.button.center_close{background-position: -126px -21px;} | |||
| .ztree li span.button.bottom_open{background-position: -105px -42px;} | |||
| .ztree li span.button.bottom_close{background-position: -126px -42px;} | |||
| .ztree li span.button.noline_open{background-position: -105px -84px;} | |||
| .ztree li span.button.noline_close{background-position: -126px -84px;} | |||
| .ztree li span.button.root_docu{ background:none;} | |||
| .ztree li span.button.roots_docu{background-position: -84px 0;} | |||
| .ztree li span.button.center_docu{background-position: -84px -21px;} | |||
| .ztree li span.button.bottom_docu{background-position: -84px -42px;} | |||
| .ztree li span.button.noline_docu{ background:none;} | |||
| .ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.edit:hover { | |||
| background-position: -168px -21px; | |||
| } | |||
| .ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.remove:hover { | |||
| background-position: -168px -42px; | |||
| } | |||
| .ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.add:hover { | |||
| background-position: -168px 0; | |||
| } | |||
| .ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||
| ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||
| span.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||
| background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||
| background-position:-168px -84px; background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")} | |||
| ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} | |||
| .ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} | |||
| @@ -0,0 +1,99 @@ | |||
| /*------------------------------------- | |||
| zTree Style | |||
| version: 3.5.19 | |||
| author: Hunter.z | |||
| email: hunter.z@263.net | |||
| website: http://code.google.com/p/jquerytree/ | |||
| -------------------------------------*/ | |||
| .ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} | |||
| .ztree {margin:0; padding:5px; color:#333;margin-top: 0; height: 100%; max-height: 400px; overflow-y: scroll;} | |||
| .ztree::-webkit-scrollbar-track{background-color: #FFF;} | |||
| .ztree li{padding:5px 0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0; position: relative;} | |||
| .ztree li ul{ margin:0; padding:0 0 0 18px} | |||
| /*.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}*/ | |||
| .ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent; | |||
| text-decoration:none; vertical-align:top; display: inline-block} | |||
| .ztree li a:hover {text-decoration:none;} | |||
| .ztree li a:hover .node_name::after{content: '';position: absolute;left: 0;right: 0;top: 0;background-color: #f7f7f7;height: 100%;z-index: -1;} | |||
| .ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} | |||
| .ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} | |||
| .ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid; | |||
| opacity:0.8; filter:alpha(opacity=80)} | |||
| .ztree li a.tmpTargetNode_prev {} | |||
| .ztree li a.tmpTargetNode_next {} | |||
| .ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; | |||
| font-size:12px; border:1px #7EC4CC solid; *border:0px} | |||
| .ztree li span {line-height:16px; margin-right:2px} | |||
| .ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle; | |||
| border:0 none; cursor: pointer;outline:none; | |||
| background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||
| background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} | |||
| .ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto} | |||
| .ztree li span.button.chk.checkbox_false_full {background-position:0 0} | |||
| .ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px} | |||
| .ztree li span.button.chk.checkbox_false_part {background-position:0 -28px} | |||
| .ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px} | |||
| .ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px} | |||
| .ztree li span.button.chk.checkbox_true_full {background-position:-14px 0} | |||
| .ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px} | |||
| .ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px} | |||
| .ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px} | |||
| .ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px} | |||
| .ztree li span.button.chk.radio_false_full {background-position:-28px 0} | |||
| .ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px} | |||
| .ztree li span.button.chk.radio_false_part {background-position:-28px -28px} | |||
| .ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px} | |||
| .ztree li span.button.chk.radio_false_disable {background-position:-28px -56px} | |||
| .ztree li span.button.chk.radio_true_full {background-position:-42px 0} | |||
| .ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px} | |||
| .ztree li span.button.chk.radio_true_part {background-position:-42px -28px} | |||
| .ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px} | |||
| .ztree li span.button.chk.radio_true_disable {background-position:-42px -56px} | |||
| .ztree li span.button.switch {width:18px; height:18px} | |||
| .ztree li span.button.root_open{background-position:-92px -54px} | |||
| .ztree li span.button.root_close{background-position:-74px -54px} | |||
| .ztree li span.button.roots_open{background-position:-92px 0} | |||
| .ztree li span.button.roots_close{background-position:-74px 0} | |||
| .ztree li span.button.center_open{background-position:-92px -18px} | |||
| .ztree li span.button.center_close{background-position:-74px -18px} | |||
| .ztree li span.button.bottom_open{background-position:-92px -36px} | |||
| .ztree li span.button.bottom_close{background-position:-74px -36px} | |||
| .ztree li span.button.noline_open{background-position:-92px -72px} | |||
| .ztree li span.button.noline_close{background-position:-74px -72px} | |||
| .ztree li span.button.root_docu{ background:none;} | |||
| .ztree li span.button.roots_docu{background-position:-56px 0} | |||
| .ztree li span.button.center_docu{background-position:-56px -18px} | |||
| .ztree li span.button.bottom_docu{background-position:-56px -36px} | |||
| .ztree li span.button.noline_docu{ background:none;} | |||
| .ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle} | |||
| .ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} | |||
| ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} | |||
| span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; | |||
| background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; | |||
| background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} | |||
| ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} | |||
| .zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} | |||
| /* level style*/ | |||
| /*.ztree li span.button.level0 { | |||
| display:none; | |||
| } | |||
| .ztree li ul.level0 { | |||
| padding:0; | |||
| background:none; | |||
| }*/ | |||
| @@ -0,0 +1,167 @@ | |||
| /*! | |||
| * jQuery JavaScript Library v1.4.4 | |||
| * http://jquery.com/ | |||
| * | |||
| * Copyright 2010, John Resig | |||
| * Dual licensed under the MIT or GPL Version 2 licenses. | |||
| * http://jquery.org/license | |||
| * | |||
| * Includes Sizzle.js | |||
| * http://sizzlejs.com/ | |||
| * Copyright 2010, The Dojo Foundation | |||
| * Released under the MIT, BSD, and GPL Licenses. | |||
| * | |||
| * Date: Thu Nov 11 19:04:53 2010 -0500 | |||
| */ | |||
| (function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= | |||
| h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"|| | |||
| h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, | |||
| "`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, | |||
| e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, | |||
| "margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ | |||
| a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, | |||
| C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, | |||
| s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, | |||
| j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, | |||
| toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== | |||
| -1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; | |||
| if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--; | |||
| if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", | |||
| b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& | |||
| !F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& | |||
| l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z], | |||
| z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j, | |||
| s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v= | |||
| s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)|| | |||
| [];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u, | |||
| false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), | |||
| k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, | |||
| scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= | |||
| false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= | |||
| 1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= | |||
| "none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= | |||
| c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); | |||
| else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this, | |||
| a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e= | |||
| c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this, | |||
| a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan", | |||
| colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType=== | |||
| 1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "), | |||
| l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this, | |||
| "__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; | |||
| if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r= | |||
| a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, | |||
| attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& | |||
| b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; | |||
| c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, | |||
| arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= | |||
| d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ | |||
| c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b= | |||
| w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== | |||
| 8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== | |||
| "click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ | |||
| d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), | |||
| fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| | |||
| d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this, | |||
| Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp= | |||
| c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U}; | |||
| var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!== | |||
| "form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V, | |||
| xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= | |||
| B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== | |||
| "file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== | |||
| 0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d, | |||
| a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d= | |||
| 1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d=== | |||
| "object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}}); | |||
| c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); | |||
| (function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i, | |||
| [y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; | |||
| break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, | |||
| q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= | |||
| l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*")); | |||
| return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!== | |||
| B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/, | |||
| POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()=== | |||
| i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m= | |||
| i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g, | |||
| "")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, | |||
| m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== | |||
| true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== | |||
| g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]- | |||
| 0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n=== | |||
| "first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== | |||
| i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; | |||
| if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, | |||
| g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1; | |||
| for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"), | |||
| i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); | |||
| n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& | |||
| function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| | |||
| p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= | |||
| t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? | |||
| function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML; | |||
| c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})}, | |||
| not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= | |||
| h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): | |||
| c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, | |||
| 2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, | |||
| b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& | |||
| e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1, | |||
| "<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= | |||
| c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, | |||
| wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, | |||
| prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, | |||
| this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); | |||
| return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; | |||
| else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d= | |||
| c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a, | |||
| b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")): | |||
| this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", | |||
| prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| | |||
| b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length- | |||
| 1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); | |||
| d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, | |||
| jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, | |||
| zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), | |||
| h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); | |||
| if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= | |||
| d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; | |||
| e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, | |||
| ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== | |||
| "object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& | |||
| !this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, | |||
| getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", | |||
| script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| | |||
| !T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= | |||
| false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; | |||
| A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", | |||
| b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& | |||
| c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| | |||
| c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= | |||
| encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", | |||
| [b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), | |||
| e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); | |||
| if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", | |||
| 3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay", | |||
| d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b, | |||
| d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)=== | |||
| "inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L|| | |||
| 1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, | |||
| d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* | |||
| Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} | |||
| var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; | |||
| this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| | |||
| this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= | |||
| c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a=== | |||
| b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&& | |||
| h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle; | |||
| for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+= | |||
| parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px", | |||
| height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells= | |||
| f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a, | |||
| "marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, | |||
| e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& | |||
| c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); | |||
| c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ | |||
| b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); | |||
| @@ -0,0 +1,652 @@ | |||
| /* | |||
| * JQuery zTree excheck | |||
| * v3.5.48 | |||
| * http://treejs.cn/ | |||
| * | |||
| * Copyright (c) 2010 Hunter.z | |||
| * | |||
| * Licensed same as jquery - MIT License | |||
| * http://www.opensource.org/licenses/mit-license.php | |||
| * | |||
| * Date: 2020-11-21 | |||
| */ | |||
| (function ($) { | |||
| //default consts of excheck | |||
| var _consts = { | |||
| event: { | |||
| CHECK: "ztree_check" | |||
| }, | |||
| id: { | |||
| CHECK: "_check" | |||
| }, | |||
| checkbox: { | |||
| STYLE: "checkbox", | |||
| DEFAULT: "chk", | |||
| DISABLED: "disable", | |||
| FALSE: "false", | |||
| TRUE: "true", | |||
| FULL: "full", | |||
| PART: "part", | |||
| FOCUS: "focus" | |||
| }, | |||
| radio: { | |||
| STYLE: "radio", | |||
| TYPE_ALL: "all", | |||
| TYPE_LEVEL: "level" | |||
| } | |||
| }, | |||
| //default setting of excheck | |||
| _setting = { | |||
| check: { | |||
| enable: false, | |||
| autoCheckTrigger: false, | |||
| chkStyle: _consts.checkbox.STYLE, | |||
| nocheckInherit: false, | |||
| chkDisabledInherit: false, | |||
| radioType: _consts.radio.TYPE_LEVEL, | |||
| chkboxType: { | |||
| "Y": "ps", | |||
| "N": "ps" | |||
| } | |||
| }, | |||
| data: { | |||
| key: { | |||
| checked: "checked" | |||
| } | |||
| }, | |||
| callback: { | |||
| beforeCheck: null, | |||
| onCheck: null | |||
| } | |||
| }, | |||
| //default root of excheck | |||
| _initRoot = function (setting) { | |||
| var r = data.getRoot(setting); | |||
| r.radioCheckedList = []; | |||
| }, | |||
| //default cache of excheck | |||
| _initCache = function (treeId) { | |||
| }, | |||
| //default bind event of excheck | |||
| _bindEvent = function (setting) { | |||
| var o = setting.treeObj, | |||
| c = consts.event; | |||
| o.bind(c.CHECK, function (event, srcEvent, treeId, node) { | |||
| event.srcEvent = srcEvent; | |||
| tools.apply(setting.callback.onCheck, [event, treeId, node]); | |||
| }); | |||
| }, | |||
| _unbindEvent = function (setting) { | |||
| var o = setting.treeObj, | |||
| c = consts.event; | |||
| o.unbind(c.CHECK); | |||
| }, | |||
| //default event proxy of excheck | |||
| _eventProxy = function (e) { | |||
| var target = e.target, | |||
| setting = data.getSetting(e.data.treeId), | |||
| tId = "", node = null, | |||
| nodeEventType = "", treeEventType = "", | |||
| nodeEventCallback = null, treeEventCallback = null; | |||
| if (tools.eqs(e.type, "mouseover")) { | |||
| if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||
| tId = tools.getNodeMainDom(target).id; | |||
| nodeEventType = "mouseoverCheck"; | |||
| } | |||
| } else if (tools.eqs(e.type, "mouseout")) { | |||
| if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||
| tId = tools.getNodeMainDom(target).id; | |||
| nodeEventType = "mouseoutCheck"; | |||
| } | |||
| } else if (tools.eqs(e.type, "click")) { | |||
| if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) { | |||
| tId = tools.getNodeMainDom(target).id; | |||
| nodeEventType = "checkNode"; | |||
| } | |||
| } | |||
| if (tId.length > 0) { | |||
| node = data.getNodeCache(setting, tId); | |||
| switch (nodeEventType) { | |||
| case "checkNode" : | |||
| nodeEventCallback = _handler.onCheckNode; | |||
| break; | |||
| case "mouseoverCheck" : | |||
| nodeEventCallback = _handler.onMouseoverCheck; | |||
| break; | |||
| case "mouseoutCheck" : | |||
| nodeEventCallback = _handler.onMouseoutCheck; | |||
| break; | |||
| } | |||
| } | |||
| var proxyResult = { | |||
| stop: nodeEventType === "checkNode", | |||
| node: node, | |||
| nodeEventType: nodeEventType, | |||
| nodeEventCallback: nodeEventCallback, | |||
| treeEventType: treeEventType, | |||
| treeEventCallback: treeEventCallback | |||
| }; | |||
| return proxyResult | |||
| }, | |||
| //default init node of excheck | |||
| _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { | |||
| if (!n) return; | |||
| var checked = data.nodeChecked(setting, n); | |||
| n.checkedOld = checked; | |||
| if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true"); | |||
| n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck); | |||
| if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true"); | |||
| n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled); | |||
| if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true"); | |||
| n.halfCheck = !!n.halfCheck; | |||
| n.check_Child_State = -1; | |||
| n.check_Focus = false; | |||
| n.getCheckStatus = function () { | |||
| return data.getCheckStatus(setting, n); | |||
| }; | |||
| if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && checked) { | |||
| var r = data.getRoot(setting); | |||
| r.radioCheckedList.push(n); | |||
| } | |||
| }, | |||
| //add dom for check | |||
| _beforeA = function (setting, node, html) { | |||
| if (setting.check.enable) { | |||
| data.makeChkFlag(setting, node); | |||
| html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true ? " style='display:none;'" : ""), "></span>"); | |||
| } | |||
| }, | |||
| //update zTreeObj, add method of check | |||
| _zTreeTools = function (setting, zTreeTools) { | |||
| zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) { | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| if (node.chkDisabled === true) return; | |||
| if (checked !== true && checked !== false) { | |||
| checked = !nodeChecked; | |||
| } | |||
| callbackFlag = !!callbackFlag; | |||
| if (nodeChecked === checked && !checkTypeFlag) { | |||
| return; | |||
| } else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) { | |||
| return; | |||
| } | |||
| if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) { | |||
| data.nodeChecked(setting, node, checked); | |||
| var checkObj = $$(node, consts.id.CHECK, this.setting); | |||
| if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); | |||
| view.setChkClass(this.setting, checkObj, node); | |||
| view.repairParentChkClassWithSelf(this.setting, node); | |||
| if (callbackFlag) { | |||
| this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]); | |||
| } | |||
| } | |||
| } | |||
| zTreeTools.checkAllNodes = function (checked) { | |||
| view.repairAllChk(this.setting, !!checked); | |||
| } | |||
| zTreeTools.getCheckedNodes = function (checked) { | |||
| checked = (checked !== false); | |||
| var children = data.nodeChildren(setting, data.getRoot(this.setting)); | |||
| return data.getTreeCheckedNodes(this.setting, children, checked); | |||
| } | |||
| zTreeTools.getChangeCheckedNodes = function () { | |||
| var children = data.nodeChildren(setting, data.getRoot(this.setting)); | |||
| return data.getTreeChangeCheckedNodes(this.setting, children); | |||
| } | |||
| zTreeTools.setChkDisabled = function (node, disabled, inheritParent, inheritChildren) { | |||
| disabled = !!disabled; | |||
| inheritParent = !!inheritParent; | |||
| inheritChildren = !!inheritChildren; | |||
| view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren); | |||
| view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent); | |||
| } | |||
| var _updateNode = zTreeTools.updateNode; | |||
| zTreeTools.updateNode = function (node, checkTypeFlag) { | |||
| if (_updateNode) _updateNode.apply(zTreeTools, arguments); | |||
| if (!node || !this.setting.check.enable) return; | |||
| var nObj = $$(node, this.setting); | |||
| if (nObj.get(0) && tools.uCanDo(this.setting)) { | |||
| var checkObj = $$(node, consts.id.CHECK, this.setting); | |||
| if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); | |||
| view.setChkClass(this.setting, checkObj, node); | |||
| view.repairParentChkClassWithSelf(this.setting, node); | |||
| } | |||
| } | |||
| }, | |||
| //method of operate data | |||
| _data = { | |||
| getRadioCheckedList: function (setting) { | |||
| var checkedList = data.getRoot(setting).radioCheckedList; | |||
| for (var i = 0, j = checkedList.length; i < j; i++) { | |||
| if (!data.getNodeCache(setting, checkedList[i].tId)) { | |||
| checkedList.splice(i, 1); | |||
| i--; | |||
| j--; | |||
| } | |||
| } | |||
| return checkedList; | |||
| }, | |||
| getCheckStatus: function (setting, node) { | |||
| if (!setting.check.enable || node.nocheck || node.chkDisabled) return null; | |||
| var checked = data.nodeChecked(setting, node), | |||
| r = { | |||
| checked: checked, | |||
| half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (checked ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0))) | |||
| }; | |||
| return r; | |||
| }, | |||
| getTreeCheckedNodes: function (setting, nodes, checked, results) { | |||
| if (!nodes) return []; | |||
| var onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL); | |||
| results = !results ? [] : results; | |||
| for (var i = 0, l = nodes.length; i < l; i++) { | |||
| var node = nodes[i]; | |||
| var children = data.nodeChildren(setting, node); | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked == checked) { | |||
| results.push(node); | |||
| if (onlyOne) { | |||
| break; | |||
| } | |||
| } | |||
| data.getTreeCheckedNodes(setting, children, checked, results); | |||
| if (onlyOne && results.length > 0) { | |||
| break; | |||
| } | |||
| } | |||
| return results; | |||
| }, | |||
| getTreeChangeCheckedNodes: function (setting, nodes, results) { | |||
| if (!nodes) return []; | |||
| results = !results ? [] : results; | |||
| for (var i = 0, l = nodes.length; i < l; i++) { | |||
| var node = nodes[i]; | |||
| var children = data.nodeChildren(setting, node); | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked != node.checkedOld) { | |||
| results.push(node); | |||
| } | |||
| data.getTreeChangeCheckedNodes(setting, children, results); | |||
| } | |||
| return results; | |||
| }, | |||
| makeChkFlag: function (setting, node) { | |||
| if (!node) return; | |||
| var chkFlag = -1; | |||
| var children = data.nodeChildren(setting, node); | |||
| if (children) { | |||
| for (var i = 0, l = children.length; i < l; i++) { | |||
| var cNode = children[i]; | |||
| var nodeChecked = data.nodeChecked(setting, cNode); | |||
| var tmp = -1; | |||
| if (setting.check.chkStyle == consts.radio.STYLE) { | |||
| if (cNode.nocheck === true || cNode.chkDisabled === true) { | |||
| tmp = cNode.check_Child_State; | |||
| } else if (cNode.halfCheck === true) { | |||
| tmp = 2; | |||
| } else if (nodeChecked) { | |||
| tmp = 2; | |||
| } else { | |||
| tmp = cNode.check_Child_State > 0 ? 2 : 0; | |||
| } | |||
| if (tmp == 2) { | |||
| chkFlag = 2; | |||
| break; | |||
| } else if (tmp == 0) { | |||
| chkFlag = 0; | |||
| } | |||
| } else if (setting.check.chkStyle == consts.checkbox.STYLE) { | |||
| if (cNode.nocheck === true || cNode.chkDisabled === true) { | |||
| tmp = cNode.check_Child_State; | |||
| } else if (cNode.halfCheck === true) { | |||
| tmp = 1; | |||
| } else if (nodeChecked) { | |||
| tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1; | |||
| } else { | |||
| tmp = (cNode.check_Child_State > 0) ? 1 : 0; | |||
| } | |||
| if (tmp === 1) { | |||
| chkFlag = 1; | |||
| break; | |||
| } else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) { | |||
| chkFlag = 1; | |||
| break; | |||
| } else if (chkFlag === 2 && tmp > -1 && tmp < 2) { | |||
| chkFlag = 1; | |||
| break; | |||
| } else if (tmp > -1) { | |||
| chkFlag = tmp; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| node.check_Child_State = chkFlag; | |||
| } | |||
| }, | |||
| //method of event proxy | |||
| _event = {}, | |||
| //method of event handler | |||
| _handler = { | |||
| onCheckNode: function (event, node) { | |||
| if (node.chkDisabled === true) return false; | |||
| var setting = data.getSetting(event.data.treeId); | |||
| if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true; | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| data.nodeChecked(setting, node, !nodeChecked); | |||
| view.checkNodeRelation(setting, node); | |||
| var checkObj = $$(node, consts.id.CHECK, setting); | |||
| view.setChkClass(setting, checkObj, node); | |||
| view.repairParentChkClassWithSelf(setting, node); | |||
| setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]); | |||
| return true; | |||
| }, | |||
| onMouseoverCheck: function (event, node) { | |||
| if (node.chkDisabled === true) return false; | |||
| var setting = data.getSetting(event.data.treeId), | |||
| checkObj = $$(node, consts.id.CHECK, setting); | |||
| node.check_Focus = true; | |||
| view.setChkClass(setting, checkObj, node); | |||
| return true; | |||
| }, | |||
| onMouseoutCheck: function (event, node) { | |||
| if (node.chkDisabled === true) return false; | |||
| var setting = data.getSetting(event.data.treeId), | |||
| checkObj = $$(node, consts.id.CHECK, setting); | |||
| node.check_Focus = false; | |||
| view.setChkClass(setting, checkObj, node); | |||
| return true; | |||
| } | |||
| }, | |||
| //method of tools for zTree | |||
| _tools = {}, | |||
| //method of operate ztree dom | |||
| _view = { | |||
| checkNodeRelation: function (setting, node) { | |||
| var pNode, i, l, | |||
| r = consts.radio; | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| if (setting.check.chkStyle == r.STYLE) { | |||
| var checkedList = data.getRadioCheckedList(setting); | |||
| if (nodeChecked) { | |||
| if (setting.check.radioType == r.TYPE_ALL) { | |||
| for (i = checkedList.length - 1; i >= 0; i--) { | |||
| pNode = checkedList[i]; | |||
| var pNodeChecked = data.nodeChecked(setting, pNode); | |||
| if (pNodeChecked && pNode != node) { | |||
| data.nodeChecked(setting, pNode, false); | |||
| checkedList.splice(i, 1); | |||
| view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); | |||
| if (pNode.parentTId != node.parentTId) { | |||
| view.repairParentChkClassWithSelf(setting, pNode); | |||
| } | |||
| } | |||
| } | |||
| checkedList.push(node); | |||
| } else { | |||
| var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); | |||
| var children = data.nodeChildren(setting, parentNode); | |||
| for (i = 0, l = children.length; i < l; i++) { | |||
| pNode = children[i]; | |||
| var pNodeChecked = data.nodeChecked(setting, pNode); | |||
| if (pNodeChecked && pNode != node) { | |||
| data.nodeChecked(setting, pNode, false); | |||
| view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); | |||
| } | |||
| } | |||
| } | |||
| } else if (setting.check.radioType == r.TYPE_ALL) { | |||
| for (i = 0, l = checkedList.length; i < l; i++) { | |||
| if (node == checkedList[i]) { | |||
| checkedList.splice(i, 1); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| var children = data.nodeChildren(setting, node); | |||
| if (nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.Y.indexOf("s") > -1)) { | |||
| view.setSonNodeCheckBox(setting, node, true); | |||
| } | |||
| if (!nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.N.indexOf("s") > -1)) { | |||
| view.setSonNodeCheckBox(setting, node, false); | |||
| } | |||
| if (nodeChecked && setting.check.chkboxType.Y.indexOf("p") > -1) { | |||
| view.setParentNodeCheckBox(setting, node, true); | |||
| } | |||
| if (!nodeChecked && setting.check.chkboxType.N.indexOf("p") > -1) { | |||
| view.setParentNodeCheckBox(setting, node, false); | |||
| } | |||
| } | |||
| }, | |||
| makeChkClass: function (setting, node) { | |||
| var c = consts.checkbox, r = consts.radio, | |||
| fullStyle = ""; | |||
| var nodeChecked = data.nodeChecked(setting, node); | |||
| if (node.chkDisabled === true) { | |||
| fullStyle = c.DISABLED; | |||
| } else if (node.halfCheck) { | |||
| fullStyle = c.PART; | |||
| } else if (setting.check.chkStyle == r.STYLE) { | |||
| fullStyle = (node.check_Child_State < 1) ? c.FULL : c.PART; | |||
| } else { | |||
| fullStyle = nodeChecked ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL : c.PART) : ((node.check_Child_State < 1) ? c.FULL : c.PART); | |||
| } | |||
| var chkName = setting.check.chkStyle + "_" + (nodeChecked ? c.TRUE : c.FALSE) + "_" + fullStyle; | |||
| chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; | |||
| return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName; | |||
| }, | |||
| repairAllChk: function (setting, checked) { | |||
| if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) { | |||
| var root = data.getRoot(setting); | |||
| var children = data.nodeChildren(setting, root); | |||
| for (var i = 0, l = children.length; i < l; i++) { | |||
| var node = children[i]; | |||
| if (node.nocheck !== true && node.chkDisabled !== true) { | |||
| data.nodeChecked(setting, node, checked); | |||
| } | |||
| view.setSonNodeCheckBox(setting, node, checked); | |||
| } | |||
| } | |||
| }, | |||
| repairChkClass: function (setting, node) { | |||
| if (!node) return; | |||
| data.makeChkFlag(setting, node); | |||
| if (node.nocheck !== true) { | |||
| var checkObj = $$(node, consts.id.CHECK, setting); | |||
| view.setChkClass(setting, checkObj, node); | |||
| } | |||
| }, | |||
| repairParentChkClass: function (setting, node) { | |||
| if (!node || !node.parentTId) return; | |||
| var pNode = node.getParentNode(); | |||
| view.repairChkClass(setting, pNode); | |||
| view.repairParentChkClass(setting, pNode); | |||
| }, | |||
| repairParentChkClassWithSelf: function (setting, node) { | |||
| if (!node) return; | |||
| var children = data.nodeChildren(setting, node); | |||
| if (children && children.length > 0) { | |||
| view.repairParentChkClass(setting, children[0]); | |||
| } else { | |||
| view.repairParentChkClass(setting, node); | |||
| } | |||
| }, | |||
| repairSonChkDisabled: function (setting, node, chkDisabled, inherit) { | |||
| if (!node) return; | |||
| if (node.chkDisabled != chkDisabled) { | |||
| node.chkDisabled = chkDisabled; | |||
| } | |||
| view.repairChkClass(setting, node); | |||
| var children = data.nodeChildren(setting, node); | |||
| if (children && inherit) { | |||
| for (var i = 0, l = children.length; i < l; i++) { | |||
| var sNode = children[i]; | |||
| view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit); | |||
| } | |||
| } | |||
| }, | |||
| repairParentChkDisabled: function (setting, node, chkDisabled, inherit) { | |||
| if (!node) return; | |||
| if (node.chkDisabled != chkDisabled && inherit) { | |||
| node.chkDisabled = chkDisabled; | |||
| } | |||
| view.repairChkClass(setting, node); | |||
| view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit); | |||
| }, | |||
| setChkClass: function (setting, obj, node) { | |||
| if (!obj) return; | |||
| if (node.nocheck === true) { | |||
| obj.hide(); | |||
| } else { | |||
| obj.show(); | |||
| } | |||
| obj.attr('class', view.makeChkClass(setting, node)); | |||
| }, | |||
| setParentNodeCheckBox: function (setting, node, value, srcNode) { | |||
| var checkObj = $$(node, consts.id.CHECK, setting); | |||
| if (!srcNode) srcNode = node; | |||
| data.makeChkFlag(setting, node); | |||
| if (node.nocheck !== true && node.chkDisabled !== true) { | |||
| data.nodeChecked(setting, node, value); | |||
| view.setChkClass(setting, checkObj, node); | |||
| if (setting.check.autoCheckTrigger && node != srcNode) { | |||
| setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); | |||
| } | |||
| } | |||
| if (node.parentTId) { | |||
| var pSign = true; | |||
| if (!value) { | |||
| var pNodes = data.nodeChildren(setting, node.getParentNode()); | |||
| for (var i = 0, l = pNodes.length; i < l; i++) { | |||
| var pNode = pNodes[i]; | |||
| var nodeChecked = data.nodeChecked(setting, pNode); | |||
| if ((pNode.nocheck !== true && pNode.chkDisabled !== true && nodeChecked) | |||
| || ((pNode.nocheck === true || pNode.chkDisabled === true) && pNode.check_Child_State > 0)) { | |||
| pSign = false; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (pSign) { | |||
| view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode); | |||
| } | |||
| } | |||
| }, | |||
| setSonNodeCheckBox: function (setting, node, value, srcNode) { | |||
| if (!node) return; | |||
| var checkObj = $$(node, consts.id.CHECK, setting); | |||
| if (!srcNode) srcNode = node; | |||
| var hasDisable = false; | |||
| var children = data.nodeChildren(setting, node); | |||
| if (children) { | |||
| for (var i = 0, l = children.length; i < l; i++) { | |||
| var sNode = children[i]; | |||
| view.setSonNodeCheckBox(setting, sNode, value, srcNode); | |||
| if (sNode.chkDisabled === true) hasDisable = true; | |||
| } | |||
| } | |||
| if (node != data.getRoot(setting) && node.chkDisabled !== true) { | |||
| if (hasDisable && node.nocheck !== true) { | |||
| data.makeChkFlag(setting, node); | |||
| } | |||
| if (node.nocheck !== true && node.chkDisabled !== true) { | |||
| data.nodeChecked(setting, node, value); | |||
| if (!hasDisable) node.check_Child_State = (children && children.length > 0) ? (value ? 2 : 0) : -1; | |||
| } else { | |||
| node.check_Child_State = -1; | |||
| } | |||
| view.setChkClass(setting, checkObj, node); | |||
| if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) { | |||
| setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| _z = { | |||
| tools: _tools, | |||
| view: _view, | |||
| event: _event, | |||
| data: _data | |||
| }; | |||
| $.extend(true, $.fn.zTree.consts, _consts); | |||
| $.extend(true, $.fn.zTree._z, _z); | |||
| var zt = $.fn.zTree, | |||
| tools = zt._z.tools, | |||
| consts = zt.consts, | |||
| view = zt._z.view, | |||
| data = zt._z.data, | |||
| event = zt._z.event, | |||
| $$ = tools.$; | |||
| data.nodeChecked = function (setting, node, newChecked) { | |||
| if (!node) { | |||
| return false; | |||
| } | |||
| var key = setting.data.key.checked; | |||
| if (typeof newChecked !== 'undefined') { | |||
| if (typeof newChecked === "string") { | |||
| newChecked = tools.eqs(newChecked, "true"); | |||
| } | |||
| newChecked = !!newChecked; | |||
| node[key] = newChecked; | |||
| } else if (typeof node[key] == "string"){ | |||
| node[key] = tools.eqs(node[key], "true"); | |||
| } else { | |||
| node[key] = !!node[key]; | |||
| } | |||
| return node[key]; | |||
| }; | |||
| data.exSetting(_setting); | |||
| data.addInitBind(_bindEvent); | |||
| data.addInitUnBind(_unbindEvent); | |||
| data.addInitCache(_initCache); | |||
| data.addInitNode(_initNode); | |||
| data.addInitProxy(_eventProxy, true); | |||
| data.addInitRoot(_initRoot); | |||
| data.addBeforeA(_beforeA); | |||
| data.addZTreeTools(_zTreeTools); | |||
| var _createNodes = view.createNodes; | |||
| view.createNodes = function (setting, level, nodes, parentNode, index) { | |||
| if (_createNodes) _createNodes.apply(view, arguments); | |||
| if (!nodes) return; | |||
| view.repairParentChkClassWithSelf(setting, parentNode); | |||
| } | |||
| var _removeNode = view.removeNode; | |||
| view.removeNode = function (setting, node) { | |||
| var parentNode = node.getParentNode(); | |||
| if (_removeNode) _removeNode.apply(view, arguments); | |||
| if (!node || !parentNode) return; | |||
| view.repairChkClass(setting, parentNode); | |||
| view.repairParentChkClass(setting, parentNode); | |||
| } | |||
| var _appendNodes = view.appendNodes; | |||
| view.appendNodes = function (setting, level, nodes, parentNode, index, initFlag, openFlag) { | |||
| var html = ""; | |||
| if (_appendNodes) { | |||
| html = _appendNodes.apply(view, arguments); | |||
| } | |||
| if (parentNode) { | |||
| data.makeChkFlag(setting, parentNode); | |||
| } | |||
| return html; | |||
| } | |||
| })(jQuery); | |||
| @@ -0,0 +1,405 @@ | |||
| /* | |||
| * JQuery zTree exHideNodes | |||
| * v3.5.48 | |||
| * http://treejs.cn/ | |||
| * | |||
| * Copyright (c) 2010 Hunter.z | |||
| * | |||
| * Licensed same as jquery - MIT License | |||
| * http://www.opensource.org/licenses/mit-license.php | |||
| * | |||
| * Date: 2020-11-21 | |||
| */ | |||
| (function ($) { | |||
| var _setting = { | |||
| data: { | |||
| key: { | |||
| isHidden: "isHidden" | |||
| } | |||
| } | |||
| }; | |||
| //default init node of exLib | |||
| var _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { | |||
| var isHidden = data.isHidden(setting, n); | |||
| data.isHidden(setting, n, isHidden); | |||
| data.initHideForExCheck(setting, n); | |||
| }, | |||
| //add dom for check | |||
| _beforeA = function (setting, node, html) { | |||
| }, | |||
| //update zTreeObj, add method of exLib | |||
| _zTreeTools = function (setting, zTreeTools) { | |||
| zTreeTools.showNodes = function (nodes, options) { | |||
| view.showNodes(setting, nodes, options); | |||
| } | |||
| zTreeTools.showNode = function (node, options) { | |||
| if (!node) { | |||
| return; | |||
| } | |||
| view.showNodes(setting, [node], options); | |||
| } | |||
| zTreeTools.hideNodes = function (nodes, options) { | |||
| view.hideNodes(setting, nodes, options); | |||
| } | |||
| zTreeTools.hideNode = function (node, options) { | |||
| if (!node) { | |||
| return; | |||
| } | |||
| view.hideNodes(setting, [node], options); | |||
| } | |||
| var _checkNode = zTreeTools.checkNode; | |||
| if (_checkNode) { | |||
| zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) { | |||
| if (!!node && !!data.isHidden(setting, node)) { | |||
| return; | |||
| } | |||
| _checkNode.apply(zTreeTools, arguments); | |||
| } | |||
| } | |||
| }, | |||
| //method of operate data | |||
| _data = { | |||
| initHideForExCheck: function (setting, n) { | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (isHidden && setting.check && setting.check.enable) { | |||
| if (typeof n._nocheck == "undefined") { | |||
| n._nocheck = !!n.nocheck | |||
| n.nocheck = true; | |||
| } | |||
| n.check_Child_State = -1; | |||
| if (view.repairParentChkClassWithSelf) { | |||
| view.repairParentChkClassWithSelf(setting, n); | |||
| } | |||
| } | |||
| }, | |||
| initShowForExCheck: function (setting, n) { | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (!isHidden && setting.check && setting.check.enable) { | |||
| if (typeof n._nocheck != "undefined") { | |||
| n.nocheck = n._nocheck; | |||
| delete n._nocheck; | |||
| } | |||
| if (view.setChkClass) { | |||
| var checkObj = $$(n, consts.id.CHECK, setting); | |||
| view.setChkClass(setting, checkObj, n); | |||
| } | |||
| if (view.repairParentChkClassWithSelf) { | |||
| view.repairParentChkClassWithSelf(setting, n); | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| //method of operate ztree dom | |||
| _view = { | |||
| clearOldFirstNode: function (setting, node) { | |||
| var n = node.getNextNode(); | |||
| while (!!n) { | |||
| if (n.isFirstNode) { | |||
| n.isFirstNode = false; | |||
| view.setNodeLineIcos(setting, n); | |||
| break; | |||
| } | |||
| if (n.isLastNode) { | |||
| break; | |||
| } | |||
| n = n.getNextNode(); | |||
| } | |||
| }, | |||
| clearOldLastNode: function (setting, node, openFlag) { | |||
| var n = node.getPreNode(); | |||
| while (!!n) { | |||
| if (n.isLastNode) { | |||
| n.isLastNode = false; | |||
| if (openFlag) { | |||
| view.setNodeLineIcos(setting, n); | |||
| } | |||
| break; | |||
| } | |||
| if (n.isFirstNode) { | |||
| break; | |||
| } | |||
| n = n.getPreNode(); | |||
| } | |||
| }, | |||
| makeDOMNodeMainBefore: function (html, setting, node) { | |||
| var isHidden = data.isHidden(setting, node); | |||
| html.push("<li ", (isHidden ? "style='display:none;' " : ""), "id='", node.tId, "' class='", consts.className.LEVEL, node.level, "' tabindex='0' hidefocus='true' treenode>"); | |||
| }, | |||
| showNode: function (setting, node, options) { | |||
| data.isHidden(setting, node, false); | |||
| data.initShowForExCheck(setting, node); | |||
| $$(node, setting).show(); | |||
| }, | |||
| showNodes: function (setting, nodes, options) { | |||
| if (!nodes || nodes.length == 0) { | |||
| return; | |||
| } | |||
| var pList = {}, i, j; | |||
| for (i = 0, j = nodes.length; i < j; i++) { | |||
| var n = nodes[i]; | |||
| if (!pList[n.parentTId]) { | |||
| var pn = n.getParentNode(); | |||
| pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode(); | |||
| } | |||
| view.showNode(setting, n, options); | |||
| } | |||
| for (var tId in pList) { | |||
| var children = data.nodeChildren(setting, pList[tId]); | |||
| view.setFirstNodeForShow(setting, children); | |||
| view.setLastNodeForShow(setting, children); | |||
| } | |||
| }, | |||
| hideNode: function (setting, node, options) { | |||
| data.isHidden(setting, node, true); | |||
| node.isFirstNode = false; | |||
| node.isLastNode = false; | |||
| data.initHideForExCheck(setting, node); | |||
| view.cancelPreSelectedNode(setting, node); | |||
| $$(node, setting).hide(); | |||
| }, | |||
| hideNodes: function (setting, nodes, options) { | |||
| if (!nodes || nodes.length == 0) { | |||
| return; | |||
| } | |||
| var pList = {}, i, j; | |||
| for (i = 0, j = nodes.length; i < j; i++) { | |||
| var n = nodes[i]; | |||
| if ((n.isFirstNode || n.isLastNode) && !pList[n.parentTId]) { | |||
| var pn = n.getParentNode(); | |||
| pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode(); | |||
| } | |||
| view.hideNode(setting, n, options); | |||
| } | |||
| for (var tId in pList) { | |||
| var children = data.nodeChildren(setting, pList[tId]); | |||
| view.setFirstNodeForHide(setting, children); | |||
| view.setLastNodeForHide(setting, children); | |||
| } | |||
| }, | |||
| setFirstNode: function (setting, parentNode) { | |||
| var children = data.nodeChildren(setting, parentNode); | |||
| var isHidden = data.isHidden(setting, children[0], false); | |||
| if (children.length > 0 && !isHidden) { | |||
| children[0].isFirstNode = true; | |||
| } else if (children.length > 0) { | |||
| view.setFirstNodeForHide(setting, children); | |||
| } | |||
| }, | |||
| setLastNode: function (setting, parentNode) { | |||
| var children = data.nodeChildren(setting, parentNode); | |||
| var isHidden = data.isHidden(setting, children[0]); | |||
| if (children.length > 0 && !isHidden) { | |||
| children[children.length - 1].isLastNode = true; | |||
| } else if (children.length > 0) { | |||
| view.setLastNodeForHide(setting, children); | |||
| } | |||
| }, | |||
| setFirstNodeForHide: function (setting, nodes) { | |||
| var n, i, j; | |||
| for (i = 0, j = nodes.length; i < j; i++) { | |||
| n = nodes[i]; | |||
| if (n.isFirstNode) { | |||
| break; | |||
| } | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (!isHidden && !n.isFirstNode) { | |||
| n.isFirstNode = true; | |||
| view.setNodeLineIcos(setting, n); | |||
| break; | |||
| } else { | |||
| n = null; | |||
| } | |||
| } | |||
| return n; | |||
| }, | |||
| setFirstNodeForShow: function (setting, nodes) { | |||
| var n, i, j, first, old; | |||
| for (i = 0, j = nodes.length; i < j; i++) { | |||
| n = nodes[i]; | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (!first && !isHidden && n.isFirstNode) { | |||
| first = n; | |||
| break; | |||
| } else if (!first && !isHidden && !n.isFirstNode) { | |||
| n.isFirstNode = true; | |||
| first = n; | |||
| view.setNodeLineIcos(setting, n); | |||
| } else if (first && n.isFirstNode) { | |||
| n.isFirstNode = false; | |||
| old = n; | |||
| view.setNodeLineIcos(setting, n); | |||
| break; | |||
| } else { | |||
| n = null; | |||
| } | |||
| } | |||
| return {"new": first, "old": old}; | |||
| }, | |||
| setLastNodeForHide: function (setting, nodes) { | |||
| var n, i; | |||
| for (i = nodes.length - 1; i >= 0; i--) { | |||
| n = nodes[i]; | |||
| if (n.isLastNode) { | |||
| break; | |||
| } | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (!isHidden && !n.isLastNode) { | |||
| n.isLastNode = true; | |||
| view.setNodeLineIcos(setting, n); | |||
| break; | |||
| } else { | |||
| n = null; | |||
| } | |||
| } | |||
| return n; | |||
| }, | |||
| setLastNodeForShow: function (setting, nodes) { | |||
| var n, i, j, last, old; | |||
| for (i = nodes.length - 1; i >= 0; i--) { | |||
| n = nodes[i]; | |||
| var isHidden = data.isHidden(setting, n); | |||
| if (!last && !isHidden && n.isLastNode) { | |||
| last = n; | |||
| break; | |||
| } else if (!last && !isHidden && !n.isLastNode) { | |||
| n.isLastNode = true; | |||
| last = n; | |||
| view.setNodeLineIcos(setting, n); | |||
| } else if (last && n.isLastNode) { | |||
| n.isLastNode = false; | |||
| old = n; | |||
| view.setNodeLineIcos(setting, n); | |||
| break; | |||
| } else { | |||
| n = null; | |||
| } | |||
| } | |||
| return {"new": last, "old": old}; | |||
| } | |||
| }, | |||
| _z = { | |||
| view: _view, | |||
| data: _data | |||
| }; | |||
| $.extend(true, $.fn.zTree._z, _z); | |||
| var zt = $.fn.zTree, | |||
| tools = zt._z.tools, | |||
| consts = zt.consts, | |||
| view = zt._z.view, | |||
| data = zt._z.data, | |||
| event = zt._z.event, | |||
| $$ = tools.$; | |||
| data.isHidden = function (setting, node, newIsHidden) { | |||
| if (!node) { | |||
| return false; | |||
| } | |||
| var key = setting.data.key.isHidden; | |||
| if (typeof newIsHidden !== 'undefined') { | |||
| if (typeof newIsHidden === "string") { | |||
| newIsHidden = tools.eqs(newIsHidden, "true"); | |||
| } | |||
| newIsHidden = !!newIsHidden; | |||
| node[key] = newIsHidden; | |||
| } else if (typeof node[key] == "string"){ | |||
| node[key] = tools.eqs(node[key], "true"); | |||
| } else { | |||
| node[key] = !!node[key]; | |||
| } | |||
| return node[key]; | |||
| }; | |||
| data.exSetting(_setting); | |||
| data.addInitNode(_initNode); | |||
| data.addBeforeA(_beforeA); | |||
| data.addZTreeTools(_zTreeTools); | |||
| // Override method in core | |||
| var _dInitNode = data.initNode; | |||
| data.initNode = function (setting, level, node, parentNode, isFirstNode, isLastNode, openFlag) { | |||
| var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting), | |||
| children = tmpPNode[setting.data.key.children]; | |||
| data.tmpHideFirstNode = view.setFirstNodeForHide(setting, children); | |||
| data.tmpHideLastNode = view.setLastNodeForHide(setting, children); | |||
| if (openFlag) { | |||
| view.setNodeLineIcos(setting, data.tmpHideFirstNode); | |||
| view.setNodeLineIcos(setting, data.tmpHideLastNode); | |||
| } | |||
| isFirstNode = (data.tmpHideFirstNode === node); | |||
| isLastNode = (data.tmpHideLastNode === node); | |||
| if (_dInitNode) _dInitNode.apply(data, arguments); | |||
| if (openFlag && isLastNode) { | |||
| view.clearOldLastNode(setting, node, openFlag); | |||
| } | |||
| }; | |||
| var _makeChkFlag = data.makeChkFlag; | |||
| if (!!_makeChkFlag) { | |||
| data.makeChkFlag = function (setting, node) { | |||
| if (!!node && !!data.isHidden(setting, node)) { | |||
| return; | |||
| } | |||
| _makeChkFlag.apply(data, arguments); | |||
| } | |||
| } | |||
| var _getTreeCheckedNodes = data.getTreeCheckedNodes; | |||
| if (!!_getTreeCheckedNodes) { | |||
| data.getTreeCheckedNodes = function (setting, nodes, checked, results) { | |||
| if (!!nodes && nodes.length > 0) { | |||
| var p = nodes[0].getParentNode(); | |||
| if (!!p && !!data.isHidden(setting, p)) { | |||
| return []; | |||
| } | |||
| } | |||
| return _getTreeCheckedNodes.apply(data, arguments); | |||
| } | |||
| } | |||
| var _getTreeChangeCheckedNodes = data.getTreeChangeCheckedNodes; | |||
| if (!!_getTreeChangeCheckedNodes) { | |||
| data.getTreeChangeCheckedNodes = function (setting, nodes, results) { | |||
| if (!!nodes && nodes.length > 0) { | |||
| var p = nodes[0].getParentNode(); | |||
| if (!!p && !!data.isHidden(setting, p)) { | |||
| return []; | |||
| } | |||
| } | |||
| return _getTreeChangeCheckedNodes.apply(data, arguments); | |||
| } | |||
| } | |||
| var _expandCollapseSonNode = view.expandCollapseSonNode; | |||
| if (!!_expandCollapseSonNode) { | |||
| view.expandCollapseSonNode = function (setting, node, expandFlag, animateFlag, callback) { | |||
| if (!!node && !!data.isHidden(setting, node)) { | |||
| return; | |||
| } | |||
| _expandCollapseSonNode.apply(view, arguments); | |||
| } | |||
| } | |||
| var _setSonNodeCheckBox = view.setSonNodeCheckBox; | |||
| if (!!_setSonNodeCheckBox) { | |||
| view.setSonNodeCheckBox = function (setting, node, value, srcNode) { | |||
| if (!!node && !!data.isHidden(setting, node)) { | |||
| return; | |||
| } | |||
| _setSonNodeCheckBox.apply(view, arguments); | |||
| } | |||
| } | |||
| var _repairParentChkClassWithSelf = view.repairParentChkClassWithSelf; | |||
| if (!!_repairParentChkClassWithSelf) { | |||
| view.repairParentChkClassWithSelf = function (setting, node) { | |||
| if (!!node && !!data.isHidden(setting, node)) { | |||
| return; | |||
| } | |||
| _repairParentChkClassWithSelf.apply(view, arguments); | |||
| } | |||
| } | |||
| })(jQuery); | |||
| @@ -10,6 +10,7 @@ import ( | |||
| "github.com/360EntSecGroup-Skylar/excelize/v2" | |||
| "code.gitea.io/gitea/modules/modelarts" | |||
| "code.gitea.io/gitea/routers/repo" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -34,10 +35,14 @@ func CloudBrains(ctx *context.Context) { | |||
| listType := ctx.Query("listType") | |||
| jobType := ctx.Query("jobType") | |||
| jobStatus := ctx.Query("jobStatus") | |||
| aiCenter := ctx.Query("aiCenter") | |||
| cluster := ctx.Query("cluster") | |||
| ctx.Data["ListType"] = listType | |||
| ctx.Data["JobType"] = jobType | |||
| ctx.Data["JobStatus"] = jobStatus | |||
| ctx.Data["aiCenter"] = aiCenter | |||
| ctx.Data["cluster"] = cluster | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| @@ -79,6 +84,8 @@ func CloudBrains(ctx *context.Context) { | |||
| IsLatestVersion: modelarts.IsLatestVersion, | |||
| ComputeResource: listType, | |||
| Type: models.TypeCloudBrainAll, | |||
| AiCenter: aiCenter, | |||
| Cluster: cluster, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Get job failed:", err) | |||
| @@ -89,6 +96,10 @@ func CloudBrains(ctx *context.Context) { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDel = true | |||
| ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource | |||
| ciTasks[i].Cloudbrain.AiCenter = repo.GetCloudbrainAiCenter(task.Cloudbrain, ctx) | |||
| _, cardType, _ := repo.GetCloudbrainCardNumAndType(task.Cloudbrain) | |||
| ciTasks[i].Cloudbrain.CardType = cardType | |||
| ciTasks[i].Cloudbrain.Cluster = repo.GetCloudbrainCluster(task.Cloudbrain, ctx) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, getTotalPage(count, setting.UI.IssuePagingNum)) | |||
| @@ -188,11 +199,19 @@ func DownloadCloudBrains(ctx *context.Context) { | |||
| } | |||
| func allValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[string]string { | |||
| return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): rs.JobType, getCellName("C", row): rs.Status, getCellName("D", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("E", row): getDurationTime(rs), | |||
| getCellName("F", row): rs.ComputeResource, getCellName("G", row): rs.Name, getCellName("H", row): getRepoPathName(rs), getCellName("I", row): rs.JobName, | |||
| return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): repo.GetCloudbrainCluster(rs.Cloudbrain, ctx), | |||
| getCellName("C", row): rs.JobType, getCellName("D", row): rs.Status, getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), | |||
| getCellName("F", row): getDurationTime(rs), getCellName("G", row): rs.ComputeResource, | |||
| getCellName("H", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("I", row): getCloudbrainCardType(rs), | |||
| getCellName("J", row): rs.Name, getCellName("K", row): getRepoPathName(rs), getCellName("L", row): rs.JobName, | |||
| } | |||
| } | |||
| func getCloudbrainCardType(rs *models.CloudbrainInfo) string { | |||
| _, cardType, _ := repo.GetCloudbrainCardNumAndType(rs.Cloudbrain) | |||
| return cardType | |||
| } | |||
| func getRepoPathName(rs *models.CloudbrainInfo) string { | |||
| if rs.Repo != nil { | |||
| return rs.Repo.OwnerName + "/" + rs.Repo.Alias | |||
| @@ -225,7 +244,11 @@ func getTotalPage(total int64, pageSize int) int { | |||
| func allHeader(ctx *context.Context) map[string]string { | |||
| return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.cloudbrain_task_type"), "C1": ctx.Tr("repo.modelarts.status"), "D1": ctx.Tr("repo.modelarts.createtime"), "E1": ctx.Tr("repo.modelarts.train_job.dura_time"), "F1": ctx.Tr("repo.modelarts.computing_resources"), "G1": ctx.Tr("repo.cloudbrain_creator"), "H1": ctx.Tr("repo.repo_name"), "I1": ctx.Tr("repo.cloudbrain_task_name")} | |||
| return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.modelarts.cluster"), | |||
| "C1": ctx.Tr("repo.cloudbrain_task_type"), "D1": ctx.Tr("repo.modelarts.status"), "E1": ctx.Tr("repo.modelarts.createtime"), | |||
| "F1": ctx.Tr("repo.modelarts.train_job.dura_time"), "G1": ctx.Tr("repo.modelarts.computing_resources"), | |||
| "H1": ctx.Tr("repo.modelarts.ai_center"), "I1": ctx.Tr("repo.modelarts.card_type"), "J1": ctx.Tr("repo.cloudbrain_creator"), | |||
| "K1": ctx.Tr("repo.repo_name"), "L1": ctx.Tr("repo.cloudbrain_task_name")} | |||
| } | |||
| @@ -0,0 +1,284 @@ | |||
| package admin | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/base" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/routers/response" | |||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||
| "net/http" | |||
| "strconv" | |||
| "strings" | |||
| ) | |||
| const ( | |||
| tplResourceQueue base.TplName = "admin/resources/queue" | |||
| tplResourceSpecification base.TplName = "admin/resources/specification" | |||
| tplResourceScene base.TplName = "admin/resources/scene" | |||
| ) | |||
| func GetQueuePage(ctx *context.Context) { | |||
| ctx.Data["PageIsAdmin"] = true | |||
| ctx.Data["PageIsAdminResources"] = true | |||
| ctx.Data["PageIsAdminResourcesQueue"] = true | |||
| ctx.HTML(200, tplResourceQueue) | |||
| } | |||
| func GetSpecificationPage(ctx *context.Context) { | |||
| ctx.Data["PageIsAdmin"] = true | |||
| ctx.Data["PageIsAdminResources"] = true | |||
| ctx.Data["PageIsAdminResourcesSpecification"] = true | |||
| ctx.HTML(200, tplResourceSpecification) | |||
| } | |||
| func GetScenePage(ctx *context.Context) { | |||
| ctx.Data["PageIsAdmin"] = true | |||
| ctx.Data["PageIsAdminResources"] = true | |||
| ctx.Data["PageIsAdminResourcesScene"] = true | |||
| ctx.HTML(200, tplResourceScene) | |||
| } | |||
| func GetResourceQueueList(ctx *context.Context) { | |||
| page := ctx.QueryInt("page") | |||
| cluster := ctx.Query("cluster") | |||
| aiCenterCode := ctx.Query("center") | |||
| computeResource := ctx.Query("resource") | |||
| accCardType := ctx.Query("card") | |||
| list, err := resource.GetResourceQueueList(models.SearchResourceQueueOptions{ | |||
| ListOptions: models.ListOptions{Page: page, PageSize: 10}, | |||
| Cluster: cluster, | |||
| AiCenterCode: aiCenterCode, | |||
| ComputeResource: computeResource, | |||
| AccCardType: accCardType, | |||
| }) | |||
| if err != nil { | |||
| log.Error("GetResourceQueueList error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(list)) | |||
| } | |||
| func GetResourceQueueCodes(ctx *context.Context) { | |||
| cluster := ctx.Query("cluster") | |||
| list, err := resource.GetResourceQueueCodes(models.GetQueueCodesOptions{Cluster: cluster}) | |||
| if err != nil { | |||
| log.Error("GetResourceQueueCodes error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(list)) | |||
| } | |||
| func GetResourceAiCenters(ctx *context.Context) { | |||
| list, err := resource.GetResourceAiCenters() | |||
| if err != nil { | |||
| log.Error("GetResourceAiCenters error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(list)) | |||
| } | |||
| func AddResourceQueue(ctx *context.Context, req models.ResourceQueueReq) { | |||
| req.IsAutomaticSync = false | |||
| req.CreatorId = ctx.User.ID | |||
| err := resource.AddResourceQueue(req) | |||
| if err != nil { | |||
| log.Error("AddResourceQueue error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func UpdateResourceQueue(ctx *context.Context, req models.ResourceQueueReq) { | |||
| queueId := ctx.ParamsInt64(":id") | |||
| //only CardsTotalNum permitted to change | |||
| err := resource.UpdateResourceQueue(queueId, req) | |||
| if err != nil { | |||
| log.Error("UpdateResourceQueue error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func SyncGrampusQueue(ctx *context.Context) { | |||
| err := resource.SyncGrampusQueue(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("AddResourceQueue error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func GetResourceSpecificationList(ctx *context.Context) { | |||
| page := ctx.QueryInt("page") | |||
| queue := ctx.QueryInt64("queue") | |||
| status := ctx.QueryInt("status") | |||
| cluster := ctx.Query("cluster") | |||
| list, err := resource.GetResourceSpecificationList(models.SearchResourceSpecificationOptions{ | |||
| ListOptions: models.ListOptions{Page: page, PageSize: 10}, | |||
| QueueId: queue, | |||
| Status: status, | |||
| Cluster: cluster, | |||
| }) | |||
| if err != nil { | |||
| log.Error("GetResourceSpecificationList error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(list)) | |||
| } | |||
| func GetResourceSpecificationScenes(ctx *context.Context) { | |||
| specId := ctx.ParamsInt64(":id") | |||
| list, err := resource.GetResourceSpecificationScenes(specId) | |||
| if err != nil { | |||
| log.Error("GetResourceSpecificationScenes error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| r := make(map[string]interface{}) | |||
| r["List"] = list | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | |||
| } | |||
| func AddResourceSpecification(ctx *context.Context, req models.ResourceSpecificationReq) { | |||
| req.IsAutomaticSync = false | |||
| req.CreatorId = ctx.User.ID | |||
| err := resource.AddResourceSpecification(ctx.User.ID, req) | |||
| if err != nil { | |||
| log.Error("AddResourceQueue error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func UpdateResourceSpecification(ctx *context.Context, req models.ResourceSpecificationReq) { | |||
| id := ctx.ParamsInt64(":id") | |||
| action := ctx.Query("action") | |||
| var err *response.BizError | |||
| switch action { | |||
| case "edit": | |||
| if req.UnitPrice < 0 { | |||
| ctx.JSON(http.StatusOK, response.ServerError("param error")) | |||
| return | |||
| } | |||
| //only UnitPrice and permitted to change | |||
| err = resource.UpdateSpecUnitPrice(ctx.User.ID, id, req.UnitPrice) | |||
| case "on-shelf": | |||
| err = resource.ResourceSpecOnShelf(ctx.User.ID, id, req.UnitPrice) | |||
| case "off-shelf": | |||
| err = resource.ResourceSpecOffShelf(ctx.User.ID, id) | |||
| } | |||
| if err != nil { | |||
| log.Error("UpdateResourceSpecification error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ResponseError(err)) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func SyncGrampusSpecs(ctx *context.Context) { | |||
| err := resource.SyncGrampusSpecs(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("AddResourceQueue error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func GetResourceSceneList(ctx *context.Context) { | |||
| page := ctx.QueryInt("page") | |||
| jobType := ctx.Query("jobType") | |||
| aiCenterCode := ctx.Query("center") | |||
| queueId := ctx.QueryInt64("queue") | |||
| isExclusive := ctx.QueryInt("IsExclusive") | |||
| list, err := resource.GetResourceSceneList(models.SearchResourceSceneOptions{ | |||
| ListOptions: models.ListOptions{Page: page, PageSize: 10}, | |||
| JobType: jobType, | |||
| IsExclusive: isExclusive, | |||
| AiCenterCode: aiCenterCode, | |||
| QueueId: queueId, | |||
| }) | |||
| if err != nil { | |||
| log.Error("GetResourceSceneList error.%v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(list)) | |||
| } | |||
| func AddResourceScene(ctx *context.Context, req models.ResourceSceneReq) { | |||
| req.CreatorId = ctx.User.ID | |||
| err := resource.AddResourceScene(req) | |||
| if err != nil { | |||
| log.Error("AddResourceScene error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func UpdateResourceScene(ctx *context.Context, req models.ResourceSceneReq) { | |||
| id := ctx.ParamsInt64(":id") | |||
| action := ctx.Query("action") | |||
| req.ID = id | |||
| var err error | |||
| switch action { | |||
| case "edit": | |||
| err = resource.UpdateResourceScene(req) | |||
| case "delete": | |||
| err = resource.DeleteResourceScene(id) | |||
| } | |||
| if err != nil { | |||
| log.Error("UpdateResourceScene error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| func RefreshHistorySpec(ctx *context.Context) { | |||
| scope := ctx.Query("scope") | |||
| list := ctx.Query("list") | |||
| var scopeAll = false | |||
| if scope == "all" { | |||
| scopeAll = true | |||
| } | |||
| var ids = make([]int64, 0) | |||
| if list != "" { | |||
| strs := strings.Split(list, "|") | |||
| for _, s := range strs { | |||
| i, err := strconv.ParseInt(s, 10, 64) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ids = append(ids, i) | |||
| } | |||
| } | |||
| total, success, err := resource.RefreshHistorySpec(scopeAll, ids) | |||
| if err != nil { | |||
| log.Error("RefreshHistorySpec error. %v", err) | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| r := make(map[string]interface{}, 0) | |||
| r["success"] = success | |||
| r["total"] = total | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | |||
| } | |||
| @@ -570,6 +570,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/query_user_last_month", operationReq, repo_ext.QueryUserStaticLastMonth) | |||
| m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday) | |||
| m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll) | |||
| m.Get("/query_user_activity", operationReq, repo_ext.QueryUserActivity) | |||
| m.Get("/query_user_login", operationReq, repo_ext.QueryUserLoginInfo) | |||
| //cloudbrain board | |||
| m.Group("/cloudbrainboard", func() { | |||
| m.Get("/downloadAll", repo.DownloadCloudBrainBoard) | |||
| @@ -914,6 +916,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/cloudbrain", func() { | |||
| m.Get("/:id", repo.GetCloudbrainTask) | |||
| m.Get("/:id/log", repo.CloudbrainGetLog) | |||
| m.Get("/:id/download_log_file", repo.CloudbrainDownloadLogFile) | |||
| m.Group("/train-job", func() { | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", repo.GetModelArtsTrainJobVersion) | |||
| @@ -921,7 +924,20 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop) | |||
| }) | |||
| }) | |||
| m.Group("/inference-job", func() { | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", repo.GetCloudBrainInferenceJob) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.DelCloudBrainJob) | |||
| m.Get("/result_list", repo.InferencJobResultList) | |||
| }) | |||
| }) | |||
| }, reqRepoReader(models.UnitTypeCloudBrain)) | |||
| m.Group("/modelmanage", func() { | |||
| m.Get("/:id", repo.GetCloudbrainModelConvertTask) | |||
| m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog) | |||
| m.Get("/:id/modelartlog", repo.TrainJobForModelConvertGetLog) | |||
| m.Get("/:id/model_list", repo.CloudBrainModelConvertList) | |||
| }, reqRepoReader(models.UnitTypeModelManage)) | |||
| m.Group("/modelarts", func() { | |||
| m.Group("/notebook", func() { | |||
| //m.Get("/:jobid", repo.GetModelArtsNotebook) | |||
| @@ -1056,6 +1072,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/prd/event", authentication.AcceptWechatEvent) | |||
| }) | |||
| m.Get("/wechat/material", authentication.GetMaterial) | |||
| m.Get("/cloudbrain/get_newest_job", repo.GetNewestJobs) | |||
| m.Get("/cloudbrain/get_center_info", repo.GetAICenterInfo) | |||
| }, securityHeaders(), context.APIContexter(), sudo()) | |||
| } | |||
| @@ -6,16 +6,24 @@ | |||
| package repo | |||
| import ( | |||
| "bufio" | |||
| "encoding/json" | |||
| "io" | |||
| "net/http" | |||
| "os" | |||
| "sort" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/modelarts" | |||
| "code.gitea.io/gitea/modules/storage" | |||
| routerRepo "code.gitea.io/gitea/routers/repo" | |||
| ) | |||
| @@ -71,7 +79,7 @@ func GetCloudbrainTask(ctx *context.APIContext) { | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| taskRoles := result.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| @@ -83,6 +91,9 @@ func GetCloudbrainTask(ctx *context.APIContext) { | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -96,25 +107,211 @@ func GetCloudbrainTask(ctx *context.APIContext) { | |||
| "SubState": result.JobStatus.SubState, | |||
| "CreatedTime": time.Unix(result.JobStatus.CreatedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||
| "CompletedTime": time.Unix(result.JobStatus.CompletedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||
| "JobDuration": job.TrainJobDuration, | |||
| }) | |||
| } | |||
| func CloudbrainGetLog(ctx *context.Context) { | |||
| func GetCloudBrainInferenceJob(ctx *context.APIContext) { | |||
| jobID := ctx.Params(":jobid") | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| jobResult, err := cloudbrain.GetJob(job.JobID) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| log.Error("GetJob failed:", err) | |||
| return | |||
| } | |||
| result, err := models.ConvertToJobResultPayload(jobResult.Payload) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||
| taskRoles := result.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP | |||
| job.ContainerID = taskRes.TaskStatuses[0].ContainerID | |||
| job.Status = taskRes.TaskStatuses[0].State | |||
| } | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "JobStatus": job.Status, | |||
| "JobDuration": job.TrainJobDuration, | |||
| }) | |||
| } | |||
| func DelCloudBrainJob(ctx *context.APIContext) { | |||
| jobID := ctx.Params(":jobid") | |||
| errStr := cloudbrain.DelCloudBrainJob(jobID) | |||
| if errStr != "" { | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "Message": ctx.Tr(errStr), | |||
| "VersionName": "1", | |||
| "Code": 1, | |||
| }) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "Message": "", | |||
| "VersionName": "1", | |||
| "Code": 0, | |||
| }) | |||
| } | |||
| } | |||
| func InferencJobResultList(ctx *context.APIContext) { | |||
| jobID := ctx.Params(":jobid") | |||
| parentDir := ctx.Query("parentDir") | |||
| dirArray := strings.Split(parentDir, "/") | |||
| task, err := models.GetCloudbrainByJobID(jobID) | |||
| if err != nil { | |||
| log.Error("get cloud brain err:", err) | |||
| ctx.ServerError("get cloud brain information failed:", err) | |||
| } | |||
| //get dirs | |||
| dirs, err := routerRepo.GetResultDirs(task.JobName, parentDir) | |||
| if err != nil { | |||
| log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||
| ctx.ServerError("GetModelDirs failed:", err) | |||
| return | |||
| } | |||
| var fileInfos []storage.FileInfo | |||
| err = json.Unmarshal([]byte(dirs), &fileInfos) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return | |||
| } | |||
| for i, fileInfo := range fileInfos { | |||
| temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime) | |||
| fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05") | |||
| } | |||
| sort.Slice(fileInfos, func(i, j int) bool { | |||
| return fileInfos[i].ModTime > fileInfos[j].ModTime | |||
| }) | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "StatusOK": 0, | |||
| "Path": dirArray, | |||
| "Dirs": fileInfos, | |||
| "task": task, | |||
| "PageIsCloudBrain": true, | |||
| }) | |||
| } | |||
| func GetCloudbrainModelConvertTask(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| ID := ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(ID) | |||
| job, err := models.QueryModelConvertById(ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| ctx.NotFound(err) | |||
| log.Error("GetCloudbrainByID failed:", err) | |||
| return | |||
| } | |||
| if job.IsGpuTrainTask() { | |||
| jobResult, err := cloudbrain.GetJob(job.CloudBrainTaskId) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| log.Error("GetJob failed:", err) | |||
| return | |||
| } | |||
| result, _ := models.ConvertToJobResultPayload(jobResult.Payload) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| job.Status = result.JobStatus.State | |||
| taskRoles := result.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||
| job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP | |||
| job.ContainerID = taskRes.TaskStatuses[0].ContainerID | |||
| job.Status = taskRes.TaskStatuses[0].State | |||
| } | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ModelComputeAndSetDuration(job, result) | |||
| err = models.UpdateModelConvert(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "ID": ID, | |||
| "JobName": result.Config.JobName, | |||
| "JobStatus": result.JobStatus.State, | |||
| "SubState": result.JobStatus.SubState, | |||
| "CreatedTime": time.Unix(result.JobStatus.CreatedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||
| "CompletedTime": time.Unix(result.JobStatus.CompletedTime/1000, 0).Format("2006-01-02 15:04:05"), | |||
| }) | |||
| } else { | |||
| result, err := modelarts.GetTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId) | |||
| if err != nil { | |||
| log.Error("get modelart job failed:", err) | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.RunTime = result.Duration / 1000 | |||
| job.TrainJobDuration = models.ConvertDurationToStr(job.RunTime) | |||
| err = models.UpdateModelConvert(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "ID": ID, | |||
| "JobStatus": job.Status, | |||
| }) | |||
| } | |||
| } | |||
| func CloudbrainGetLogByJobId(jobId string, jobName string) map[string]interface{} { | |||
| var hits []models.Hits | |||
| result, err := cloudbrain.GetJobLog(job.JobID) | |||
| result, err := cloudbrain.GetJobLog(jobId) | |||
| if err != nil { | |||
| log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| log.Error("GetJobLog failed: %v", err) | |||
| return nil | |||
| } | |||
| hits = result.Hits.Hits | |||
| @@ -123,7 +320,7 @@ func CloudbrainGetLog(ctx *context.Context) { | |||
| for { | |||
| resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID) | |||
| if err != nil { | |||
| log.Error("GetJobAllLog failed: %v", err, ctx.Data["MsgID"]) | |||
| log.Error("GetJobAllLog failed: %v", err) | |||
| } else { | |||
| for _, hit := range resultNext.Hits.Hits { | |||
| hits = append(hits, hit) | |||
| @@ -148,12 +345,233 @@ func CloudbrainGetLog(ctx *context.Context) { | |||
| content += log.Source.Message + "\n" | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobName": job.JobName, | |||
| return map[string]interface{}{ | |||
| "JobName": jobName, | |||
| "Content": content, | |||
| }) | |||
| } | |||
| } | |||
| func CloudbrainForModelConvertGetLog(ctx *context.Context) { | |||
| ID := ctx.Params(":id") | |||
| job, err := models.QueryModelConvertById(ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| } | |||
| result := CloudbrainGetLogByJobId(job.CloudBrainTaskId, job.Name) | |||
| if result == nil { | |||
| log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, result) | |||
| } | |||
| func CloudbrainDownloadLogFile(ctx *context.Context) { | |||
| ID := ctx.Params(":id") | |||
| job, err := models.GetCloudbrainByID(ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| } | |||
| prefix := "/" + setting.CBCodePathPrefix + job.JobName + "/model" | |||
| files, err := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "") | |||
| if err != nil { | |||
| log.Error("query cloudbrain model failed: %v", err) | |||
| return | |||
| } | |||
| fileName := "" | |||
| for _, file := range files { | |||
| if strings.HasSuffix(file.FileName, "log.txt") { | |||
| fileName = file.FileName | |||
| break | |||
| } | |||
| } | |||
| if fileName != "" { | |||
| url, err := storage.Attachments.PresignedGetURL(prefix+"/"+fileName, fileName) | |||
| if err != nil { | |||
| log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||
| ctx.ServerError("Get minio get SignedUrl failed", err) | |||
| return | |||
| } | |||
| http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect) | |||
| } | |||
| } | |||
| func CloudbrainGetLog(ctx *context.Context) { | |||
| ID := ctx.Params(":id") | |||
| startLine := ctx.QueryInt("base_line") | |||
| lines := ctx.QueryInt("lines") | |||
| endLine := startLine + lines | |||
| order := ctx.Query("order") | |||
| if order == "asc" { | |||
| endLine = startLine | |||
| startLine = endLine - lines | |||
| if startLine < 0 { | |||
| startLine = 0 | |||
| } | |||
| } | |||
| job, err := models.GetCloudbrainByID(ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| } | |||
| result := getLogFromModelDir(job.JobName, startLine, endLine) | |||
| if result == nil { | |||
| log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
| ctx.ServerError(err.Error(), err) | |||
| return | |||
| } | |||
| re := map[string]interface{}{ | |||
| "JobID": ID, | |||
| "LogFileName": result["FileName"], | |||
| "StartLine": startLine, | |||
| "EndLine": result["endLine"], | |||
| "Content": result["Content"], | |||
| "Lines": result["lines"], | |||
| "CanLogDownload": result["FileName"] != "", | |||
| } | |||
| //result := CloudbrainGetLogByJobId(job.JobID, job.JobName) | |||
| ctx.JSON(http.StatusOK, re) | |||
| } | |||
| func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]interface{} { | |||
| prefix := "/" + setting.CBCodePathPrefix + jobName + "/model" | |||
| files, err := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "") | |||
| if err != nil { | |||
| log.Error("query cloudbrain model failed: %v", err) | |||
| return nil | |||
| } | |||
| re := "" | |||
| fileName := "" | |||
| count := 0 | |||
| fileEndLine := endLine | |||
| for _, file := range files { | |||
| if strings.HasSuffix(file.FileName, "log.txt") { | |||
| fileName = file.FileName | |||
| path := storage.GetMinioPath(jobName+"/model/", file.FileName) | |||
| log.Info("path=" + path) | |||
| reader, err := os.Open(path) | |||
| defer reader.Close() | |||
| if err == nil { | |||
| r := bufio.NewReader(reader) | |||
| for i := 0; i < endLine; i++ { | |||
| line, error := r.ReadString('\n') | |||
| log.Info("line=" + line) | |||
| fileEndLine = i | |||
| if error == io.EOF { | |||
| log.Info("read file completed.") | |||
| break | |||
| } | |||
| if error != nil { | |||
| log.Info("read file error." + error.Error()) | |||
| break | |||
| } | |||
| if error == nil { | |||
| if i >= startLine { | |||
| re = re + line | |||
| count++ | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| log.Info("error:" + err.Error()) | |||
| } | |||
| break | |||
| } | |||
| } | |||
| return map[string]interface{}{ | |||
| "JobName": jobName, | |||
| "Content": re, | |||
| "FileName": fileName, | |||
| "lines": count, | |||
| "endLine": fileEndLine, | |||
| } | |||
| } | |||
| func CloudBrainModelConvertList(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| ID := ctx.Params(":id") | |||
| parentDir := ctx.Query("parentDir") | |||
| dirArray := strings.Split(parentDir, "/") | |||
| job, err := models.QueryModelConvertById(ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", job.Name, err.Error()) | |||
| return | |||
| } | |||
| if job.IsGpuTrainTask() { | |||
| //get dirs | |||
| dirs, err := routerRepo.GetModelDirs(job.ID, parentDir) | |||
| if err != nil { | |||
| log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||
| ctx.ServerError("GetModelDirs failed:", err) | |||
| return | |||
| } | |||
| var fileInfos []storage.FileInfo | |||
| err = json.Unmarshal([]byte(dirs), &fileInfos) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return | |||
| } | |||
| for i, fileInfo := range fileInfos { | |||
| temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime) | |||
| fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05") | |||
| } | |||
| sort.Slice(fileInfos, func(i, j int) bool { | |||
| return fileInfos[i].ModTime > fileInfos[j].ModTime | |||
| }) | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": ID, | |||
| "VersionName": "", | |||
| "StatusOK": 0, | |||
| "Path": dirArray, | |||
| "Dirs": fileInfos, | |||
| "task": job, | |||
| "PageIsCloudBrain": true, | |||
| }) | |||
| } else { | |||
| var jobID = ctx.Params(":id") | |||
| var versionName = "V0001" | |||
| parentDir := ctx.Query("parentDir") | |||
| dirArray := strings.Split(parentDir, "/") | |||
| models, err := storage.GetObsListObject(job.ID, "output/", parentDir, versionName) | |||
| if err != nil { | |||
| log.Info("get TrainJobListModel failed:", err) | |||
| ctx.ServerError("GetObsListObject:", err) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "VersionName": versionName, | |||
| "StatusOK": 0, | |||
| "Path": dirArray, | |||
| "Dirs": models, | |||
| "task": job, | |||
| "PageIsCloudBrain": true, | |||
| }) | |||
| } | |||
| return | |||
| } | |||
| func CloudBrainModelList(ctx *context.APIContext) { | |||
| @@ -207,3 +625,94 @@ func CloudBrainModelList(ctx *context.APIContext) { | |||
| "PageIsCloudBrain": true, | |||
| }) | |||
| } | |||
| type JobInfo struct { | |||
| JobName string `json:"job_name"` | |||
| AiCenterId int `json:"ai_center_id"` | |||
| } | |||
| func GetNewestJobs(ctx *context.APIContext) { | |||
| idsC2Net, err := models.GetNewestJobsByAiCenter() | |||
| if err != nil { | |||
| log.Error("GetNewestJobsByAiCenter(%s) failed:%v", err.Error()) | |||
| return | |||
| } | |||
| idsCloudbrain, err := models.GetNewestJobsByType() | |||
| if err != nil { | |||
| log.Error("GetNewestJobsByType(%s) failed:%v", err.Error()) | |||
| return | |||
| } | |||
| ids := make([]int64, len(idsC2Net), cap(idsC2Net)*2) | |||
| copy(ids, idsC2Net) | |||
| for _, id := range idsCloudbrain { | |||
| ids = append(ids, id) | |||
| } | |||
| jobs, err := models.GetCloudbrainByIDs(ids) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByIDs(%s) failed:%v", err.Error()) | |||
| return | |||
| } | |||
| jobInfos := make([]JobInfo, 0) | |||
| for _, job := range jobs { | |||
| var id int | |||
| var content string | |||
| switch job.Type { | |||
| case models.TypeCloudBrainOne: | |||
| id, content = getAICenterID("cloudbrain_one") | |||
| if content == "" { | |||
| log.Error("job(%s) has no match config info", job.DisplayJobName) | |||
| continue | |||
| } | |||
| case models.TypeCloudBrainTwo: | |||
| id, content = getAICenterID("cloudbrain_two") | |||
| if content == "" { | |||
| log.Error("job(%s) has no match config info", job.DisplayJobName) | |||
| continue | |||
| } | |||
| case models.TypeC2Net: | |||
| centerInfo := strings.Split(job.AiCenter, "+") | |||
| if len(centerInfo) != 2 { | |||
| log.Error("job(%s):ai_center(%s) is wrong", job.DisplayJobName, job.AiCenter) | |||
| continue | |||
| } | |||
| id, content = getAICenterID(centerInfo[0]) | |||
| if content == "" { | |||
| log.Error("job(%s) has no match config info", job.DisplayJobName) | |||
| continue | |||
| } | |||
| default: | |||
| log.Error("no match info") | |||
| continue | |||
| } | |||
| jobInfos = append(jobInfos, JobInfo{ | |||
| JobName: job.DisplayJobName, | |||
| AiCenterId: id, | |||
| }) | |||
| } | |||
| ctx.JSON(http.StatusOK, jobInfos) | |||
| } | |||
| func GetAICenterInfo(ctx *context.APIContext) { | |||
| if setting.C2NetInfos == nil { | |||
| log.Error("C2NET_SEQUENCE is incorrect") | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, setting.C2NetInfos.C2NetSqInfo) | |||
| } | |||
| func getAICenterID(name string) (int, string) { | |||
| for _, info := range setting.C2NetInfos.C2NetSqInfo { | |||
| if name == info.Name { | |||
| return info.ID, info.Content | |||
| } | |||
| } | |||
| return 0, "" | |||
| } | |||
| @@ -10,6 +10,7 @@ import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/routers/repo" | |||
| "github.com/360EntSecGroup-Skylar/excelize/v2" | |||
| ) | |||
| @@ -678,6 +679,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||
| jobType := ctx.Query("jobType") | |||
| jobStatus := ctx.Query("jobStatus") | |||
| cloudBrainType := ctx.QueryInt("Type") | |||
| aiCenter := ctx.Query("aiCenter") | |||
| needDeleteInfo := ctx.Query("needDeleteInfo") | |||
| page := ctx.QueryInt("page") | |||
| pageSize := ctx.QueryInt("pagesize") | |||
| @@ -723,6 +726,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||
| NeedRepoInfo: true, | |||
| BeginTimeUnix: int64(recordBeginTime), | |||
| EndTimeUnix: endTime.Unix(), | |||
| AiCenter: aiCenter, | |||
| NeedDeleteInfo: needDeleteInfo, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Get job failed:", err) | |||
| @@ -735,6 +740,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||
| var taskDetail models.TaskDetail | |||
| taskDetail.ID = ciTasks[i].Cloudbrain.ID | |||
| taskDetail.JobID = ciTasks[i].Cloudbrain.JobID | |||
| taskDetail.JobName = ciTasks[i].JobName | |||
| taskDetail.DisplayJobName = ciTasks[i].DisplayJobName | |||
| taskDetail.Status = ciTasks[i].Status | |||
| @@ -751,48 +757,14 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||
| taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name | |||
| taskDetail.RepoAlias = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Alias | |||
| } | |||
| if ciTasks[i].Cloudbrain.Status == string(models.JobWaiting) { | |||
| if ciTasks[i].Cloudbrain.DeletedAt != nilTime { | |||
| WaitTimeInt := ciTasks[i].Cloudbrain.UpdatedUnix.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) | |||
| if WaitTimeInt < 0 { | |||
| taskDetail.WaitTime = "00:00:00" | |||
| } | |||
| } else { | |||
| if ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 { | |||
| WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) | |||
| if WaitTimeInt < 0 { | |||
| taskDetail.WaitTime = "00:00:00" | |||
| } | |||
| } else { | |||
| WaitTimeInt := ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) | |||
| if WaitTimeInt < 0 { | |||
| taskDetail.WaitTime = "00:00:00" | |||
| } | |||
| } | |||
| } | |||
| } else if ciTasks[i].Cloudbrain.Status == string(models.JobStopped) && ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 { | |||
| WaitTimeInt := ciTasks[i].Cloudbrain.EndTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) | |||
| if WaitTimeInt < 0 { | |||
| taskDetail.WaitTime = "00:00:00" | |||
| } | |||
| } else { | |||
| WaitTimeInt := ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt) | |||
| if WaitTimeInt < 0 { | |||
| taskDetail.WaitTime = "00:00:00" | |||
| } | |||
| } | |||
| taskDetail.CardNum, taskDetail.CardType, _ = repo.GetCloudbrainCardNumAndType(ciTasks[i].Cloudbrain) | |||
| taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain) | |||
| taskDetail.AiCenter = repo.GetCloudbrainAiCenter(ciTasks[i].Cloudbrain, ctx) | |||
| taskDetail.FlavorName, _ = repo.GetCloudbrainFlavorName(ciTasks[i].Cloudbrain) | |||
| if ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainTwo || (ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainOne && ciTasks[i].Cloudbrain.JobType == "TRAIN") { | |||
| taskDetail.JobID = ciTasks[i].Cloudbrain.JobID | |||
| } | |||
| taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain) | |||
| if ciTasks[i].Cloudbrain.DeletedAt != nilTime { | |||
| if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil { | |||
| taskDetail.IsDelete = true | |||
| } else { | |||
| taskDetail.IsDelete = false | |||
| @@ -813,6 +785,17 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||
| }) | |||
| } | |||
| func getCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string { | |||
| if task.Type == models.TypeCloudBrainOne { | |||
| return ctx.Tr("repo.cloudbrain1") | |||
| } else if task.Type == models.TypeCloudBrainTwo { | |||
| return ctx.Tr("repo.cloudbrain2") | |||
| } else if task.Type == models.TypeC2Net { | |||
| return task.AiCenter | |||
| } | |||
| return "" | |||
| } | |||
| func GetCloudbrainsCreateHoursData(ctx *context.Context) { | |||
| recordCloudbrain, err := models.GetRecordBeginTime() | |||
| if err != nil { | |||
| @@ -1247,18 +1230,23 @@ func allCloudbrainHeader(ctx *context.Context) map[string]string { | |||
| return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.cloudbrain_type"), "C1": ctx.Tr("repo.modelarts.status"), "D1": ctx.Tr("repo.cloudbrain_task_type"), | |||
| "E1": ctx.Tr("repo.modelarts.createtime"), "F1": ctx.Tr("repo.modelarts.train_job.wait_time"), "G1": ctx.Tr("repo.modelarts.train_job.dura_time"), | |||
| "H1": ctx.Tr("repo.modelarts.train_job.start_time"), | |||
| "I1": ctx.Tr("repo.modelarts.train_job.end_time"), "J1": ctx.Tr("repo.modelarts.computing_resources"), | |||
| "K1": ctx.Tr("repo.cloudbrain_creator"), "L1": ctx.Tr("repo.repo_name"), "M1": ctx.Tr("repo.cloudbrain_task_name"), "N1": ctx.Tr("repo.modelarts.deletetime")} | |||
| "H1": ctx.Tr("cloudbrain.card_duration"), | |||
| "I1": ctx.Tr("repo.modelarts.train_job.start_time"), "J1": ctx.Tr("repo.modelarts.train_job.end_time"), | |||
| "K1": ctx.Tr("repo.modelarts.computing_resources"), "L1": ctx.Tr("cloudbrain.card_type"), | |||
| "M1": ctx.Tr("repo.grampus.train_job.ai_center"), "N1": ctx.Tr("cloudbrain.resource_specification"), | |||
| "O1": ctx.Tr("repo.cloudbrain_creator"), "P1": ctx.Tr("repo.repo_name"), "Q1": ctx.Tr("repo.cloudbrain_task_name"), | |||
| "R1": ctx.Tr("repo.modelarts.deletetime")} | |||
| } | |||
| func allCloudbrainValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[string]string { | |||
| return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): getCloudbrainType(rs, ctx), getCellName("C", row): rs.Status, getCellName("D", row): rs.JobType, | |||
| getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("F", row): getBrainWaitTime(rs), | |||
| getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): getBrainStartTime(rs), | |||
| getCellName("I", row): getBrainEndTime(rs), | |||
| getCellName("J", row): rs.ComputeResource, getCellName("K", row): rs.Name, getCellName("L", row): getBrainRepo(rs), | |||
| getCellName("M", row): rs.JobName, getCellName("N", row): getBrainDeleteTime(rs), | |||
| getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("F", row): repo.GetCloudbrainWaitTime(rs.Cloudbrain), | |||
| getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): repo.GetCloudbrainCardDuration(rs.Cloudbrain), | |||
| getCellName("I", row): getBrainStartTime(rs), | |||
| getCellName("J", row): getBrainEndTime(rs), getCellName("K", row): rs.ComputeResource, getCellName("L", row): getCloudbrainCardType(rs), | |||
| getCellName("M", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("N", row): getCloudbrainFlavorName(rs), | |||
| getCellName("O", row): rs.Name, getCellName("P", row): getBrainRepo(rs), | |||
| getCellName("Q", row): rs.JobName, getCellName("R", row): getBrainDeleteTime(rs), | |||
| } | |||
| } | |||
| func getBrainRepo(rs *models.CloudbrainInfo) string { | |||
| @@ -1285,19 +1273,6 @@ func getBrainEndTime(rs *models.CloudbrainInfo) string { | |||
| } | |||
| } | |||
| func getBrainWaitTime(rs *models.CloudbrainInfo) string { | |||
| var waitTime int64 | |||
| if rs.Cloudbrain.Status == string(models.JobWaiting) { | |||
| waitTime = time.Now().Unix() - rs.Cloudbrain.CreatedUnix.AsTime().Unix() | |||
| } else { | |||
| waitTime = int64(rs.Cloudbrain.StartTime - rs.Cloudbrain.CreatedUnix) | |||
| } | |||
| if waitTime <= 0 { | |||
| return "00:00:00" | |||
| } else { | |||
| return models.ConvertDurationToStr(waitTime) | |||
| } | |||
| } | |||
| func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string { | |||
| if rs.Cloudbrain.Type == models.TypeCloudBrainOne { | |||
| return ctx.Tr("repo.cloudbrain1") | |||
| @@ -1309,6 +1284,14 @@ func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string { | |||
| return ctx.Tr("repo.cloudbrain_untype") | |||
| } | |||
| } | |||
| func getCloudbrainCardType(rs *models.CloudbrainInfo) string { | |||
| _, cardType, _ := repo.GetCloudbrainCardNumAndType(rs.Cloudbrain) | |||
| return cardType | |||
| } | |||
| func getCloudbrainFlavorName(rs *models.CloudbrainInfo) string { | |||
| flavorName, _ := repo.GetCloudbrainFlavorName(rs.Cloudbrain) | |||
| return flavorName | |||
| } | |||
| func getBrainDeleteTime(rs *models.CloudbrainInfo) string { | |||
| nilTime := time.Time{} | |||
| @@ -6,14 +6,17 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/grampus" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "encoding/json" | |||
| "net/http" | |||
| "path" | |||
| "strconv" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "code.gitea.io/gitea/modules/grampus" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| "code.gitea.io/gitea/modules/context" | |||
| @@ -24,37 +27,6 @@ import ( | |||
| routerRepo "code.gitea.io/gitea/routers/repo" | |||
| ) | |||
| func GetModelArtsNotebook(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| jobID := ctx.Params(":jobid") | |||
| repoID := ctx.Repo.Repository.ID | |||
| job, err := models.GetRepoCloudBrainByJobID(repoID, jobID) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| result, err := modelarts.GetJob(jobID) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| job.Status = result.Status | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "JobStatus": result.Status, | |||
| }) | |||
| } | |||
| func GetModelArtsNotebook2(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| @@ -66,29 +38,17 @@ func GetModelArtsNotebook2(ctx *context.APIContext) { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| result, err := modelarts.GetNotebook2(job.JobID) | |||
| err = modelarts.HandleNotebookInfo(job) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| if job.StartTime == 0 && result.Lease.UpdateTime > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) | |||
| } | |||
| job.Status = result.Status | |||
| if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) { | |||
| job.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| job.CorrectCreateUnix() | |||
| job.ComputeAndSetDuration() | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "ID": ID, | |||
| "JobName": job.JobName, | |||
| "JobStatus": result.Status, | |||
| "ID": ID, | |||
| "JobName": job.JobName, | |||
| "JobStatus": job.Status, | |||
| "JobDuration": job.TrainJobDuration, | |||
| }) | |||
| } | |||
| @@ -110,10 +70,13 @@ func GetModelArtsTrainJob(ctx *context.APIContext) { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.Duration = result.Duration | |||
| job.TrainJobDuration = result.TrainJobDuration | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -154,7 +117,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||
| taskRoles := result.TaskRoles | |||
| @@ -167,33 +130,20 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| } | |||
| } else if job.Type == models.TypeCloudBrainTwo { | |||
| result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10)) | |||
| err := modelarts.HandleTrainJobInfo(job) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| if job.StartTime == 0 && result.StartTime > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.StartTime / 1000) | |||
| } | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.Duration = result.Duration / 1000 | |||
| job.TrainJobDuration = models.ConvertDurationToStr(job.Duration) | |||
| if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 { | |||
| job.EndTime = job.StartTime.Add(job.Duration) | |||
| } | |||
| job.CorrectCreateUnix() | |||
| err = models.UpdateTrainJobVersion(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| } else if job.Type == models.TypeC2Net { | |||
| result, err := grampus.GetJob(jobID) | |||
| if err != nil { | |||
| @@ -205,6 +155,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| if job.StartTime == 0 && result.JobInfo.StartedAt > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.JobInfo.StartedAt) | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | |||
| job.Duration = result.JobInfo.RunSec | |||
| job.TrainJobDuration = models.ConvertDurationToStr(job.Duration) | |||
| @@ -227,6 +178,9 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| aiCenterName = temp[1] | |||
| } | |||
| } | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateTrainJobVersion(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -242,6 +196,75 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| } | |||
| func TrainJobForModelConvertGetLog(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| var jobID = ctx.Params(":id") | |||
| var baseLine = ctx.Query("base_line") | |||
| var order = ctx.Query("order") | |||
| var lines = ctx.Query("lines") | |||
| lines_int, err := strconv.Atoi(lines) | |||
| if err != nil { | |||
| log.Error("change lines(%d) string to int failed", lines_int) | |||
| } | |||
| if order != modelarts.OrderDesc && order != modelarts.OrderAsc { | |||
| log.Error("order(%s) check failed", order) | |||
| ctx.JSON(http.StatusBadRequest, map[string]interface{}{ | |||
| "err_msg": "order check failed", | |||
| }) | |||
| return | |||
| } | |||
| resultLogFile, result, err := trainJobForModelConvertGetLogContent(jobID, baseLine, order, lines_int) | |||
| if err != nil { | |||
| log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||
| // ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "LogFileName": "", | |||
| "StartLine": "0", | |||
| "EndLine": "0", | |||
| "Content": "", | |||
| "Lines": 0, | |||
| }) | |||
| return | |||
| } | |||
| ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||
| "LogFileName": resultLogFile.LogFileList[0], | |||
| "StartLine": result.StartLine, | |||
| "EndLine": result.EndLine, | |||
| "Content": result.Content, | |||
| "Lines": result.Lines, | |||
| }) | |||
| } | |||
| func trainJobForModelConvertGetLogContent(jobID string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { | |||
| task, err := models.QueryModelConvertById(jobID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||
| return nil, nil, err | |||
| } | |||
| resultLogFile, err := modelarts.GetTrainJobLogFileNames(task.CloudBrainTaskId, task.ModelArtsVersionId) | |||
| if err != nil { | |||
| log.Error("GetTrainJobLogFileNames(%s) failed:%v", task.CloudBrainTaskId, err.Error()) | |||
| return nil, nil, err | |||
| } | |||
| result, err := modelarts.GetTrainJobLog(task.CloudBrainTaskId, task.ModelArtsVersionId, baseLine, resultLogFile.LogFileList[0], order, lines) | |||
| if err != nil { | |||
| log.Error("GetTrainJobLog(%s) failed:%v", task.CloudBrainTaskId, err.Error()) | |||
| return nil, nil, err | |||
| } | |||
| return resultLogFile, result, err | |||
| } | |||
| func TrainJobGetLog(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| @@ -330,6 +353,14 @@ func DelTrainJobVersion(ctx *context.APIContext) { | |||
| return | |||
| } | |||
| if task.Status != string(models.ModelArtsTrainJobImageFailed) && task.Status != string(models.ModelArtsTrainJobSubmitFailed) && task.Status != string(models.ModelArtsTrainJobDeleteFailed) && | |||
| task.Status != string(models.ModelArtsTrainJobCompleted) && task.Status != string(models.ModelArtsTrainJobFailed) && | |||
| task.Status != string(models.ModelArtsTrainJobKilled) && task.Status != string(models.ModelArtsTrainJobCanceled) && task.Status != string(models.ModelArtsTrainJobLost) { | |||
| log.Error("the job(%s) version has not been stopped", task.JobName) | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| //删除modelarts上的记录 | |||
| _, err = modelarts.DelTrainJobVersion(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
| if err != nil { | |||
| @@ -473,26 +504,11 @@ func GetModelArtsInferenceJob(ctx *context.APIContext) { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10)) | |||
| err = modelarts.HandleTrainJobInfo(job) | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| if job.StartTime == 0 && result.StartTime > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.StartTime / 1000) | |||
| } | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.Duration = result.Duration / 1000 | |||
| job.TrainJobDuration = models.ConvertDurationToStr(job.Duration) | |||
| if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 { | |||
| job.EndTime = job.StartTime.Add(job.Duration) | |||
| } | |||
| job.CorrectCreateUnix() | |||
| err = models.UpdateInferenceJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "JobID": jobID, | |||