#2314 V20220616合入develop

Merged
lewis merged 337 commits from V20220616 into develop 1 year ago
  1. +76
    -5
      custom/public/css/git.openi.css
  2. BIN
      custom/public/img/i-pic-01.jpg
  3. BIN
      custom/public/img/i-pic-02.jpg
  4. BIN
      custom/public/img/i-pic-03.jpg
  5. BIN
      custom/public/img/i-pic-04.jpg
  6. BIN
      custom/public/rotation3D/img/baseLogo.png
  7. +1250
    -0
      custom/public/rotation3D/img/baseLogo.svg
  8. BIN
      custom/public/rotation3D/img/baseMap.png
  9. +1
    -0
      custom/public/rotation3D/img/brain.svg
  10. BIN
      custom/public/rotation3D/img/idc-green.png
  11. BIN
      custom/public/rotation3D/img/idc-red.png
  12. BIN
      custom/public/rotation3D/img/idc-yellow.png
  13. +2
    -0
      custom/public/rotation3D/jquery-3.5.0.min.js
  14. +152
    -0
      custom/public/rotation3D/rotation3D.css
  15. +380
    -0
      custom/public/rotation3D/rotation3D.js
  16. +6
    -0
      custom/public/rotation3D/vue-2.6.10.min.js
  17. +11
    -0
      models/attachment.go
  18. +105
    -2
      models/cloudbrain.go
  19. +291
    -0
      models/cloudbrain_static.go
  20. +30
    -3
      models/dataset.go
  21. +2
    -0
      models/repo_list.go
  22. +16
    -13
      models/user_business_analysis.go
  23. +1
    -0
      modules/auth/repo_form.go
  24. +2
    -1
      modules/cloudbrain/cloudbrain.go
  25. +41
    -0
      modules/modelarts/resty.go
  26. +8
    -0
      modules/storage/local.go
  27. +10
    -0
      modules/storage/minio.go
  28. +134
    -0
      modules/storage/minio_ext.go
  29. +14
    -0
      modules/storage/obs.go
  30. +1
    -0
      modules/storage/storage.go
  31. +12
    -2
      options/locale/locale_en-US.ini
  32. +21
    -6
      options/locale/locale_zh-CN.ini
  33. +66
    -5
      public/home/home.js
  34. +1
    -0
      public/self/css/notebook/katex.min.css
  35. +86
    -0
      public/self/css/notebook/notebook.css
  36. +142
    -0
      public/self/css/notebook/prism.css
  37. +6
    -0
      public/self/js/notebook/ansi_up.min.js
  38. +7
    -0
      public/self/js/notebook/es5-shim.min.js
  39. +1
    -0
      public/self/js/notebook/katex-auto-render.min.js
  40. +1
    -0
      public/self/js/notebook/katex.min.js
  41. +1
    -0
      public/self/js/notebook/marked.min.js
  42. +1
    -0
      public/self/js/notebook/notebook.min.js
  43. +7
    -0
      public/self/js/notebook/prism.min.js
  44. +3
    -0
      public/self/js/notebook/purify.min.js
  45. +4
    -0
      routers/admin/dataset.go
  46. +13
    -0
      routers/api/v1/api.go
  47. +1257
    -16
      routers/api/v1/repo/cloudbrain_dashboard.go
  48. +43
    -0
      routers/api/v1/repo/modelarts.go
  49. +11
    -7
      routers/api/v1/repo/repo_dashbord.go
  50. +44
    -0
      routers/home.go
  51. +210
    -79
      routers/repo/ai_model_manage.go
  52. +19
    -8
      routers/repo/cloudbrain.go
  53. +136
    -11
      routers/repo/dataset.go
  54. +35
    -5
      routers/repo/modelarts.go
  55. +6
    -2
      routers/repo/repo.go
  56. +4
    -0
      routers/repo/view.go
  57. +9
    -3
      routers/routes/routes.go
  58. +97
    -0
      routers/user/auth.go
  59. +44
    -0
      templates/base/footer.tmpl
  60. +2
    -0
      templates/base/head_home.tmpl
  61. +4
    -4
      templates/base/head_navbar.tmpl
  62. +201
    -141
      templates/explore/datasets.tmpl
  63. +80
    -25
      templates/home.tmpl
  64. +39
    -19
      templates/repo/create.tmpl
  65. +29
    -40
      templates/repo/datasets/index.tmpl
  66. +12
    -0
      templates/repo/header.tmpl
  67. +32
    -1
      templates/repo/modelarts/trainjob/show.tmpl
  68. +203
    -112
      templates/repo/modelmanage/index.tmpl
  69. +14
    -3
      templates/repo/modelmanage/showinfo.tmpl
  70. +14
    -0
      templates/repo/view_file.tmpl
  71. +4
    -11
      templates/user/dashboard/dashboard.tmpl
  72. +1
    -1
      templates/user/dashboard/feeds.tmpl
  73. +16
    -3
      web_src/js/components/Model.vue
  74. +109
    -3
      web_src/js/index.js
  75. +4
    -0
      web_src/less/_dashboard.less

+ 76
- 5
custom/public/css/git.openi.css View File

@@ -71,6 +71,19 @@
.ui.secondary.hometop.segment #navbar{
z-index: 10;
}
.ui.secondary.c2net.segment{
/* background: #f8faff;
border: none;*/
margin-bottom: 5em;
padding-top: 2em;
color: rgba(0,0,0,.87);
background-image: linear-gradient(to bottom left,var(--tw-gradient-stops));
--tw-gradient-from: #f5f3ff;
--tw-gradient-stops: var(--tw-gradient-from),#fff,var(--tw-gradient-to,hsla(0,0%,100%,0));
--tw-gradient-to: rgba(219,234,254,0.4);
border-top: 1px solid rgba(243,244,246,1)!important;
border-bottom: 1px solid rgba(243,244,246,1)!important;
}

.hometop .ui.secondary.menu .active.item{
color: #000;
@@ -134,8 +147,13 @@
.i-code-pic > img{
margin-bottom: -3.0rem;
}
.i-env .ui.cards>.card{
box-shadow:none;
}
.i-env .ui.cards>.card>.image{
background: none;
width: 60%;
margin: auto;
}
.i-env .ui.cards>.card>.content{
border-top: none;
@@ -168,7 +186,7 @@
bottom: 0;
background-color: rgba(105, 192, 255, .4);
width: 2px;
}
}
.homenews .time-since{
padding-left: 1em;
color: #888888;
@@ -185,7 +203,7 @@
padding: 0;
}
.newslist{
height: 325px;
height: 300px;
overflow: hidden;
}

@@ -208,14 +226,25 @@
height: auto;
border-top: 2px solid #3291F8;
border-right: 2px solid #3291F8;
border-bottom: 2px solid #3291F8;
border-radius: 0 4.0em 4.0em 0;
border-radius: 0 4.0em 0 0;
width: 10em;
z-index: 6;
}
.leftline02::after, .leftline02-2::after{
content: '';
position: absolute;
transform: translate(55%,50%);
right: 0;
bottom: 0;
width: 1.0em;
height: 1.0em;
background-color: #FFF;
border: 2px solid #3291F8;
border-radius: 1em;
}
.leftline03{
border-radius: 4.0em 0 0 0;
border-top: 2px solid #3291F8;
border-top: 2px solid #3291F8;
border-bottom:none;
top: -2.0em;
}
@@ -224,6 +253,9 @@
width: 7em;
z-index: 5;
}
.leftline02-2::after{
border-color: rgba(105, 192, 255, .4);
}
.leftline04{
border-radius: 0;
border-top: none;
@@ -280,6 +312,9 @@
.i-env > div{
position: relative;
}
.event-list .ui.card>.image>img{
height: 146px !important;
}

@media only screen and (max-width: 767px) {
.am-mt-30{ margin-top: 1.5rem !important;}
@@ -376,4 +411,40 @@

@media only screen and (min-width: 1920px) {

}

/* rotation3D */
#app{
width: 800px;
margin: 0 auto;
}
.rotation3D-baseMap{
position: absolute; left: 0; right: 0; top: 270px; margin: auto;
width: 800px; height: 516px;
background: url("../rotation3D/img/baseMap.png") no-repeat;
background-size: cover;
}
.rotation3D-baseMap::before{
position: absolute;
margin: auto; z-index: 99;
left:50%; top: -150px;
transform:translate(-50%,0);
width: 342px; height: 470px; display: block; content: '';
background: url("../rotation3D/img/baseLogo.svg");
/*animation: 10s bounceUpDown infinite;*/
}
.rotation3D-baseMap::after{
position: absolute;
margin: auto; z-index: 100;
left:50%; top:0;
transform:translate(-50%,0);
width: 110px; height: 86px; display: block; content: '';
background: url("../rotation3D/img/brain.svg");
animation: 6s bounceUpDown infinite;
mix-blend-mode: color-dodge;
}
@keyframes bounceUpDown{
0% {transform: translate(-50%, 0px);}
50% {transform: translate(-50%, -15px);}
100% {transform: translate(-50%, 0px);}
}

BIN
custom/public/img/i-pic-01.jpg View File

Before After
Width: 266  |  Height: 178  |  Size: 12 KiB

BIN
custom/public/img/i-pic-02.jpg View File

Before After
Width: 266  |  Height: 178  |  Size: 11 KiB

BIN
custom/public/img/i-pic-03.jpg View File

Before After
Width: 266  |  Height: 178  |  Size: 13 KiB

BIN
custom/public/img/i-pic-04.jpg View File

Before After
Width: 266  |  Height: 178  |  Size: 16 KiB

BIN
custom/public/rotation3D/img/baseLogo.png View File

Before After
Width: 342  |  Height: 470  |  Size: 86 KiB

+ 1250
- 0
custom/public/rotation3D/img/baseLogo.svg View File

@@ -0,0 +1,1250 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 342 470" style="enable-background:new 0 0 342 470;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#Shape_00000122695819581411568980000009497889965072766366_);}
.st2{opacity:0.1;}
.st3{fill:none;stroke:#FFFFFF;stroke-width:0.28;}
.st4{fill:url(#Shape-3_00000108267555528354346850000003067232586542845062_);}
.st5{fill:url(#Shape-4_00000170962892825198117240000016507644302800111752_);}
.st6{fill:url(#Shape-5_00000152233876515447885360000003511306910976081557_);}
.st7{fill:url(#Shape-6_00000130648495190739671840000000046973013901678768_);}
.st8{opacity:0.3;}
.st9{fill:url(#Shape-8_00000067238065472127621960000006688745836265094844_);}
.st10{fill:url(#Shape-9_00000092456954712643526090000013987617450999243420_);}
.st11{fill:url(#Shape-10_00000071530715909169841760000001219864674538182321_);}
.st12{fill:url(#Shape-11_00000165230558524865277990000001984831809446982565_);}
.st13{fill:url(#Shape-12_00000156578567257238376930000013792221941525112461_);}
.st14{opacity:0.7;fill:url(#Shape-13_00000008126306159044654420000001950760845656686511_);enable-background:new ;}
.st15{fill:url(#Shape-14_00000016065736020663034800000004369015118147551141_);}
.st16{fill:url(#Shape-15_00000181064846143977355770000013065309429994795172_);}
.st17{fill:url(#Shape-16_00000031208842933427054440000012996998913138616501_);}
.st18{fill:url(#Shape-17_00000042004590833602562210000013828198405825221524_);}
.st19{fill:url(#Shape-18_00000162343186294817706670000009737502018486435718_);}
.st20{fill:url(#Shape-19_00000110467135021763194980000003285448470310495882_);}
.st21{fill:#FF9E00;}
.st22{fill:#FFFA00;}
.st23{fill:#FFD500;}
.st24{fill:#0670F4;}
.st25{fill:#0E36CA;}
.st26{fill:#0D46DA;}
.st27{fill:#00FCFF;}
.st28{fill:#C1FDFF;}
.st29{fill:#D5FDFF;}
.st30{fill:url(#SVGID_00000028292880454227640480000007941185209136214710_);}
.st31{fill:url(#SVGID_00000154385744779633976780000005015552716553969280_);}
.st32{fill:url(#SVGID_00000006709808785551018910000013165181589207510424_);}
.st33{fill:url(#SVGID_00000095338393378708966320000014319984612975200675_);}
.st34{fill:url(#SVGID_00000068668409858590940130000015473191643683796407_);}
.st35{fill:url(#SVGID_00000028288024236176209350000016805078944731773867_);}
.st36{opacity:0.9;fill:url(#SVGID_00000052083955581105786130000014221709174240235702_);enable-background:new ;}
.st37{opacity:0.9;fill:url(#SVGID_00000054967982296223834670000016083193669441212831_);enable-background:new ;}
.st38{opacity:0.9;fill:url(#SVGID_00000058550955804546596240000010683206481702016433_);enable-background:new ;}
.st39{opacity:0.9;fill:url(#SVGID_00000163043534529015062880000009083868386549199238_);enable-background:new ;}
.st40{opacity:0.7;}
.st41{fill:url(#SVGID_00000022541865909815407100000001966414287944324258_);}
.st42{fill:url(#SVGID_00000147900851745622378370000015873506469329059251_);}
.st43{fill:url(#SVGID_00000145055013217083447570000004918368404700113808_);}
.st44{opacity:0.9;fill:url(#SVGID_00000078738074373176931370000005247352960480890810_);enable-background:new ;}
.st45{opacity:0.9;fill:url(#SVGID_00000154427465430184299350000014008109346215955108_);enable-background:new ;}
.st46{opacity:0.9;fill:url(#SVGID_00000026130062154451319530000009591557964573573052_);enable-background:new ;}
.st47{opacity:0.9;fill:url(#SVGID_00000071535581989694575550000006424478893357759619_);enable-background:new ;}
.st48{fill:url(#SVGID_00000103264614985634555370000015439510514986295434_);}
.st49{fill:url(#SVGID_00000026846880724049010360000004318742928612435385_);}
.st50{fill:url(#SVGID_00000097491734475124487120000017280595404574408586_);}
.st51{opacity:0.9;fill:url(#SVGID_00000132797865532330196930000016589769163445796508_);enable-background:new ;}
.st52{opacity:0.9;fill:url(#SVGID_00000168112339364709499370000010561862793508189619_);enable-background:new ;}
.st53{opacity:0.9;fill:url(#SVGID_00000016776904099699711580000006027847166532311213_);enable-background:new ;}
.st54{opacity:0.9;fill:url(#SVGID_00000046319016626353319110000001507482231880905125_);enable-background:new ;}
.st55{fill:url(#SVGID_00000015347636505443995880000009639486512516552109_);}
.st56{fill:url(#SVGID_00000183235989598679666860000008675740694265734795_);}
.st57{fill:url(#SVGID_00000057145868332245323390000003648288391810730120_);}
.st58{opacity:0.9;fill:url(#SVGID_00000052089054271150011360000006380279030166986132_);enable-background:new ;}
.st59{opacity:0.9;fill:url(#SVGID_00000053524630414669161260000014167420226363617973_);enable-background:new ;}
.st60{opacity:0.9;fill:url(#SVGID_00000102509884178040304740000009453014021517178797_);enable-background:new ;}
.st61{opacity:0.9;fill:url(#SVGID_00000030477380050973659050000012784180663325317543_);enable-background:new ;}
.st62{fill:url(#SVGID_00000091715724373744771480000018381079266578924952_);}
.st63{fill:url(#SVGID_00000119802247028098950750000007807224728487343238_);}
.st64{fill:#DCCAFF;}
.st65{fill:url(#SVGID_00000168828291550228940780000008712892453049646482_);}
.st66{opacity:0.1;fill:url(#Shape-25_00000064352820151925633680000000538003253376652973_);enable-background:new ;}
.st67{opacity:0.1;fill:url(#Shape-26_00000058578484037833382700000001443243348334247842_);enable-background:new ;}
.st68{opacity:0.2;fill:url(#Shape-27_00000021087063130939724030000008785947539258868150_);enable-background:new ;}
.st69{opacity:0.4;fill:url(#Shape-28_00000139984370226791585180000007783386812744376985_);enable-background:new ;}
.st70{opacity:0.3;fill:url(#Shape-29_00000042729723539120537750000007554992902734426797_);enable-background:new ;}
.st71{opacity:0.8;fill:url(#Shape-30_00000116193469163751414410000014389267924888205229_);enable-background:new ;}
.st72{opacity:0.3;fill:url(#Shape-31_00000106850944086934364040000006754821160458469791_);enable-background:new ;}
.st73{opacity:0.9;}
.st74{fill:url(#SVGID_00000009548216845904308100000007854279399613521282_);}
.st75{fill:url(#SVGID_00000005946657920056642410000013858148092140242342_);}
.st76{fill:url(#SVGID_00000073713187741169993790000000518297220273631625_);}
.st77{fill:url(#SVGID_00000059309463566938012110000017242277441342374043_);}
.st78{opacity:0.2;fill:url(#Shape-33_00000092442636229672753120000015708534850319685025_);enable-background:new ;}
.st79{opacity:0.2;fill:url(#Shape-34_00000134958529537706583570000013531478499757925764_);enable-background:new ;}
.st80{opacity:0.3;fill:url(#Shape-35_00000183966536320522018980000015656474600764335774_);enable-background:new ;}
.st81{fill:url(#Shape-36_00000170990332344004291830000018267268661377741450_);}
.st82{fill:url(#Shape-37_00000081606422858984196810000010929270223930003892_);}
.st83{fill:url(#Shape-38_00000012458674817368296390000007645479619492313786_);}
.st84{fill:url(#Shape-39_00000116945922626526355790000011743352812616268682_);}
.st85{opacity:0.3;fill:url(#Shape-40_00000086677837877112201530000004355660159683157898_);enable-background:new ;}
.st86{fill:url(#Shape-41_00000181072257639661971490000013152471877230270889_);}
.st87{fill:url(#Shape-42_00000029013825415492016220000014598397158487279492_);}
.st88{opacity:0.2;fill:url(#Shape-43_00000057870855683888429600000006717933375613710484_);enable-background:new ;}
.st89{fill:url(#Shape-44_00000043445091589589969460000004866174366055113897_);}
.st90{fill:url(#SVGID_00000049914507342881612690000006947427049092657283_);}
.st91{fill:url(#SVGID_00000062886325047818555730000010750219106956600486_);}
.st92{fill:url(#SVGID_00000039855526018585779520000008358089142857900196_);}
.st93{fill:url(#SVGID_00000159453068813583809450000016564471048711535496_);}
.st94{fill:url(#SVGID_00000134221892980377044910000000824006706549954479_);}
.st95{fill:url(#Shape-45_00000121983145399346318480000017454074114138980021_);}
.st96{fill:url(#Shape-46_00000056413757225724440660000013227819678561858705_);}
.st97{fill:url(#SVGID_00000081614301598355860140000013115952882911281563_);}
.st98{fill:url(#SVGID_00000018926841404133431160000004363987530718928829_);}
.st99{fill:url(#SVGID_00000170973902844277814280000011391250150203830458_);}
.st100{fill:url(#SVGID_00000016781894814342093450000000425864608846005892_);}
.st101{fill:url(#SVGID_00000085245970713286330730000013740508628486946721_);}
.st102{fill:url(#SVGID_00000163055017777087957720000005454895562531643312_);}
.st103{fill:url(#SVGID_00000077302191023187935940000015456585497225833140_);}
.st104{fill:url(#SVGID_00000180339343354334441320000012833881165672081034_);}
.st105{fill:url(#SVGID_00000096033939601719065930000002030735641467470505_);}
.st106{opacity:0.4;fill:url(#Shape-48_00000094605520090581675820000009029972832137256374_);enable-background:new ;}
.st107{opacity:0.4;fill:url(#Shape-49_00000081627112398329943590000003802171881972280741_);enable-background:new ;}
.st108{opacity:0.4;}
.st109{fill:#FFFFFF;}
.st110{fill:url(#SVGID_00000023984037287111958640000000638087594766373052_);}
.st111{fill:url(#SVGID_00000065068286938501304560000001747638327604614276_);}
.st112{fill:url(#SVGID_00000118362122578489129280000008325696647302340015_);}
.st113{fill:url(#SVGID_00000063625050672048026430000010620158812897610639_);}
.st114{fill:url(#SVGID_00000160160255246035492840000011145811528394086550_);}
.st115{fill:url(#SVGID_00000137096698933832844710000001994592634361541522_);}
.st116{fill:url(#SVGID_00000028283920064565737470000017374870854956641424_);}
.st117{fill:url(#Shape-50_00000008114939600830930650000006400205404160199078_);}
.st118{fill:url(#Shape-51_00000165940789856988529460000001895047031287773092_);}
.st119{fill:url(#Shape-52_00000071536093562577904190000014204231495092591776_);}
.st120{fill:url(#SVGID_00000104667689609266550840000001590343809853163664_);}
.st121{fill:url(#SVGID_00000174565000182971844360000009855163291799870106_);}
.st122{fill:url(#SVGID_00000101801150018074089040000006999532880097025439_);}
.st123{fill:url(#SVGID_00000010285869994318200550000017907693555620668052_);}
.st124{fill:url(#SVGID_00000040553462087727254830000018074551645053105837_);}
.st125{fill:#FFCDA4;}
.st126{fill:#F2B588;}
.st127{fill:url(#SVGID_00000151537022301235923430000015311765200172483981_);}
.st128{fill:url(#SVGID_00000095318817484922321070000012112191509524194441_);}
.st129{opacity:0.3;fill:url(#SVGID_00000090282202284851546380000005436398103980201888_);enable-background:new ;}
.st130{fill:url(#SVGID_00000176044504512350597090000016535704918049643914_);}
.st131{fill:url(#SVGID_00000147205081033068325400000014263989530912263078_);}
.st132{fill:#0726A5;}
.st133{fill:#FFCBA2;}
</style>
<g id="图层_2_00000028314812550504214100000011184653534585739162_">
<g id="图层_1-2">
<radialGradient id="SVGID_1_" cx="168.6775" cy="1400.7551" r="197.2173" gradientTransform="matrix(1 0 0 1 0 -1216.3)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.4335" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
<stop offset="0.81" style="stop-color:#D8E6FF;stop-opacity:0.12"/>
</radialGradient>
<path class="st0" d="M294.2,344.5l-1.8-2.3c-0.2-0.3-0.4-0.7-0.8-1c-16.1-21.4-48.4-55.7-48.4-111.1c0-68.9,4.3-157.7,24.4-231.9
H65.9c20.3,74.1,24.4,163,24.4,231.9c0,58.3-30.4,93.3-45.5,114.5h0.9c-0.3,0.9-0.4,1.8-0.4,2.7c0,16.9,55.7,30.6,124.5,30.6
s124.4-13.7,124.4-30.6c0-0.9-0.2-1.9-0.4-2.7L294.2,344.5z"/>
<g id="main_system">
<linearGradient id="Shape_00000178178190290349774510000015233560893010072992_" gradientUnits="userSpaceOnUse" x1="183.1534" y1="-517.9744" x2="328.6692" y2="-492.206" gradientTransform="matrix(1 0 0 -1 0 -136)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path id="Shape" style="fill:url(#Shape_00000178178190290349774510000015233560893010072992_);" d="M397.1,375.7
c0,24.4-110.9,33.1-207.2,33.1S90.5,394,90.5,375.7s3.2-33.1,99.4-33.1S397.1,352.8,397.1,375.7z"/>
<g id="Group">
<g id="Shape-2" class="st2">
<line class="st3" x1="93.1" y1="395.7" x2="93.2" y2="418"/>
<line class="st3" x1="115.2" y1="401.9" x2="115.2" y2="424.1"/>
<line class="st3" x1="141" y1="405.8" x2="141" y2="428"/>
<line class="st3" x1="196.2" y1="405.9" x2="196.2" y2="428"/>
<line class="st3" x1="221.8" y1="402.1" x2="221.8" y2="424.2"/>
<line class="st3" x1="243.8" y1="395.9" x2="243.8" y2="418.1"/>
<line class="st3" x1="260.7" y1="387.9" x2="260.7" y2="409.9"/>
<line class="st3" x1="271.2" y1="378.6" x2="271.2" y2="399.4"/>
<line class="st3" x1="65.4" y1="378.4" x2="65.4" y2="399.4"/>
<line class="st3" x1="76.1" y1="387.7" x2="76.1" y2="409.7"/>
</g>
<linearGradient id="Shape-3_00000145760133362343895620000015494310892322915463_" gradientUnits="userSpaceOnUse" x1="-4695.894" y1="-1404.8131" x2="-4695.0723" y2="-1404.8131" gradientTransform="matrix(260.74 0 0 150.88 1224468.75 212327.9531)">
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/>
<stop offset="0.12" style="stop-color:#FEFEFE"/>
<stop offset="0.52" style="stop-color:#C3D0D7"/>
<stop offset="0.83" style="stop-color:#D2DDE2"/>
<stop offset="1" style="stop-color:#CDE1E4"/>
</linearGradient>
<path id="Shape-3" style="fill:url(#Shape-3_00000145760133362343895620000015494310892322915463_);" d="M274.5,367.4v-18.7
h-17.1c-4.5-2.4-9.2-4.6-14-6.2c-41.7-15.1-109.2-15.2-150.6-0.2c-4.9,1.8-9.7,3.9-14.3,6.5H61.9v19.3
c-0.1,10.5,9.4,20.9,31.3,28.9c41.7,15.1,109.1,15.2,150.6,0.2C266.2,388.9,274.7,378,274.5,367.4z"/>
<linearGradient id="Shape-4_00000071556748890164118890000017416756969037191558_" gradientUnits="userSpaceOnUse" x1="61.7996" y1="-1129.3312" x2="274.7628" y2="-1129.3312" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#D6DCDF"/>
<stop offset="0.8" style="stop-color:#FBFBFC"/>
<stop offset="1" style="stop-color:#EEECEE"/>
</linearGradient>
<path id="Shape-4" style="fill:url(#Shape-4_00000071556748890164118890000017416756969037191558_);" d="M243.8,374.8
c-41.4,15-108.9,15-150.6-0.2s-41.9-39.6-0.4-54.7s108.9-15,150.6,0.2S285.2,359.8,243.8,374.8z"/>
<linearGradient id="Shape-5_00000180340779580305511340000000771215996181478573_" gradientUnits="userSpaceOnUse" x1="166.7489" y1="-1151.7883" x2="171.0751" y2="-1177.7562" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#66EDF0"/>
<stop offset="0.52" style="stop-color:#FCFCFC"/>
<stop offset="1" style="stop-color:#FDFDFD"/>
</linearGradient>
<path id="Shape-5" style="fill:url(#Shape-5_00000180340779580305511340000000771215996181478573_);" d="M153.8,373.5
c9.7,0.7,19.5,0.5,29.2-0.2l6.4,9.1c-13.7,1.6-27.4,1.6-41.1,0L153.8,373.5z"/>
<linearGradient id="Shape-6_00000059309760233537008680000015072254621288308152_" gradientUnits="userSpaceOnUse" x1="-4691.7974" y1="-1403.4999" x2="-4691.1182" y2="-1403.5109" gradientTransform="matrix(210.65 0 0 93.82 988467.6875 132026.375)">
<stop offset="0" style="stop-color:#5BEFF1"/>
<stop offset="0.48" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path id="Shape-6" style="fill:url(#Shape-6_00000059309760233537008680000015072254621288308152_);" d="M243.8,366.8
c-33.4,9.3-87.8,9.2-121.5-0.2c-33.6-9.4-33.8-24.6-0.4-34c33.4-9.3,87.8-9.2,121.5,0.2S277.2,357.5,243.8,366.8z"/>
<g id="Shape-7" class="st8">
<polyline class="st3" points="243.4,320.2 93.1,374.7 93.2,396.8 "/>
<polyline class="st3" points="221.2,314 115.2,380.8 115.2,403.1 "/>
<polyline class="st3" points="195.5,310.1 141,384.8 141,406.9 "/>
<polyline class="st3" points="140.4,310.1 196.2,384.9 196.2,407 "/>
<polyline class="st3" points="114.7,313.9 221.8,381 221.8,403.2 "/>
<polyline class="st3" points="92.7,320 243.8,374.9 243.8,397 "/>
<polyline class="st3" points="75.8,327.9 260.7,366.9 260.7,388.8 "/>
<polyline class="st3" points="65.3,337.3 271.3,357.6 271.3,378.4 "/>
<line class="st3" x1="61.8" y1="347.3" x2="274.8" y2="347.5"/>
<polyline class="st3" points="271.1,337.6 65.4,357.3 65.4,378.4 "/>
<polyline class="st3" points="260.3,328.1 76.1,366.7 76.1,388.7 "/>
</g>
<radialGradient id="Shape-8_00000158733441478465335610000004571177335950995117_" cx="-4688.001" cy="-1394.5853" r="0.5038" gradientTransform="matrix(179.29 0 0 65.1 840676.625 91121.4297)" gradientUnits="userSpaceOnUse">
<stop offset="0.52" style="stop-color:#6A88CB"/>
<stop offset="1" style="stop-color:#C2C6CA;stop-opacity:0"/>
</radialGradient>
<path id="Shape-8" style="fill:url(#Shape-8_00000158733441478465335610000004571177335950995117_);" d="M231.2,369
c-35.3,12.8-92.7,12.7-128.1-0.1c-35.5-12.8-35.7-33.7-0.4-46.5s92.7-12.7,128.1,0.1S266.6,356.2,231.2,369z"/>
<linearGradient id="Shape-9_00000146497141956463728220000004586364667823936442_" gradientUnits="userSpaceOnUse" x1="93.7691" y1="-1127.861" x2="239.3361" y2="-1127.4558" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/>
<stop offset="0.12" style="stop-color:#FEFEFE"/>
<stop offset="0.52" style="stop-color:#C3D0D7"/>
<stop offset="0.83" style="stop-color:#C8CED3"/>
<stop offset="1" style="stop-color:#C2C6CA"/>
</linearGradient>
<path id="Shape-9" style="fill:url(#Shape-9_00000146497141956463728220000004586364667823936442_);" d="M218.8,364.5
c-28.5,10.3-74.7,10.3-103.4-0.1s-28.8-27.2-0.3-37.6s74.7-10.3,103.4,0.1S247.3,354.1,218.8,364.5z"/>
<linearGradient id="Shape-10_00000031206731980968605630000001700956864725006976_" gradientUnits="userSpaceOnUse" x1="-4693.501" y1="-1404.2642" x2="-4692.6792" y2="-1404.2642" gradientTransform="matrix(227.64 0 0 131.39 1068501.75 184833.1719)">
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/>
<stop offset="0.12" style="stop-color:#FEFEFE"/>
<stop offset="0.52" style="stop-color:#C3D0D7"/>
<stop offset="0.83" style="stop-color:#D2DDE2"/>
<stop offset="1" style="stop-color:#CDE1E4"/>
</linearGradient>
<path id="Shape-10" style="fill:url(#Shape-10_00000031206731980968605630000001700956864725006976_);" d="M261.1,326l-0.2-11.9
l-10.3-2.6c-5.3-3.5-10.8-6.2-16.8-8.3c-36.4-13.1-95.1-13.3-131.1-0.1c-6,2.1-11.6,4.9-16.9,8.4L75.7,314l0.2,12.6v1.1l0,0
c0.7,8.3,9.9,16.5,27.3,22.9c36.4,13.1,95.1,13.3,131.1,0.1C253,343.9,261.9,334.9,261.1,326z"/>
<linearGradient id="Shape-11_00000085950511406540719030000013699986810275359133_" gradientUnits="userSpaceOnUse" x1="-4693.4814" y1="-1404.1786" x2="-4692.3643" y2="-1404.1786" gradientTransform="matrix(227.38 0 0 131.39 1067276 184810.1719)">
<stop offset="0" style="stop-color:#D6DCDF"/>
<stop offset="0.8" style="stop-color:#FBFBFC"/>
<stop offset="1" style="stop-color:#EEECEE"/>
</linearGradient>
<path id="Shape-11" style="fill:url(#Shape-11_00000085950511406540719030000013699986810275359133_);" d="M234,339
c-36,13.1-94.8,13-131.1-0.1s-36.5-34.5-0.4-47.6c36-13.1,94.7-13,131.1,0.1C269.9,304.5,270.1,325.8,234,339z"/>
<linearGradient id="Shape-12_00000013892298855937169510000007985557031648015280_" gradientUnits="userSpaceOnUse" x1="168.7642" y1="-1136.3141" x2="219.9114" y2="-1132.152" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#66EDF0"/>
<stop offset="0.52" style="stop-color:#FCFCFC"/>
<stop offset="1" style="stop-color:#FDFDFD"/>
</linearGradient>
<path id="Shape-12" style="fill:url(#Shape-12_00000013892298855937169510000007985557031648015280_);" d="M155.3,351.9v4.9
c0,0,6.7,0.5,13,0.5c7.9,0,13-0.5,13-0.5V352C172.8,352.5,164.1,352.4,155.3,351.9z"/>
<linearGradient id="Shape-13_00000064333335148225958600000018360436247913531013_" gradientUnits="userSpaceOnUse" x1="-4398.5752" y1="-1395.9125" x2="-4398.1699" y2="-1394.8937" gradientTransform="matrix(13.71 0 0 24.9 60447.8086 35122.3555)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-13" style="opacity:0.7;fill:url(#Shape-13_00000064333335148225958600000018360436247913531013_);enable-background:new ;" d="
M137.9,358.6V370c0,0,7.2,1.1,11.2,1.4v-11.7C149.1,359.7,142.2,359.3,137.9,358.6z"/>
<linearGradient id="Shape-14_00000167393322824028187890000017452476633985115545_" gradientUnits="userSpaceOnUse" x1="-3174.8132" y1="-1394.9221" x2="-3174.7368" y2="-1394.1992" gradientTransform="matrix(2.8 0 0 22.7 9024.4199 32008.8613)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-14" style="fill:url(#Shape-14_00000167393322824028187890000017452476633985115545_);" d="M136.3,358.4v11.3
l-2.2-0.4L134,358L136.3,358.4z"/>
<linearGradient id="Shape-15_00000162352495989453854700000006277651567223056573_" gradientUnits="userSpaceOnUse" x1="-4678.0532" y1="-1402.1262" x2="-4677.2319" y2="-1402.1262" gradientTransform="matrix(128.49 0 0 74.25 601315.9375 104411.4688)">
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/>
<stop offset="0.59" style="stop-color:#6DFFCB"/>
<stop offset="1" style="stop-color:#78FFD6"/>
</linearGradient>
<path id="Shape-15" style="fill:url(#Shape-15_00000162352495989453854700000006277651567223056573_);" d="M205.8,317.1
c-20.4,7.4-53.6,7.3-74.1-0.1c-20.6-7.4-20.6-19.5-0.2-26.9s53.6-7.3,74,0.1S226.2,309.6,205.8,317.1z"/>
<linearGradient id="Shape-16_00000153668204644255466410000009863565607959374214_" gradientUnits="userSpaceOnUse" x1="-4688.4077" y1="-1403.0204" x2="-4687.7285" y2="-1403.0314" gradientTransform="matrix(180.64 0 0 91.86 847058.25 129197.0469)">
<stop offset="0" style="stop-color:#C4D0D7"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path id="Shape-16" style="fill:url(#Shape-16_00000153668204644255466410000009863565607959374214_);" d="M231.5,332
c-28.7,9.2-75.2,9.1-104.2-0.1s-29-24.1-0.3-33.3s75.4-9.1,104.2,0.1S260.2,322.9,231.5,332z"/>
<linearGradient id="Shape-17_00000081607492502552466440000007433058223660923029_" gradientUnits="userSpaceOnUse" x1="-4685.3496" y1="-1402.9875" x2="-4684.5391" y2="-1402.9875" gradientTransform="matrix(158.96 0 0 91.86 744883 129192.7344)">
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/>
<stop offset="0.12" style="stop-color:#FEFEFE"/>
<stop offset="0.52" style="stop-color:#C3D0D7"/>
<stop offset="0.83" style="stop-color:#DAE5EA"/>
<stop offset="1" style="stop-color:#CDE1E4"/>
</linearGradient>
<path id="Shape-17" style="fill:url(#Shape-17_00000081607492502552466440000007433058223660923029_);" d="M233.4,313.6v-8.2
h-1.9c-2.7-4.1-8.5-4.5-17.3-7.7c-25.3-9.2-66.4-9.3-91.6-0.1c-8.8,3.2-14.5,3.7-17.1,7.8h-1.8v9l0,0c0.1,6,6.6,11.9,19.2,16.5
c25.4,9.2,66.5,9.3,91.7,0.1C227.7,326.2,234,319.8,233.4,313.6z"/>
<linearGradient id="Shape-18_00000000935785368065642490000001491826445201081248_" gradientUnits="userSpaceOnUse" x1="111.9444" y1="-1088.2948" x2="239.703" y2="-1085.6005" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#E8E8E8"/>
<stop offset="0.53" style="stop-color:#FBFBFC"/>
</linearGradient>
<path id="Shape-18" style="fill:url(#Shape-18_00000000935785368065642490000001491826445201081248_);" d="M214.6,321.8
c-25.2,9.2-66.3,9.1-91.7-0.1s-25.5-24.1-0.3-33.3s66.3-9.1,91.7,0.1S239.9,312.6,214.6,321.8z"/>
<linearGradient id="Shape-19_00000159470190286743471590000007947123095774400143_" gradientUnits="userSpaceOnUse" x1="-4688.3633" y1="-1403.1714" x2="-4687.8926" y2="-1403.1821" gradientTransform="matrix(180.64 0 0 91.86 847058.25 129197.0469)">
<stop offset="0" style="stop-color:#C4D0D7"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path id="Shape-19" style="fill:url(#Shape-19_00000159470190286743471590000007947123095774400143_);" d="M211.9,313.6
c-20.2,6.7-52.8,6.6-73.1-0.1s-20.4-17.5-0.2-24.2s52.8-6.6,73.1,0.1S232.1,306.9,211.9,313.6z"/>
<ellipse class="st21" cx="169.8" cy="299.6" rx="46.7" ry="18.4"/>
<rect x="123.1" y="283.4" class="st21" width="93.3" height="16.3"/>
<ellipse class="st22" cx="169.8" cy="283.4" rx="46.7" ry="18.6"/>
<ellipse class="st23" cx="169.8" cy="283" rx="46.7" ry="18.4"/>
<ellipse class="st24" cx="169.8" cy="281.8" rx="39.6" ry="15.7"/>
<ellipse class="st25" cx="169.8" cy="281.8" rx="27.5" ry="10.8"/>
<ellipse class="st26" cx="169.8" cy="281.8" rx="20.9" ry="8.2"/>
<ellipse class="st27" cx="169.8" cy="281.8" rx="16" ry="6.4"/>
<path class="st28" d="M179.2,281.8c0,2.1-4.2,3.7-9.4,3.7c-5.3,0-9.4-1.6-9.4-3.7s4.2-3.7,9.4-3.7
C175,278.1,179.2,279.7,179.2,281.8z"/>
<ellipse class="st29" cx="203.1" cy="280.9" rx="2.8" ry="1.1"/>
<ellipse class="st29" cx="169" cy="268.3" rx="2.8" ry="1.1"/>
<path class="st29" d="M139.7,281.2c0,0.7-1.3,1.1-2.8,1.1s-2.8-0.5-2.8-1.1s1.3-1.1,2.8-1.1S139.7,280.6,139.7,281.2z"/>
<ellipse class="st29" cx="148.6" cy="293.1" rx="2.8" ry="1.1"/>
<ellipse class="st29" cx="189.2" cy="293.1" rx="2.8" ry="1.1"/>
<linearGradient id="SVGID_00000139277114413283346430000003203015687710406051_" gradientUnits="userSpaceOnUse" x1="203.143" y1="819.6531" x2="203.0444" y2="875.5317" gradientTransform="matrix(1 0 0 1 0 -592.21)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<path style="fill:url(#SVGID_00000139277114413283346430000003203015687710406051_);" d="M206.6,277.1c0,1.2-1.5,2.2-3.5,2.2
l0,0c-2,0-3.5-1-3.5-2.2v-50.5l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V277.1z"/>
<linearGradient id="SVGID_00000183221014587477581410000000706386369785952431_" gradientUnits="userSpaceOnUse" x1="169.1382" y1="807.0799" x2="169.0506" y2="862.9583" gradientTransform="matrix(1 0 0 1 0 -592.21)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<path style="fill:url(#SVGID_00000183221014587477581410000000706386369785952431_);" d="M172.6,264.5c0,1.2-1.5,2.2-3.5,2.2
l0,0c-2,0-3.5-1-3.5-2.2V214l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V264.5z"/>
<linearGradient id="SVGID_00000039096372971356690410000012421145682396891277_" gradientUnits="userSpaceOnUse" x1="189.4431" y1="826.3558" x2="189.3446" y2="888.3239" gradientTransform="matrix(1 0 0 1 0 -592.21)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<path style="fill:url(#SVGID_00000039096372971356690410000012421145682396891277_);" d="M192.9,289.5c0,1.2-1.5,2.2-3.5,2.2
l0,0c-2,0-3.5-1-3.5-2.2v-56.4l0,0V233c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V289.5z"/>
<linearGradient id="SVGID_00000013163074585285730020000005816107648387152776_" gradientUnits="userSpaceOnUse" x1="148.6431" y1="826.3557" x2="148.5445" y2="888.3237" gradientTransform="matrix(1 0 0 1 0 -592.21)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<path style="fill:url(#SVGID_00000013163074585285730020000005816107648387152776_);" d="M152.1,289.5c0,1.2-1.5,2.2-3.5,2.2
l0,0c-2,0-3.5-1-3.5-2.2v-56.4l0,0V233c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V289.5z"/>
<linearGradient id="SVGID_00000033367422727462969740000017109666248109283748_" gradientUnits="userSpaceOnUse" x1="136.9382" y1="819.653" x2="136.8506" y2="875.5316" gradientTransform="matrix(1 0 0 1 0 -592.21)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<path style="fill:url(#SVGID_00000033367422727462969740000017109666248109283748_);" d="M140.4,277.1c0,1.2-1.5,2.2-3.5,2.2
l0,0c-2,0-3.5-1-3.5-2.2v-50.5l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V277.1z"/>
</g>
<g id="Group-2">
<g id="Shape-20">
<linearGradient id="SVGID_00000066491685535550283050000010067348639462920879_" gradientUnits="userSpaceOnUse" x1="83.7" y1="-1141.8" x2="96.2" y2="-1141.8" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000066491685535550283050000010067348639462920879_);" d="M96.2,359.8c0,1.5-4.5,2.2-8.4,2.2
s-4.1-1-4.1-2.2s0.1-2.2,4.1-2.2C91.7,357.6,96.2,358.3,96.2,359.8z"/>
<linearGradient id="SVGID_00000028319550724681881430000017225317771668268424_" gradientUnits="userSpaceOnUse" x1="89.9811" y1="-1142.4447" x2="82.3912" y2="-1140.8129" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000028319550724681881430000017225317771668268424_);enable-background:new ;" d="
M90.5,359.7v-0.8h-0.1c-0.1-0.3-0.5-0.4-1-0.7c-1.6-0.9-3.6-0.9-5.3,0c-0.5,0.3-0.9,0.3-1,0.8H83v0.8l0,0
c0.1,0.7,0.4,1.2,1.1,1.5c1.6,0.9,3.6,0.9,5.3,0C89.9,361,90.4,360.3,90.5,359.7z"/>
<linearGradient id="SVGID_00000078734006496365647220000003596442759833680783_" gradientUnits="userSpaceOnUse" x1="74.6527" y1="-1139.2683" x2="91.3549" y2="-1141.5902" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000078734006496365647220000003596442759833680783_);enable-background:new ;" d="
M89.4,360.5c-1.6,0.9-3.6,0.9-5.3,0c-1.4-0.9-1.4-2.2,0-3.1c1.6-0.9,3.6-0.9,5.3,0C90.8,358.2,90.8,359.6,89.4,360.5z"/>
<linearGradient id="SVGID_00000016778492564968718270000007715733383074586243_" gradientUnits="userSpaceOnUse" x1="-4461.2017" y1="-1399.1519" x2="-4461.1797" y2="-1399.8967" gradientTransform="matrix(17.18 0 0 41.2 76732.1953 58011.2617)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000016778492564968718270000007715733383074586243_);enable-background:new ;" d="
M92.6,339.1c-0.9-0.9-2-1.2-2.7-0.4l-3.6,3.4c-1,1-1.6,2.4-1.6,3.8l0,0v12.3l0,0c0,0.5,1,1.1,2.2,1.1s2.1-0.4,2.2-0.9v-0.1
v-12.2c0-0.3,0.1-0.5,0.3-0.9l3.6-3.5C93.7,341,93.3,340,92.6,339.1z"/>
<linearGradient id="SVGID_00000110445505960899282040000008185106537552059583_" gradientUnits="userSpaceOnUse" x1="87.1364" y1="-1123.8972" x2="94.5402" y2="-1120.8854" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000110445505960899282040000008185106537552059583_);enable-background:new ;" d="
M92.8,341.8c-0.9,0.5-2.1,0.3-2.6-0.5c-0.8-0.7-0.9-1.9-0.3-2.7c0.7-0.5,1.6-0.4,2.6,0.5C93.4,340.1,93.4,341.2,92.8,341.8z"/>
<g class="st40">
<linearGradient id="SVGID_00000051370268289873400610000018298761055778287753_" gradientUnits="userSpaceOnUse" x1="-4205.8408" y1="-1377.0852" x2="-4204.7896" y2="-1376.0007" gradientTransform="matrix(8.51 0 0 9.65 35874.4414 13634.9932)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000051370268289873400610000018298761055778287753_);" d="M82.9,347.3c1.5,2.3,4.2,3.6,6.9,3.5
v1.3c-2.5,0.4-5-0.4-6.9-2.2V347.3L82.9,347.3z"/>
<linearGradient id="SVGID_00000022539495148538625040000011656406462773614524_" gradientUnits="userSpaceOnUse" x1="-4203.5879" y1="-1360.5885" x2="-4202.3726" y2="-1359.7999" gradientTransform="matrix(8.48 0 0 6.06 35729.3945 8596.1113)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000022539495148538625040000011656406462773614524_);" d="M82.9,350.6c0,0,1.1,2.3,6.9,2.2v0.9
c0,0-5,0.3-6.9-1.8V350.6z"/>
</g>
</g>
<g id="Shape-21">
<linearGradient id="SVGID_00000053529045596386359860000012693715221203522699_" gradientUnits="userSpaceOnUse" x1="-4537.0894" y1="-1374.7428" x2="-4536.6074" y2="-1374.7318" gradientTransform="matrix(24.44 0 0 8.38 111101.9062 11894.1025)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000053529045596386359860000012693715221203522699_);" d="M229.8,373.8c0,1.6-4.8,2.2-8.9,2.2
c-4.1,0-4.3-1-4.3-2.2s0.1-2.2,4.3-2.2C225.1,371.6,229.8,372.3,229.8,373.8z"/>
<linearGradient id="SVGID_00000016041242089640294250000005076626961659910032_" gradientUnits="userSpaceOnUse" x1="-4419.8472" y1="-1374.6202" x2="-4420.3838" y2="-1374.6202" gradientTransform="matrix(14.67 0 0 8.48 65064.1992 12030.4795)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000016041242089640294250000005076626961659910032_);enable-background:new ;" d="
M215.8,373.6v-0.8h0.1c0.1-0.4,0.5-0.4,1.1-0.7c1.8-0.9,3.8-0.9,5.6,0c0.5,0.3,0.9,0.3,1.1,0.8h0.1v0.9l0,0
c-0.1,0.7-0.5,1.3-1.2,1.5c-1.8,0.9-3.8,0.9-5.6,0C216.3,375,215.9,374.4,215.8,373.6z"/>
<linearGradient id="SVGID_00000034051049874645699850000001054443060867366060_" gradientUnits="userSpaceOnUse" x1="210.2652" y1="-1156.347" x2="223.9993" y2="-1154.1678" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000034051049874645699850000001054443060867366060_);enable-background:new ;" d="
M216.9,374.4c1.8,0.9,3.8,0.9,5.6,0c1.5-0.9,1.5-2.2,0-3.1c-1.8-0.9-3.8-0.9-5.6,0C215.3,372.2,215.3,373.5,216.9,374.4z"/>
<linearGradient id="SVGID_00000140705939172839159610000000673615029388288165_" gradientUnits="userSpaceOnUse" x1="-4461.4771" y1="-1400.4607" x2="-4461.4556" y2="-1401.49" gradientTransform="matrix(17.1 0 0 49.17 76508.5 69238.9375)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000140705939172839159610000000673615029388288165_);enable-background:new ;" d="
M213.6,349.5c0.8-0.9,2-1,2.8-0.3l3.7,3.5c1.1,1,1.8,2.4,1.8,3.8v16.4l0,0c0,0.5-1,1.1-2.3,1.1s-2.3-0.4-2.3-1.1v-16.3
c0-0.3-0.1-0.7-0.4-0.9l-3.7-3.5C212.6,351.5,212.7,350.2,213.6,349.5L213.6,349.5z"/>
<linearGradient id="SVGID_00000016069627382271396290000009179125164610461070_" gradientUnits="userSpaceOnUse" x1="211.3378" y1="-1132.3972" x2="217.6791" y2="-1132.7916" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000016069627382271396290000009179125164610461070_);enable-background:new ;" d="
M213.1,352.2c0.9,0.5,2.1,0.3,2.7-0.5c0.9-0.7,1-1.8,0.3-2.6c0,0,0,0,0-0.1c-0.9-0.5-2.1-0.3-2.8,0.5
C212.7,350.2,212.5,351.4,213.1,352.2C213.1,352.1,213.1,352.2,213.1,352.2z"/>
<g class="st40">
<linearGradient id="SVGID_00000023992425455839354290000003462269822397537668_" gradientUnits="userSpaceOnUse" x1="-4209.4048" y1="-1378.4917" x2="-4208.3643" y2="-1377.4075" gradientTransform="matrix(8.51 0 0 9.65 36039.0703 13662.6221)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000023992425455839354290000003462269822397537668_);" d="M217.2,361.4
c1.5,2.3,4.2,3.6,6.9,3.5v1.3c-2.5,0.4-5-0.4-6.9-2.2V361.4L217.2,361.4z"/>
<linearGradient id="SVGID_00000161610153219861893360000018069820855094444985_" gradientUnits="userSpaceOnUse" x1="-4207.1631" y1="-1362.8098" x2="-4205.9478" y2="-1362.0103" gradientTransform="matrix(8.48 0 0 6.06 35894.0234 8623.752)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000161610153219861893360000018069820855094444985_);" d="M217.2,364.8c0,0,1.1,2.3,6.9,2.2
v0.9c0,0-5,0.3-6.9-1.8V364.8z"/>
</g>
</g>
<g id="Shape-22">
<linearGradient id="SVGID_00000101097610753023437160000010300393479110564788_" gradientUnits="userSpaceOnUse" x1="-4537.3999" y1="-1373.2405" x2="-4536.9399" y2="-1373.2295" gradientTransform="matrix(24.44 0 0 8.38 111140.0703 11867.9131)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000101097610753023437160000010300393479110564788_);" d="M259.7,360.2c0,1.6-4.6,2.2-8.5,2.2
s-4.1-1-4.1-2.2s0.1-2.2,4.1-2.2S259.7,358.7,259.7,360.2z"/>
<linearGradient id="SVGID_00000057826871241478005110000007594934890897262214_" gradientUnits="userSpaceOnUse" x1="-4420.3882" y1="-1373.1334" x2="-4420.9033" y2="-1373.1334" gradientTransform="matrix(14.67 0 0 8.48 65102.3398 12004.2705)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000057826871241478005110000007594934890897262214_);enable-background:new ;" d="
M246.3,360v-0.8h0.1c0.1-0.3,0.5-0.4,1-0.7c1.6-0.9,3.7-0.9,5.4,0c0.5,0.3,0.9,0.3,1,0.8h0.1v0.9l0,0c-0.1,0.7-0.4,1.2-1.1,1.5
c-1.6,0.9-3.7,0.9-5.4,0C246.8,361.3,246.3,360.8,246.3,360z"/>
<linearGradient id="SVGID_00000034069503416819206880000007783290857966879909_" gradientUnits="userSpaceOnUse" x1="241.1007" y1="-1144.2089" x2="255.5578" y2="-1139.4556" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000034069503416819206880000007783290857966879909_);enable-background:new ;" d="
M247.4,360.8c1.6,0.9,3.7,0.9,5.4,0c1.5-0.9,1.5-2.2,0-3.1c-1.6-0.9-3.7-0.9-5.4,0C245.9,358.6,245.9,359.9,247.4,360.8z"/>
<linearGradient id="SVGID_00000074402755482888099360000011871301802014376069_" gradientUnits="userSpaceOnUse" x1="-4463.228" y1="-1399.1514" x2="-4463.2495" y2="-1399.8962" gradientTransform="matrix(17.18 0 0 41.2 76926.3984 58012.0977)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000074402755482888099360000011871301802014376069_);enable-background:new ;" d="
M244.2,339.5c1-0.9,2-1.2,2.7-0.4l3.6,3.5c1.1,1,1.6,2.4,1.8,3.8l0,0v12.3l0,0c0,0.5-1,1.1-2.2,1.1s-2.1-0.4-2.2-0.9v-0.1
v-12.3c0-0.3-0.1-0.7-0.3-0.9l-3.6-3.5C243,341.4,243.4,340.4,244.2,339.5z"/>
<linearGradient id="SVGID_00000034800493623832042920000008020736596099291557_" gradientUnits="userSpaceOnUse" x1="235.944" y1="-1125.0896" x2="250.39" y2="-1121.2892" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000034800493623832042920000008020736596099291557_);enable-background:new ;" d="
M243.9,342.2c0.9,0.5,2.1,0.3,2.6-0.5c0.8-0.7,1-1.9,0.3-2.7c-0.7-0.5-1.6-0.4-2.6,0.5C243.3,340.4,243.3,341.6,243.9,342.2z"
/>
<g class="st40">
<linearGradient id="SVGID_00000006704291500926620380000004171103234775810997_" gradientUnits="userSpaceOnUse" x1="-4208.7266" y1="-1376.4762" x2="-4207.8501" y2="-1375.5673" gradientTransform="matrix(8.47 0 0 9.55 35885.875 13484.8174)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000006704291500926620380000004171103234775810997_);" d="M246.3,349c0,0,1.3,3.5,4.9,3.5v1.3
c-2,0.3-3.8-0.5-4.9-2.2V349z"/>
<linearGradient id="SVGID_00000177484813400042119220000011015524536336387207_" gradientUnits="userSpaceOnUse" x1="-4210.5615" y1="-1360.016" x2="-4209.5977" y2="-1359.3917" gradientTransform="matrix(8.51 0 0 6.07 36075.9102 8607.5488)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000177484813400042119220000011015524536336387207_);" d="M246.3,352.4c0,0,0.9,2.3,4.9,2.2
v0.9c0,0-3.6,0.3-4.9-1.8V352.4z"/>
</g>
</g>
<g id="Shape-23">
<linearGradient id="SVGID_00000150793386108511341090000013432375121497242256_" gradientUnits="userSpaceOnUse" x1="111" y1="-1155.8" x2="123.6828" y2="-1155.8" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000150793386108511341090000013432375121497242256_);" d="M123.7,373.8c0,1.5-4.6,2.2-8.5,2.2
s-4.2-1-4.2-2.2s0.1-2.2,4.2-2.2C119.1,371.6,123.7,372.3,123.7,373.8z"/>
<linearGradient id="SVGID_00000173862521492696290410000004963765814931415984_" gradientUnits="userSpaceOnUse" x1="117.3702" y1="-1156.4034" x2="109.6817" y2="-1154.7496" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000173862521492696290410000004963765814931415984_);enable-background:new ;" d="
M117.9,373.6v-0.8h-0.1c-0.2-0.3-0.5-0.4-1-0.7c-1.6-0.9-3.7-0.9-5.4,0c-0.5,0.3-0.9,0.3-1,0.8h-0.1v0.9l0,0
c0.1,0.7,0.4,1.2,1.1,1.5c1.6,0.9,3.7,0.9,5.4,0C117.3,374.9,117.7,374.4,117.9,373.6z"/>
<linearGradient id="SVGID_00000020398109177578560470000006450052471999083696_" gradientUnits="userSpaceOnUse" x1="101.8376" y1="-1153.1447" x2="118.7699" y2="-1155.4994" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000020398109177578560470000006450052471999083696_);enable-background:new ;" d="
M116.8,374.4c-1.6,0.9-3.7,0.9-5.4,0c-1.5-0.9-1.5-2.2,0-3.1c1.6-0.9,3.7-0.9,5.4,0C118.2,372.2,118.2,373.5,116.8,374.4z"/>
<linearGradient id="SVGID_00000146469520690687921700000001834666537324208572_" gradientUnits="userSpaceOnUse" x1="-4459.6167" y1="-1398.7903" x2="-4459.5947" y2="-1399.6775" gradientTransform="matrix(17.18 0 0 41.2 76732.1953 58011.2617)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000146469520690687921700000001834666537324208572_);enable-background:new ;" d="
M119.9,349.4c-0.9-0.9-2-1.2-2.7-0.4l-3.6,3.5c-1.1,1-1.6,2.4-1.8,3.8l0,0v12.3v3.9c0,0.5,1,1.1,2.2,1.1s2.1-0.4,2.2-0.9v-0.1
v-16.2c0-0.3,0.1-0.7,0.3-0.9l3.6-3.5C121.1,351.3,120.8,350.3,119.9,349.4z"/>
<linearGradient id="SVGID_00000146461411017424176850000008273474735748943006_" gradientUnits="userSpaceOnUse" x1="114.4784" y1="-1134.2108" x2="121.9807" y2="-1131.1552" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="1.000000e-02" style="stop-color:#5C6672"/>
<stop offset="0.28" style="stop-color:#5F87B2"/>
<stop offset="0.81" style="stop-color:#A7DFF9"/>
</linearGradient>
<path style="opacity:0.9;fill:url(#SVGID_00000146461411017424176850000008273474735748943006_);enable-background:new ;" d="
M120.3,352.1c-0.9,0.5-2.1,0.3-2.7-0.5c-0.8-0.7-1-1.9-0.3-2.7c0.7-0.7,1.8-0.4,2.6,0.5C120.7,350.4,120.9,351.5,120.3,352.1z"
/>
<g class="st40">
<linearGradient id="SVGID_00000085959571847769126780000003905589832501502136_" gradientUnits="userSpaceOnUse" x1="-4202.5493" y1="-1376.0286" x2="-4201.4976" y2="-1374.9441" gradientTransform="matrix(8.51 0 0 9.65 35874.4414 13634.9932)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000085959571847769126780000003905589832501502136_);" d="M111,357.6c1.5,2.3,4.2,3.6,6.9,3.5
v1.3c-2.5,0.4-5.1-0.4-6.9-2.2V357.6L111,357.6z"/>
<linearGradient id="SVGID_00000101066731764067032500000013534230380051260331_" gradientUnits="userSpaceOnUse" x1="-4200.2793" y1="-1358.8921" x2="-4199.064" y2="-1358.1035" gradientTransform="matrix(8.48 0 0 6.06 35729.3945 8596.1113)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path style="fill:url(#SVGID_00000101066731764067032500000013534230380051260331_);" d="M111,360.9c0,0,1.1,2.3,6.9,2.2v0.9
c0,0-5,0.3-6.9-1.8V360.9z"/>
</g>
</g>
</g>
<path id="Shape-24" class="st64" d="M101.5,377.4c0,0,2,0.7,5.5,1.5c1.8,0.4,3.9,1,6.4,1.5c2.4,0.5,5.4,1.1,8.4,1.6
c1.5,0.2,3.2,0.5,4.9,0.8l2.6,0.4l2.6,0.3c0.9,0.1,1.9,0.2,2.7,0.3l2.8,0.3c2,0.2,3.9,0.4,5.9,0.5l3.1,0.2l3.1,0.2
c2.1,0.1,4.2,0.2,6.4,0.3c1.1,0.1,2.1,0.1,3.2,0.1s2.2,0.1,3.2,0.1h3.3h1.6h1.6c2.2,0,4.3,0,6.5-0.1h3.1l3.2-0.1l3.2-0.1l3.1-0.2
c1-0.1,2.1-0.1,3.1-0.2l3.1-0.3l3-0.3l3-0.3l2.8-0.3c1-0.1,1.9-0.2,2.7-0.4l2.6-0.4l1.3-0.2l1.3-0.2l4.9-0.9
c1.5-0.3,3.1-0.5,4.5-0.9s2.7-0.5,3.9-0.9l3.5-0.8l1.5-0.3l1.4-0.3l5.5-1.4l-5.5,1.4c-0.4,0.1-0.9,0.2-1.4,0.3l-1.5,0.3l-3.5,0.8
c-1.2,0.3-2.6,0.5-3.9,0.9s-2.8,0.5-4.5,0.9l-4.9,0.9l-1.3,0.2l-1.3,0.2l-2.6,0.4c-0.9,0.1-1.9,0.2-2.7,0.4l-2.8,0.3l-3,0.3
l-3,0.3l-3.1,0.3c-1,0.1-2.1,0.1-3.1,0.2l-3.2,0.2l-3.2,0.1c-1.1,0-2.2,0.1-3.2,0.1l-3.2,0.1c-2.2,0.1-4.3,0.1-6.5,0.1H167h-1.6
h-3.3l-3.2-0.1c-1.1,0-2.2-0.1-3.2-0.1c-2.1-0.1-4.3-0.2-6.4-0.4l-3.1-0.2l-3-0.3c-2-0.1-3.9-0.4-5.9-0.7l-2.8-0.3
c-0.9-0.1-1.9-0.2-2.7-0.3l-2.7-0.4l-2.6-0.4c-1.8-0.2-3.3-0.5-4.9-0.8c-3.1-0.5-5.9-1.1-8.4-1.6s-4.6-1.1-6.4-1.5
C103.5,378,101.5,377.4,101.5,377.4z"/>
</g>
<radialGradient id="SVGID_00000152945109931711952980000000514259528298555047_" cx="164.9579" cy="-350.9658" r="213.7317" gradientTransform="matrix(1 0 0 -1 0 -136)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#2AC6FF;stop-opacity:0.7"/>
<stop offset="0.6704" style="stop-color:#2AC6FF;stop-opacity:0.3"/>
<stop offset="0.9329" style="stop-color:#FFFFFF;stop-opacity:0"/>
</radialGradient>
<path style="fill:url(#SVGID_00000152945109931711952980000000514259528298555047_);" d="M294.2,344.5l-1.8-2.3
c-0.2-0.3-0.4-0.7-0.8-1c-16.1-21.4-48.4-55.7-48.4-111.1c0-68.9,4.3-157.7,24.4-231.9H65.9c20.3,74.1,24.4,163,24.4,231.9
c0,58.3-30.4,93.3-45.5,114.5h0.9c-0.3,0.9-0.4,1.8-0.4,2.7c0,16.9,55.7,30.6,124.5,30.6s124.4-13.7,124.4-30.6
c0-0.9-0.2-1.9-0.4-2.7L294.2,344.5z"/>
<linearGradient id="Shape-25_00000062897884857159563720000017493666428800170661_" gradientUnits="userSpaceOnUse" x1="-3138.2468" y1="-1399.6875" x2="-3138.2468" y2="-1399.1289" gradientTransform="matrix(2.13 0 0 135.17 6832.7236 189269.7344)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="0.41" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-25" style="opacity:0.1;fill:url(#Shape-25_00000062897884857159563720000017493666428800170661_);enable-background:new ;" d="
M148.3,81.3c-0.5,0-1,0.4-1,1l0,0v102.2c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0V82.3C149.3,81.7,148.9,81.3,148.3,81.3L148.3,81.3z"/>
<linearGradient id="Shape-26_00000096747381355368235380000013244751307849799820_" gradientUnits="userSpaceOnUse" x1="-3141.8672" y1="-1399.7417" x2="-3141.8672" y2="-1399.1831" gradientTransform="matrix(2.13 0 0 135.17 6894.334 189301.5781)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="0.41" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-26" style="opacity:0.1;fill:url(#Shape-26_00000096747381355368235380000013244751307849799820_);enable-background:new ;" d="
M202.2,105.8c-0.5,0-1,0.4-1,1v102.1c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0V106.9C203.2,106.4,202.7,105.8,202.2,105.8z"/>
<linearGradient id="Shape-27_00000119823744966612805220000010319973446294606232_" gradientUnits="userSpaceOnUse" x1="-3136.2" y1="-1399.7588" x2="-3136.2" y2="-1399.1892" gradientTransform="matrix(2.13 0 0 135.17 6791.6636 189308.4531)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="0.41" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-27" style="opacity:0.2;fill:url(#Shape-27_00000119823744966612805220000010319973446294606232_);enable-background:new ;" d="
M111.6,110.1c-0.5,0-1,0.4-1,1l0,0v102.2c0,0.5,0.4,1,0.9,1s1-0.4,1-1l0,0V111.1C112.6,110.6,112.2,110.2,111.6,110.1L111.6,110.1
z"/>
<linearGradient id="Shape-28_00000103240500498414136000000006526299530864732311_" gradientUnits="userSpaceOnUse" x1="-2292.4885" y1="-1395.9701" x2="-2292.4885" y2="-1395.4005" gradientTransform="matrix(1.38 0 0 87.55 3393.5439 122396.2578)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="0.41" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-28" style="opacity:0.4;fill:url(#Shape-28_00000103240500498414136000000006526299530864732311_);enable-background:new ;" d="
M230,172.8c-0.3,0-0.7,0.3-0.7,0.7l0,0v66.2c0,0.3,0.2,0.7,0.5,0.7l0,0c0.3,0,0.7-0.3,0.7-0.7l0,0v-66.2
C230.6,173.2,230.3,172.8,230,172.8z"/>
<linearGradient id="Shape-29_00000003076700492934946240000003238066575396519355_" gradientUnits="userSpaceOnUse" x1="-3137.2019" y1="-1396.8502" x2="-3137.2019" y2="-1396.2916" gradientTransform="matrix(2.13 0 0 94.53 6812.8838 132233.6719)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="0.41" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-29" style="opacity:0.3;fill:url(#Shape-29_00000003076700492934946240000003238066575396519355_);enable-background:new ;" d="
M130.6,191.5c-0.5,0-1,0.4-0.9,1v70.9c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0v-70.9C131.5,191.9,131.1,191.5,130.6,191.5z"/>
<linearGradient id="Shape-30_00000142141291087823972360000005780631530962408337_" gradientUnits="userSpaceOnUse" x1="165.1285" y1="-976.6299" x2="164.8766" y2="-910.3356" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.5"/>
<stop offset="0.99" style="stop-color:#12FFF7;stop-opacity:0"/>
</linearGradient>
<path id="Shape-30" style="opacity:0.8;fill:url(#Shape-30_00000142141291087823972360000005780631530962408337_);enable-background:new ;" d="
M165.3,195.1c-24.6,0-48-3.5-65.4-10s-27.4-15.2-27.4-24.4s9.5-17.9,26.9-24.2s40.5-10,65.3-10s47.9,3.5,65.4,10
s27.4,15.2,27.4,24.4s-9.5,17.7-26.9,24.2c-2.6,1-5.5,2-8.5,2.8c-11.2,3.2-22.7,5.1-34.2,6.1C180.5,194.8,172.9,195.1,165.3,195.1
z M164.7,127.1c-24.5,0-47.5,3.5-64.7,10c-17.3,6.4-26.6,14.7-26.6,23.7s9.6,17.4,26.9,23.9s40.4,10,64.9,10
c7.6,0,15.1-0.3,22.3-1c11.5-1,22.9-3.1,34-6.1c3-0.9,5.8-1.8,8.4-2.7c17.1-6.4,26.5-14.8,26.5-23.7s-9.6-17.5-26.9-23.9
C212.3,130.8,189.3,127.1,164.7,127.1z"/>
<linearGradient id="Shape-31_00000047765179999079558420000018338508616989585558_" gradientUnits="userSpaceOnUse" x1="-4556.9941" y1="-423.3402" x2="-4561.7476" y2="-464.8384" gradientTransform="matrix(77.04 0 0 111.08 359914.0938 155486.75)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="1" style="stop-color:#2AFADF"/>
</linearGradient>
<path id="Shape-31" style="opacity:0.3;fill:url(#Shape-31_00000047765179999079558420000018338508616989585558_);enable-background:new ;" d="
M235.5,241.1c-6.9,2.7-14,4.9-21.2,6.6c-2.6,0.7-4.7-0.9-4.7-3.3v-28.1c0-2.4,2.1-4.7,4.7-5.4c7.2-1.6,14.3-3.8,21.2-6.6
c3.4-1.4,6.8-2.8,10-4.5c20.4-10.4,30.8-24,31.4-37.6v34.3c0.5,14.5-9.9,29-31.4,40.1C242.3,238.2,238.9,239.7,235.5,241.1z"/>
<g id="Shape-32" class="st73">
<linearGradient id="SVGID_00000083767028849843557540000003015893000703474077_" gradientUnits="userSpaceOnUse" x1="-3997.0054" y1="-1331.5676" x2="-3997.0054" y2="-1330.6367" gradientTransform="matrix(4.67 0 0 12.58 18914.2656 16962.2617)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000083767028849843557540000003015893000703474077_);" points="250.3,228.9 250.3,221.8
246.2,223.9 246.2,231.6 "/>
<linearGradient id="SVGID_00000000215917149092826270000018230445423745942943_" gradientUnits="userSpaceOnUse" x1="-4006.7764" y1="-1383.0823" x2="-4006.7654" y2="-1381.5378" gradientTransform="matrix(4.74 0 0 36.55 19216.0312 50684.7617)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path style="fill:url(#SVGID_00000000215917149092826270000018230445423745942943_);" d="M226.1,240.6c-1.3,0.4-2.7,0.9-4.1,1.3
l-0.1-26.9c1.3-0.4,2.7-0.8,4.1-1.2L226.1,240.6z"/>
<linearGradient id="SVGID_00000127760218784342968640000002359079861741369269_" gradientUnits="userSpaceOnUse" x1="-4002.3381" y1="-1369.6538" x2="-4002.3381" y2="-1368.5916" gradientTransform="matrix(4.7 0 0 25.06 19043.0879 34513.9961)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path style="fill:url(#SVGID_00000127760218784342968640000002359079861741369269_);" d="M234.2,237.6l-2.2,0.9l-1.9,0.8
l-0.1-17.7h0.1l1.9-0.8c0.8-0.3,1.4-0.5,2.2-0.9V237.6z"/>
<linearGradient id="SVGID_00000025411509199572341930000014536893160322097330_" gradientUnits="userSpaceOnUse" x1="-4005.9248" y1="-1380.2017" x2="-4005.9248" y2="-1379.1831" gradientTransform="matrix(4.73 0 0 34.85 19188.4746 48291.8477)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path style="fill:url(#SVGID_00000025411509199572341930000014536893160322097330_);" d="M242.5,233.6l-1.3,0.7
c-0.9,0.4-1.8,0.9-2.7,1.3l-0.1-24.8l4.1-2.1V233.6z"/>
</g>
<linearGradient id="Shape-33_00000137132446951879004030000008177934085669183874_" gradientUnits="userSpaceOnUse" x1="247.2798" y1="-966.5903" x2="243.775" y2="-1045.7864" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#30E4E5"/>
<stop offset="1" style="stop-color:#2AFADF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-33" style="opacity:0.2;fill:url(#Shape-33_00000137132446951879004030000008177934085669183874_);enable-background:new ;" d="
M277.1,199.4v95.5l-67.2,39.4v-89.2c0.3,2,2.3,3.2,4.7,2.6c7.2-1.6,14.3-3.8,21.2-6.6c3.4-1.4,6.8-2.8,10-4.5
C265.8,226.3,276.2,212.8,277.1,199.4z"/>
<linearGradient id="Shape-34_00000017487326329354270790000004505123412309728175_" gradientUnits="userSpaceOnUse" x1="-4586.5684" y1="-1389.8807" x2="-4591.4204" y2="-1389.8807" gradientTransform="matrix(27.05 0 0 59.5 124361.1797 82796.8516)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="1" style="stop-color:#2AFADF"/>
</linearGradient>
<path id="Shape-34" style="opacity:0.2;fill:url(#Shape-34_00000017487326329354270790000004505123412309728175_);enable-background:new ;" d="
M249,119.2c-0.7-0.3-1.4-0.8-2.2-1.1c-1.2-0.5-2.2-3-2.2-5.3V79.4c0-2.4,1-3.8,2.2-3.3c0.8,0.3,1.4,0.7,2.2,1.1
c24,12.3,25.6,31.5,4.7,44.7C252.1,120.9,250.5,120.1,249,119.2z"/>
<linearGradient id="Shape-35_00000182508484054447651870000016260184141608580785_" gradientUnits="userSpaceOnUse" x1="-4667.9175" y1="-1396.4476" x2="-4665.9023" y2="-1396.4476" gradientTransform="matrix(73.17 0 0 97.58 341653.125 136403.875)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="1" style="stop-color:#2AFADF"/>
</linearGradient>
<path id="Shape-35" style="opacity:0.3;fill:url(#Shape-35_00000182508484054447651870000016260184141608580785_);enable-background:new ;" d="
M268.2,142.8c0.1,8.5-6.2,17.1-18.9,23.7c-1.9,1-3.9,1.9-6,2.7c-7.8,3.1-15.9,5-24.2,6c-3.3,0.4-6.6,0.7-10,0.9
c-2.4,0.2-4.6-1.4-4.8-3.8c0-0.1,0-0.2,0-0.3v-33.5c0-2.4,2.2-4.3,4.8-4.4c3.3-0.1,6.7-0.4,10-0.9c8.3-1,16.4-3.1,24.2-6.1
c2.1-0.9,4.2-1.8,6-2.7c12.7-6.5,18.9-15,18.9-23.5V142.8z"/>
<linearGradient id="Shape-36_00000134951791006757682060000002162209820624686987_" gradientUnits="userSpaceOnUse" x1="225.9564" y1="-904.1375" x2="222.7145" y2="-937.75" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-36" style="fill:url(#Shape-36_00000134951791006757682060000002162209820624686987_);" d="M234.1,150.1
c0,6.4-5,14.1-11.4,17.3s-11.4,0.7-11.4-5.7s5-14.1,11.4-17.3C229,141.2,234.1,143.7,234.1,150.1z M222.7,163.8
c4.3-2.2,7.7-7.4,7.7-11.7s-3.5-6-7.8-3.9s-7.8,7.4-7.7,11.7C215,164.1,218.4,165.9,222.7,163.8L222.7,163.8z"/>
<linearGradient id="Shape-37_00000106120806841072813860000004463379643489448371_" gradientUnits="userSpaceOnUse" x1="-4573.8359" y1="-1375.6361" x2="-4572.96" y2="-1375.6361" gradientTransform="matrix(24.13 0 0 31.7 110559.8047 43764.2852)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-37" style="fill:url(#Shape-37_00000106120806841072813860000004463379643489448371_);" d="M229.4,156.3
c-1.3,3.2-3.7,5.7-6.7,7.4c-4.3,2.2-7.8,0.4-7.8-3.9c0-4.4,3.4-9.6,7.7-11.7l0,0v-3.7l0,0c-6.2,3.2-11.4,11-11.4,17.3
c0,6.4,5.1,9,11.4,5.7c4.3-2.4,7.7-6,9.7-10.5L229.4,156.3z"/>
<linearGradient id="Shape-38_00000103972781162050256340000014581144695034338738_" gradientUnits="userSpaceOnUse" x1="-4570.1318" y1="-1373.7581" x2="-4568.1167" y2="-1373.7581" gradientTransform="matrix(23.4 0 0 30.11 107153.7891 41508.875)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-38" style="fill:url(#Shape-38_00000103972781162050256340000014581144695034338738_);" d="M262,139.8
c0,5.7-4.5,12.7-10.2,15.6c-5.7,2.8-10.3,0.5-10.3-5.1s4.5-12.7,10.2-15.6C257.4,131.8,262,134.1,262,139.8z M251.8,152
c3.8-2,6.9-6.7,6.9-10.6c0-3.9-3.2-5.5-7-3.5s-6.9,6.7-6.9,10.6C244.8,152.5,248,154,251.8,152z"/>
<linearGradient id="Shape-39_00000025423177438856170250000006332888040414474649_" gradientUnits="userSpaceOnUse" x1="-4426.6255" y1="-1371.6255" x2="-4425.7603" y2="-1371.6255" gradientTransform="matrix(11.7 0 0 28.37 52017.5625 39058.5156)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-39" style="fill:url(#Shape-39_00000025423177438856170250000006332888040414474649_);" d="M251.7,134.6
c-5.7,2.8-10.2,9.9-10.2,15.6c0,3.5,1.8,5.8,4.4,6.2l1.8-3.7c-1.8-0.4-2.8-1.9-2.8-4.3c0-3.9,3.1-8.7,6.9-10.6l0,0L251.7,134.6
L251.7,134.6z"/>
<linearGradient id="Shape-40_00000021118273186128926250000015044912358265521326_" gradientUnits="userSpaceOnUse" x1="-4665.3408" y1="-1397.1777" x2="-4662.8545" y2="-1397.1777" gradientTransform="matrix(69.21 0 0 106.39 322845.875 148760.2031)">
<stop offset="0" style="stop-color:#4C83FF"/>
<stop offset="1" style="stop-color:#2AFADF"/>
</linearGradient>
<path id="Shape-40" style="opacity:0.3;fill:url(#Shape-40_00000021118273186128926250000015044912358265521326_);enable-background:new ;" d="
M121.7,107.5v44.9c0,2.4-2.1,3.7-4.6,2.8c-9.6-3.1-19.1-6.8-28.1-11.4c-8.8-4.4-17-9.7-24.4-16c-2-2-3.3-4.6-3.4-7.3V75.6
c0-2.4,1.5-2.8,3.4-1.2C72,80.6,80.3,86,89,90.4c9.1,4.6,18.5,8.3,28.1,11.4C119.6,102.5,121.5,104.8,121.7,107.5z"/>
<linearGradient id="Shape-41_00000005975336679041812930000005759237068217401271_" gradientUnits="userSpaceOnUse" x1="138.8851" y1="-878.1784" x2="67.1695" y2="-905.581" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-41" style="fill:url(#Shape-41_00000005975336679041812930000005759237068217401271_);" d="M85.1,101.2
c8.4,4.3,15.3,14.8,15.3,23.3s-6.9,12-15.3,7.8S69.8,117.5,69.8,109S76.7,96.9,85.1,101.2z M85,127.3c5.7,3,10.4,0.5,10.4-5.3
s-4.6-12.9-10.4-15.9s-10.4-0.5-10.4,5.3S79.3,124.4,85,127.3L85,127.3z"/>
<linearGradient id="Shape-42_00000122712814098058905890000007017593085226539443_" gradientUnits="userSpaceOnUse" x1="-4521.1196" y1="-1373.542" x2="-4520.2432" y2="-1373.542" gradientTransform="matrix(17.49 0 0 30.28 79147.5156 41703.7031)">
<stop offset="0" style="stop-color:#2AFADF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
</linearGradient>
<path id="Shape-42" style="fill:url(#Shape-42_00000122712814098058905890000007017593085226539443_);" d="M85.1,101.2
c8.4,4.3,15.3,14.8,15.3,23.3l-4.9-2.5c0-5.8-4.6-12.9-10.4-15.9V101.2z"/>
<linearGradient id="Shape-43_00000030453719429377122740000013557076259559090617_" gradientUnits="userSpaceOnUse" x1="109.0421" y1="-913.4399" x2="80.9496" y2="-976.8318" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#30E4E5"/>
<stop offset="0.6" style="stop-color:#2AFADF;stop-opacity:0"/>
</linearGradient>
<path id="Shape-43" style="opacity:0.2;fill:url(#Shape-43_00000030453719429377122740000013557076259559090617_);enable-background:new ;" d="
M121.7,152.3V222l-60.6-29.8v-71.7c0.1,2.7,1.4,5.4,3.4,7.3c7.4,6.2,15.7,11.6,24.4,16c9.1,4.6,18.5,8.3,28.1,11.4
C119.6,156,121.7,154.7,121.7,152.3z"/>
<linearGradient id="Shape-44_00000176727814201571328480000011766605898265965704_" gradientUnits="userSpaceOnUse" x1="249.2" y1="-1232.5" x2="287.6426" y2="-1232.5" gradientTransform="matrix(1 0 0 -1 0 -782)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<polygon id="Shape-44" style="fill:url(#Shape-44_00000176727814201571328480000011766605898265965704_);" points="249.2,460.7
271,457.3 287.6,446.1 274.3,440.3 "/>
<linearGradient id="SVGID_00000042695819913126177250000000172513830783411371_" gradientUnits="userSpaceOnUse" x1="-4654.0396" y1="-1402.9192" x2="-4653.481" y2="-1403.2366" gradientTransform="matrix(75.74 0 0 55.03 352723.9688 77637.6016)">
<stop offset="1.000000e-02" style="stop-color:#009FFC"/>
<stop offset="0.56" style="stop-color:#1595F4"/>
<stop offset="1" style="stop-color:#2090F0"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000042695819913126177250000000172513830783411371_);" points="244.6,425.2 249.2,433.2
279.7,415.2 275.4,407.6 "/>
<linearGradient id="SVGID_00000117638879148804653300000015399300247122409869_" gradientUnits="userSpaceOnUse" x1="-4644.7964" y1="-1405.0366" x2="-4644.709" y2="-1404.4231" gradientTransform="matrix(65.77 0 0 97.87 305750.0312 137920.9688)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000117638879148804653300000015399300247122409869_);" points="249.2,433.2 249.2,460.7
279.7,440.7 279.7,415.2 "/>
<linearGradient id="SVGID_00000085224804945207263520000014360999943671216563_" gradientUnits="userSpaceOnUse" x1="-4353.3867" y1="-1395.6317" x2="-4353.4966" y2="-1396.1903" gradientTransform="matrix(12.39 0 0 17.46 54185.7148 24803.7129)">
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/>
<stop offset="0.59" style="stop-color:#6DFFCB"/>
<stop offset="1" style="stop-color:#78FFD6"/>
</linearGradient>
<polyline style="fill:url(#SVGID_00000085224804945207263520000014360999943671216563_);" points="244.6,425.2 249.2,433.2
248.2,433.2 243.4,425.1 244.6,425.2 "/>
<linearGradient id="SVGID_00000057131615203601934700000015143495052675431324_" gradientUnits="userSpaceOnUse" x1="-4352.3335" y1="-1403.6678" x2="-4352.2788" y2="-1403.8651" gradientTransform="matrix(12.35 0 0 59.18 53998.4648 83513.9609)">
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/>
<stop offset="0.59" style="stop-color:#6DFFCB"/>
<stop offset="1" style="stop-color:#78FFD6"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000057131615203601934700000015143495052675431324_);" points="248.2,433.2 248.2,459.4
243.5,456.5 243.5,457.3 249.2,460.7 249.2,433.2 "/>
<linearGradient id="SVGID_00000029010345686687337160000011462027730732656565_" gradientUnits="userSpaceOnUse" x1="-4281.1147" y1="-1393.7373" x2="-4280.3813" y2="-1394.3835" gradientTransform="matrix(10.3 0 0 11.87 44341.7695 17001.1699)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000029010345686687337160000011462027730732656565_);" points="243.5,456.5 248.2,453.9
248.2,459.4 "/>
<linearGradient id="Shape-45_00000098906919044303374130000006733002538008474547_" gradientUnits="userSpaceOnUse" x1="-4647.6909" y1="-1401.2917" x2="-4647.1543" y2="-1401.2148" gradientTransform="matrix(68.73 0 0 38.94 319689.0938 54981.9297)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon id="Shape-45" style="fill:url(#Shape-45_00000098906919044303374130000006733002538008474547_);" points="275.4,407.6
274.7,407.1 243.4,425.1 244.6,425.2 "/>
<linearGradient id="Shape-46_00000155104190746461959110000008164066156702385284_" gradientUnits="userSpaceOnUse" x1="-4651.0366" y1="-1404.4684" x2="-4650.7954" y2="-1404.1398" gradientTransform="matrix(72.46 0 0 96.76 337260.875 136272.1094)">
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/>
<stop offset="0.59" style="stop-color:#6DFFCB"/>
<stop offset="1" style="stop-color:#78FFD6"/>
</linearGradient>
<path id="Shape-46" style="fill:url(#Shape-46_00000155104190746461959110000008164066156702385284_);" d="M243.4,420.8l31.2-18.1
c0.7-0.4,1.1-1.2,1.1-2l0.3-23.9c0-0.8-0.4-1.1-1-0.8l-31.2,18.1c-0.7,0.4-1,1.2-1,2l-0.3,23.9
C242.4,420.8,242.8,421.1,243.4,420.8z"/>
<g id="Shape-47" class="st40">
<linearGradient id="SVGID_00000101076599354358181930000006343129837226329520_" gradientUnits="userSpaceOnUse" x1="-4352.7603" y1="-1398.1875" x2="-4352.8589" y2="-1397.7163" gradientTransform="matrix(12.28 0 0 25.58 53724.875 36168.9766)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#FFFFFF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000101076599354358181930000006343129837226329520_);" d="M275.8,393.5c0,0,0,0.9,0,2.3
c0,0.7,0,1.5,0,2.4c0,0.4,0,0.9,0,1.3s0,0.9,0,1.4c0,0.4-0.2,1-0.4,1.3c-0.1,0.2-0.3,0.3-0.5,0.5c-0.2,0.1-0.4,0.2-0.5,0.3
l-2.1,1.2l-2.1,1.1l2-1.2l2.1-1.2c0.4-0.2,0.8-0.4,1-0.8c0.2-0.3,0.4-0.8,0.4-1.2c0-0.4,0-1,0-1.4s0-0.9,0-1.3
c0-0.9,0-1.6,0.1-2.4C275.8,394.4,275.8,393.5,275.8,393.5z"/>
</g>
<linearGradient id="SVGID_00000025437517784366984770000010747534483800912309_" gradientUnits="userSpaceOnUse" x1="-4462.6445" y1="-1386.6772" x2="-4462.1733" y2="-1386.6772" gradientTransform="matrix(17.68 0 0 11.8 79164.0781 16746.4414)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000025437517784366984770000010747534483800912309_);" points="274,381.6 265.8,386.4
265.8,385.6 274,380.9 "/>
<linearGradient id="SVGID_00000014603506014971141140000003413487988091619970_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1381.9902" x2="-4391.9395" y2="-1381.9902" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13597.9766)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000014603506014971141140000003413487988091619970_);" points="272.3,384.7 265.8,388.4
265.8,387.6 272.3,383.9 "/>
<linearGradient id="SVGID_00000057835095209813497070000006025639477437015717_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1382.2275" x2="-4391.9395" y2="-1382.2275" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13602.2461)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000057835095209813497070000006025639477437015717_);" points="272.3,386.6 265.8,390.4
265.8,389.6 272.3,385.9 "/>
<linearGradient id="SVGID_00000112619206826002184200000001160212017524668599_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1382.4702" x2="-4391.9395" y2="-1382.4702" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13606.5156)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000112619206826002184200000001160212017524668599_);" points="272.3,388.6 265.8,392.3
265.8,391.6 272.3,387.9 "/>
<linearGradient id="SVGID_00000014619903439646413060000003573965781630823350_" gradientUnits="userSpaceOnUse" x1="-4462.6445" y1="-1387.7568" x2="-4462.1733" y2="-1387.7568" gradientTransform="matrix(17.68 0 0 11.8 79164.0781 16769.0801)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000014619903439646413060000003573965781630823350_);" points="274,391.6 265.8,396.3
265.8,395.6 274,390.8 "/>
<linearGradient id="SVGID_00000135687018638205079420000002421485263476320680_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.1858" x2="-4391.9395" y2="-1383.1858" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13619.3066)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000135687018638205079420000002421485263476320680_);" points="272.3,394.6 265.8,398.2
265.8,397.6 272.3,393.9 "/>
<linearGradient id="SVGID_00000033353309158504731440000001683089570208010429_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.4285" x2="-4391.9395" y2="-1383.4285" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13623.5762)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000033353309158504731440000001683089570208010429_);" points="272.3,396.6 265.8,400.2
265.8,399.6 272.3,395.8 "/>
<linearGradient id="SVGID_00000129923475701508823520000005680875115117715122_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.6606" x2="-4391.9395" y2="-1383.6606" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13627.8457)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000129923475701508823520000005680875115117715122_);" points="272.3,398.6 265.8,402.3
265.8,401.5 272.3,397.8 "/>
<linearGradient id="Shape-48_00000020372391056104230850000014324465669750481819_" gradientUnits="userSpaceOnUse" x1="-4538.2388" y1="-1403.8259" x2="-4538.3047" y2="-1403.3442" gradientTransform="matrix(25.5 0 0 71.67 115982.2188 100989.3438)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<polygon id="Shape-48" style="opacity:0.4;fill:url(#Shape-48_00000020372391056104230850000014324465669750481819_);enable-background:new ;" points="
259.7,385 250.1,417 252,415.9 261.9,383.7 "/>
<linearGradient id="Shape-49_00000158746474549493822570000018370522913050869146_" gradientUnits="userSpaceOnUse" x1="-4587.5259" y1="-1404.0281" x2="-4587.6245" y2="-1403.5239" gradientTransform="matrix(35.56 0 0 77.83 163397.2344 109641.4844)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</linearGradient>
<polygon id="Shape-49" style="opacity:0.4;fill:url(#Shape-49_00000158746474549493822570000018370522913050869146_);enable-background:new ;" points="
263.6,382.7 253.8,414.9 260.3,411.1 270.3,378.6 "/>
<g class="st108">
<polygon class="st109" points="262.4,390.4 247.8,398.8 247.8,398.7 262.4,390.2 "/>
</g>
<g class="st108">
<polygon class="st109" points="262.4,393.4 247.8,402 247.8,401.9 262.4,393.3 "/>
</g>
<g class="st108">
<polygon class="st109" points="262.4,396.6 247.8,405.1 247.8,405 262.4,396.5 "/>
</g>
<g class="st108">
<polygon class="st109" points="262.4,399.8 247.8,408.3 247.8,408.1 262.4,399.7 "/>
</g>
<g class="st108">
<polygon class="st109" points="262.4,403 247.8,411.4 247.8,411.3 262.4,402.8 "/>
</g>
<linearGradient id="SVGID_00000076567543439310601720000004045448953772141723_" gradientUnits="userSpaceOnUse" x1="-3294.0398" y1="-1400.6531" x2="-3294.0398" y2="-1401.113" gradientTransform="matrix(3.13 0 0 37.05 10559.5449 52306.3789)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000076567543439310601720000004045448953772141723_);" points="249.9,413.6 248.5,414.5
248.5,398 249.9,397.1 "/>
<linearGradient id="SVGID_00000079488291248167022160000006589743079914859678_" gradientUnits="userSpaceOnUse" x1="-3294.5764" y1="-1396.5031" x2="-3294.5764" y2="-1396.0323" gradientTransform="matrix(3.13 0 0 20.21 10562.6748 28634.0879)">
<stop offset="1.000000e-02" style="stop-color:#009FFC"/>
<stop offset="0.56" style="stop-color:#1595F4"/>
<stop offset="1" style="stop-color:#2090F0"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000079488291248167022160000006589743079914859678_);" points="251.4,412.7 249.9,413.6
249.9,405 251.4,404.2 "/>
<linearGradient id="SVGID_00000067926720751569274880000009097307530463908492_" gradientUnits="userSpaceOnUse" x1="-3295.7585" y1="-1398.5204" x2="-3295.7585" y2="-1398.9913" gradientTransform="matrix(3.13 0 0 26.95 10569.625 38095.2344)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000067926720751569274880000009097307530463908492_);" points="254.7,410.8 253.1,411.7
253.1,400 254.7,399.1 "/>
<linearGradient id="SVGID_00000000212797735812424900000012527227039377536170_" gradientUnits="userSpaceOnUse" x1="-3296.2793" y1="-1401.8259" x2="-3296.2793" y2="-1401.366" gradientTransform="matrix(3.13 0 0 43.78 10572.7549 61771.4961)">
<stop offset="1.000000e-02" style="stop-color:#009FFC"/>
<stop offset="0.56" style="stop-color:#1595F4"/>
<stop offset="1" style="stop-color:#2090F0"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000000212797735812424900000012527227039377536170_);" points="256.1,410.1 254.7,410.8
254.7,391.3 256.1,390.5 "/>
<linearGradient id="SVGID_00000098184852967546321720000017918665523034777504_" gradientUnits="userSpaceOnUse" x1="-3297.3301" y1="-1390.7391" x2="-3297.3301" y2="-1391.1991" gradientTransform="matrix(3.13 0 0 13.48 10579.2441 19151.5078)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000098184852967546321720000017918665523034777504_);" points="259.4,408.1 257.8,409
257.8,403.6 259.4,402.7 "/>
<linearGradient id="SVGID_00000099643791442660283550000003955445333089008051_" gradientUnits="userSpaceOnUse" x1="-3297.998" y1="-1400.3435" x2="-3297.998" y2="-1399.8726" gradientTransform="matrix(3.13 0 0 33.68 10582.835 47560.3516)">
<stop offset="1.000000e-02" style="stop-color:#009FFC"/>
<stop offset="0.56" style="stop-color:#1595F4"/>
<stop offset="1" style="stop-color:#2090F0"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000099643791442660283550000003955445333089008051_);" points="260.8,407.3 259.4,408.1
259.4,393.3 260.8,392.5 "/>
<linearGradient id="SVGID_00000139981804617803399270000013206585361592540318_" gradientUnits="userSpaceOnUse" x1="-4573.7271" y1="-1401.5767" x2="-4573.2671" y2="-1401.5767" gradientTransform="matrix(31.99 0 0 43.44 146560.3125 61289.4375)">
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/>
<stop offset="0.12" style="stop-color:#00B6F8"/>
<stop offset="0.52" style="stop-color:#0085F1"/>
<stop offset="0.83" style="stop-color:#0066EC"/>
<stop offset="1" style="stop-color:#005BEA"/>
</linearGradient>
<polygon style="fill:url(#SVGID_00000139981804617803399270000013206585361592540318_);" points="262.4,406.5 247.5,415.1
247.5,395 247.6,394.8 247.6,414.9 262.4,406.3 "/>
<linearGradient id="Shape-50_00000140719076435951959120000006641442635192087477_" gradientUnits="userSpaceOnUse" x1="-4655.9185" y1="-1402.9375" x2="-4655.9624" y2="-1403.0032" gradientTransform="matrix(78.92 0 0 57.93 367701.5 81679.6797)">
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/>
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/>
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/>
</linearGradient>
<polygon id="Shape-50" style="fill:url(#Shape-50_00000140719076435951959120000006641442635192087477_);" points="244.6,425.2
243.4,425.1 240.4,419.8 277,398.2 275.4,407.6 "/>
<linearGradient id="Shape-51_00000147939181360286582920000004146921999076484486_" gradientUnits="userSpaceOnUse" x1="-4353.4653" y1="-1402.2626" x2="-4353.4541" y2="-1401.704" gradientTransform="matrix(12.39 0 0 31.04 54185.7031 43981.7422)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<polyline id="Shape-51" style="fill:url(#Shape-51_00000147939181360286582920000004146921999076484486_);" points="249.2,471.7
249.2,460.7 243.5,457.3 243.4,458.3 248.1,461 "/>
<linearGradient id="Shape-52_00000133514124685140248980000012016277643264497070_" gradientUnits="userSpaceOnUse" x1="-4650.8057" y1="-1400.7756" x2="-4650.313" y2="-1400.7756" gradientTransform="matrix(71.6 0 0 27.35 333266.75 38764.7188)">
<stop offset="0" style="stop-color:#91BFDB"/>
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/>
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/>
</linearGradient>
<path id="Shape-52" style="fill:url(#Shape-52_00000133514124685140248980000012016277643264497070_);" d="M271.6,457.3
c2.3-0.1,5.8-2.3,30.2-1.5c3.6-1.2,2.3-4.6,1.1-5.7c-1.2-1.1-12.5,0.4-16.4,1.2c-3.9,0.8-15,3.2-15.4,5.4"/>
<g id="Shape-53">
<linearGradient id="SVGID_00000054984489780984634950000007063448993696825000_" gradientUnits="userSpaceOnUse" x1="-4313.8755" y1="-1382.7407" x2="-4314.3354" y2="-1382.7407" gradientTransform="matrix(11.1 0 0 6.07 48165.1211 8850.4492)">
<stop offset="0" style="stop-color:#2A2ED0"/>
<stop offset="0.1" style="stop-color:#3133D1"/>
<stop offset="0.25" style="stop-color:#433FD6"/>
<stop offset="0.42" style="stop-color:#6255DC"/>
<stop offset="0.61" style="stop-color:#8C72E6"/>
<stop offset="0.81" style="stop-color:#C297F2"/>
<stop offset="1" style="stop-color:#FCBFFF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000054984489780984634950000007063448993696825000_);" d="M272.9,457.5c0,0,0.1,0.7-0.2,1
c-0.3,0.3-1.8,0.1-2.7-0.4c-0.8-0.3-1.5-0.8-2.2-1.4c-0.1-0.3,0-0.7,0.2-0.9C268.2,455.6,272.9,457.5,272.9,457.5z"/>
<linearGradient id="SVGID_00000080918987833476237920000016819689408787064764_" gradientUnits="userSpaceOnUse" x1="-4299.2207" y1="-1380.0359" x2="-4299.0454" y2="-1379.6963" gradientTransform="matrix(10.7 0 0 5.64 46274.793 8242.5244)">
<stop offset="0.1" style="stop-color:#89F7FE"/>
<stop offset="0.28" style="stop-color:#87F2FE"/>
<stop offset="0.5" style="stop-color:#81E4FE"/>
<stop offset="0.73" style="stop-color:#76CCFF"/>
<stop offset="0.97" style="stop-color:#68ABFF"/>
<stop offset="1" style="stop-color:#66A6FF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000080918987833476237920000016819689408787064764_);" d="M272.7,456.4c0,0,0.7,1.2-0.2,1.6
c-1.1,0.4-4.9-1.4-4.5-2.2c0.3-0.5,1.2-0.3,2.5-0.3C271.4,455.5,272.2,455.9,272.7,456.4z"/>
<linearGradient id="SVGID_00000160875980869004348870000016218684430427734656_" gradientUnits="userSpaceOnUse" x1="-4314.251" y1="-1382.3303" x2="-4315.248" y2="-1382.3523" gradientTransform="matrix(11.1 0 0 6.07 48178.8828 8845.9297)">
<stop offset="0" style="stop-color:#2A2ED0"/>
<stop offset="0.1" style="stop-color:#3133D1"/>
<stop offset="0.25" style="stop-color:#433FD6"/>
<stop offset="0.42" style="stop-color:#6255DC"/>
<stop offset="0.61" style="stop-color:#8C72E6"/>
<stop offset="0.81" style="stop-color:#C297F2"/>
<stop offset="1" style="stop-color:#FCBFFF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000160875980869004348870000016218684430427734656_);" d="M279.3,455.3c0,0,0.1,0.7-0.2,1
c-0.3,0.3-1.8,0.1-2.7-0.4c-0.8-0.3-1.5-0.9-2.2-1.4c-0.1-0.3,0-0.7,0.2-0.9C274.6,453.4,279.3,455.3,279.3,455.3z"/>
<linearGradient id="SVGID_00000138549545104016646050000011419445232965228706_" gradientUnits="userSpaceOnUse" x1="-4300.1392" y1="-1379.9625" x2="-4300.9165" y2="-1379.5682" gradientTransform="matrix(10.7 0 0 5.64 46288.5508 8237.4941)">
<stop offset="0.1" style="stop-color:#89F7FE"/>
<stop offset="0.28" style="stop-color:#87F2FE"/>
<stop offset="0.5" style="stop-color:#81E4FE"/>
<stop offset="0.73" style="stop-color:#76CCFF"/>
<stop offset="0.97" style="stop-color:#68ABFF"/>
<stop offset="1" style="stop-color:#66A6FF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000138549545104016646050000011419445232965228706_);" d="M279.1,454.2c0,0,0.7,1.2-0.2,1.6
c-1.1,0.4-4.9-1.4-4.5-2.2c0.3-0.5,1.2-0.3,2.5-0.3C277.8,453.3,278.5,453.7,279.1,454.2z"/>
<linearGradient id="SVGID_00000012439461484347364750000007568484484384575618_" gradientUnits="userSpaceOnUse" x1="-4509.1016" y1="-1403.5773" x2="-4509.123" y2="-1404.2782" gradientTransform="matrix(21.74 0 0 66.22 98302.5234 93415.1875)">
<stop offset="0" style="stop-color:#1E2275"/>
<stop offset="1" style="stop-color:#0046BC"/>
</linearGradient>
<path style="fill:url(#SVGID_00000012439461484347364750000007568484484384575618_);" d="M279,426.5c0.5,2.6,0.5,5.3,0,7.9
c-0.7,2.6,0,19.9,0,19.9s-0.7,0.9-2.3,0.1c0,0-0.8-6.5-1-11.9c-0.1-3.9-0.2-7.2-0.2-7.8l-1.5,0.7c-0.5,2.7-0.9,5.5-1.1,8.3
c0,2.7-0.1,13-0.1,13c-0.5,0.4-1.4,0.4-2,0c0,0-1.2-10.8-1.5-13.7c-0.3-2.8,1-14.5,1-14.5S276,425.1,279,426.5z"/>
<path class="st125" d="M272.3,410c0,0,0.4,2.1,0.4,2.4s1.9-0.9,2.2-1.3l-0.3-2.3C273.7,409,272.9,409.3,272.3,410z"/>
<path class="st126" d="M272.3,410l0.4,2.4c0.5-0.7,0.9-1.5,1-2.3C273.7,410,273.7,408.4,272.3,410z"/>
<linearGradient id="SVGID_00000085217106529308597890000006205264978108892050_" gradientUnits="userSpaceOnUse" x1="-4097.0649" y1="-1373.2161" x2="-4097.5254" y2="-1373.2161" gradientTransform="matrix(7.17 0 0 5.93 29652.7383 8555.3711)">
<stop offset="1.000000e-02" style="stop-color:#6A9DFF"/>
<stop offset="0.27" style="stop-color:#4872EB"/>
<stop offset="0.6" style="stop-color:#2141D3"/>
<stop offset="0.86" style="stop-color:#0922C4"/>
<stop offset="1" style="stop-color:#0017BF"/>
</linearGradient>
<path style="fill:url(#SVGID_00000085217106529308597890000006205264978108892050_);" d="M275,410.8c0.2,0.2,0.4,0.5,0.7,0.8
c-0.7,1.2-2,2-3.3,2l0.4-1.3L275,410.8z"/>
<linearGradient id="SVGID_00000020394213504040997820000013097059723123130259_" gradientUnits="userSpaceOnUse" x1="-4503.46" y1="-1402.0055" x2="-4503.3394" y2="-1401.3702" gradientTransform="matrix(21.11 0 0 39.74 95340.4531 56123.2578)">
<stop offset="1.000000e-02" style="stop-color:#FB6583"/>
<stop offset="0.13" style="stop-color:#FC7688"/>
<stop offset="0.53" style="stop-color:#FDA797"/>
<stop offset="0.83" style="stop-color:#FFC6A0"/>
<stop offset="1" style="stop-color:#FFD1A3"/>
</linearGradient>
<path style="fill:url(#SVGID_00000020394213504040997820000013097059723123130259_);" d="M275.6,411.6c1,0,1.9,0.7,2.1,1.8
c0.5,2.6,1,5.4,1.2,8.1c0,1.5,0.7,4.5,0.4,5.7c-0.2,1-2,1.4-4.2,2.4c-1.6,0.9-3.7,0.8-5.4-0.2c-0.7-0.5,0.2-3.3,0.1-4.6
c-0.1-1.3-0.1-3.7,0-4.5s-0.1-4.3,2.4-6.6C273.3,412.8,274.4,412.2,275.6,411.6z"/>
<linearGradient id="SVGID_00000181058967435089559130000006669968388613110451_" gradientUnits="userSpaceOnUse" x1="-3775.5581" y1="-1390.2045" x2="-3775.6128" y2="-1389.3502" gradientTransform="matrix(4.71 0 0 29.57 18050.4395 41817.6797)">
<stop offset="1.000000e-02" style="stop-color:#FB6583"/>
<stop offset="0.13" style="stop-color:#FC7688"/>
<stop offset="0.53" style="stop-color:#FDA797"/>
<stop offset="0.83" style="stop-color:#FFC6A0"/>
<stop offset="1" style="stop-color:#FFD1A3"/>
</linearGradient>
<path style="opacity:0.3;fill:url(#SVGID_00000181058967435089559130000006669968388613110451_);enable-background:new ;" d="
M271.6,416.2c0,0-0.5,5.9-0.7,8c-0.1,1.5,0.4,5.4,0,5.7c-0.4-0.1-0.8-0.3-1.1-0.5c-0.9-0.5-0.1-3.2,0-3.9c0.1-0.8,0-2.7,0-4.3
c0-1.9,0.3-4.7,0.7-4.9C271,416.2,271.3,416.2,271.6,416.2z"/>
<linearGradient id="SVGID_00000122710278541649656810000007312387862833113729_" gradientUnits="userSpaceOnUse" x1="-4572.3774" y1="-1397.1755" x2="-4572.0815" y2="-1396.6389" gradientTransform="matrix(31.64 0 0 21.28 144939.8594 30149.8242)">
<stop offset="1.000000e-02" style="stop-color:#FB6583"/>
<stop offset="0.13" style="stop-color:#FC7688"/>
<stop offset="0.53" style="stop-color:#FDA797"/>
<stop offset="0.83" style="stop-color:#FFC6A0"/>
<stop offset="1" style="stop-color:#FFD1A3"/>
</linearGradient>
<path style="fill:url(#SVGID_00000122710278541649656810000007312387862833113729_);" d="M273.6,414.5c0,0,0.7,0.8-0.3,1.9
s-6.9,2.5-8.2,2.3c-3.7-0.7-6-8.5-6-8.5l1.6-1.3c0,0,2.8,7.3,5.4,6.9C269.1,415,272.3,412.6,273.6,414.5z"/>
<path class="st125" d="M270.2,405.4c0,0-0.8,4.5,0,5.3s2.8-0.2,2.8-0.2s2.3-1.4,1.3-2.8C273.4,406.1,270.2,405.4,270.2,405.4z"/>
<linearGradient id="SVGID_00000166643334475131779910000005720074573264916131_" gradientUnits="userSpaceOnUse" x1="-4412.3691" y1="-1392.0507" x2="-4412.5332" y2="-1392.5873" gradientTransform="matrix(14.75 0 0 18.16 65368.8008 25736.9492)">
<stop offset="0" style="stop-color:#1E2275"/>
<stop offset="1" style="stop-color:#0046BC"/>
</linearGradient>
<path style="fill:url(#SVGID_00000166643334475131779910000005720074573264916131_);" d="M275.6,410c0,0-1.8,1-2.3,0.4
c-0.7-0.7-0.9-1.6-0.5-2.5c0.1-0.7-0.3-1.1-0.7-0.3c-0.2,0.5-0.1,0.8-0.4,0.7s-0.1-0.3-0.1-0.8c0.1-0.5-0.2-1-0.7-1.2
c-0.5-0.3-0.9-1-0.9-1.5c0-1.9,1.8-3.2,4.2-2.1c2.1,1,2.8,2.5,2.6,3.5C276.6,407.1,276.4,409.5,275.6,410z"/>
<polygon class="st132" points="275.6,434.7 276.6,434.2 275.7,439.9 "/>
<path class="st133" d="M260.3,409c-0.1-0.2-0.1-0.4-0.1-0.7c0.1-0.2,0.5-0.5,0.4-0.7c-0.1-0.1-0.7,0.4-0.7,0.3s0-1.1-0.2-1.1
s-0.2,0.7-0.2,1c0,0-1,0.4-0.8,1c0.1,0.3,0.3,0.7,0.4,1L260.3,409z"/>
</g>
</g>
</g>
</svg>

BIN
custom/public/rotation3D/img/baseMap.png View File

Before After
Width: 800  |  Height: 516  |  Size: 56 KiB

+ 1
- 0
custom/public/rotation3D/img/brain.svg
File diff suppressed because it is too large
View File


BIN
custom/public/rotation3D/img/idc-green.png View File

Before After
Width: 161  |  Height: 188  |  Size: 38 KiB

BIN
custom/public/rotation3D/img/idc-red.png View File

Before After
Width: 161  |  Height: 188  |  Size: 38 KiB

BIN
custom/public/rotation3D/img/idc-yellow.png View File

Before After
Width: 161  |  Height: 188  |  Size: 38 KiB

+ 2
- 0
custom/public/rotation3D/jquery-3.5.0.min.js
File diff suppressed because it is too large
View File


+ 152
- 0
custom/public/rotation3D/rotation3D.css View File

@@ -0,0 +1,152 @@

/*
椭圆会使内部失真 transform: rotateX(50deg);
*/
.rotation3D{
position: relative; width: 800px; height: 600px; user-select: none;
margin: 0 auto;
/* border: 1px solid white; border-radius: 100%; */
/* cursor: move; */
}
.rotation3D .center{
display: none;
position: absolute; left: 50%; top: 50%;
transform: translate(-50%, -50%);
}

.rotation3D .itemList{ position: absolute; width: 100%; height: 100%; z-index: 20; }
.rotation3D .lineList{
position: absolute; width: 100%; height: 100%; z-index: 10;
transform-style: preserve-3d;
}

/*---------------------------点样式---------------------------*/
.rotation3D__item{
position: absolute; display: block; width: 161px; height: 188px;
text-align: center; line-height: 30px; font-size: 16px; color: white;
/*background: #2292ef; border-radius: 4px;*/
/*cursor: pointer; */
}
.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 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: "合肥类脑智能开放平台";
}
.itemList .rotation3D__item:nth-child(5) .cont p::after{
content: "武汉人工智能计算中心";
}
.itemList .rotation3D__item:nth-child(6) .cont p::after{
content: "西安未来人工智能计算中心";
}
.itemList .rotation3D__item:nth-child(7) .cont p::after{
content: "更多接入中…";
}
.itemList .rotation3D__item:nth-child(8) .cont p::after{
content: "中原人工智能计算中心";
}
.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; }

/*底座*/
.rotation3D__item .baseImg{ position: absolute; width: 100%; height: 100%; z-index: 1; }
.rotation3D__item.blue .baseImg{ background: url("img/idc-red.png"); }
.rotation3D__item.green .baseImg{ background: url("img/idc-green.png"); }
.rotation3D__item.yellow .baseImg{ background: url("img/idc-yellow.png"); }

/*---------------------------
线样式
线高为总高的一般
---------------------------*/
.rotation3D__line{
position: absolute; left: 50%; top: 50%;
display: block; width: 1px; 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; }
.rotation3D__line svg { position: absolute; top: 0; }
.rotation3D__line svg path {
stroke: #fff; fill: none;
stroke-width: 2;
animation: path-animation 100s linear 0s infinite normal;
}
@keyframes path-animation {
0% { stroke-dashoffset:500; }
100% { stroke-dashoffset:0; }
}
.rotation3D__line .dot {
position: absolute; top: 0; left: 0; text-align: center;
/*width: 35px; height: 35px; font-size: 35px; */
width: 19px; height: 19px; font-size: 19px;
}
.rotation3D__line .dot1,.rotation3D__line .dot3,.rotation3D__line .dot4{
animation: svg-path-animation 6s ease-in-out 0s infinite normal;
}
.rotation3D__line .dot1{
offset-path: path("M0 400, 0 0"); offset-distance: 0%;
}
.rotation3D__line .dot2{
offset-path: path("M0 200, 0 0"); offset-distance: 0%;
background: #ffd200; border-radius: 100%;
font-size: 22px; color: #000;
}
.rotation3D__line .dot3{
offset-path: path("M20 400 S 0 200, 20 0"); offset-distance: 0%;
}
.rotation3D__line .dot4{
position: relative;
offset-path: path("M20 0 S 40 200, 20 400"); offset-distance: 0%;
}
@keyframes svg-path-animation {
from {offset-distance: 100%;}
to {offset-distance: 0%;}
}
.dot1 > span{
position: absolute;
font-size: 12px;
color: #888;
transform: rotate(180deg)scale(0.80);
}

/*颜色*/
.rotation3D__line.blue { color: #07b2f9; }
.rotation3D__line.green { color: #ac94ee; }
.rotation3D__line.yellow { color: #ffd500; }

.rotation3D__line.blue svg path { stroke: #07b2f9; }
.rotation3D__line.green svg path { stroke: #ac94ee; }
.rotation3D__line.yellow svg path { stroke: #ffd500; }

+ 380
- 0
custom/public/rotation3D/rotation3D.js View File

@@ -0,0 +1,380 @@
var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame;
var requestFrame = window.requestAnimationFrame;
var time = !window.performance || !window.performance.now ?
function () {return +new Date()}:
function () {return performance.now()};

/**
* 计算两点距离
* @param points
* @returns {number}
* distance([{x:0,y:0},{x:1,y:1}]);
*/
var distance = function(points) {
var p1=points[0];
var p2=points[1];
var a = p2.x-p1.x;
var b = p2.y-p1.y;
return Math.sqrt(a*a+b*b);
};

/**
* 圆公式
* @param rotation 弧度
* 计算公式:
* Math.PI; //圆周率
* Math.sin(); //正弦 x -左 +右
* Math.cos; //余弦 y -下 +上
*/
var circleMath = {
/**
* 根据弧度计算角度
* @param rotation 弧度
* rotation, farScale, xs, xr, ys, yr, itemWidth
*/
// parseRotate: function (rotation) {
// return (180 / Math.PI * rotation) - 180;
// },
parseRotate: function (rotation, self) {
var sin = Math.sin(rotation), cos = Math.cos(rotation);
var sin_cos = sin*cos; //得出偏移正负值,从0°向左依次 +-+-
var angle = (180 / Math.PI * rotation) - 180;
var lastAngle = angle;

// console.log('rotation',rotation)
// console.log('sin',sin)
// console.log('cos',cos)
// console.log('sin*cos',sin*cos);
// console.log('统一偏移角度',self.yr * (sin_cos/Math.PI))

lastAngle = angle + (self.yr * (sin_cos/(Math.PI+1)));

return lastAngle;
},
/**
* 计算scale,x,y
* scale 最小尺寸 + ((1 - 最小尺寸) * (sin正弦 + 1) * 0.5)
* x x起点 + (尺寸 * cos余弦 * x半径) - 元素宽度一半
* y y起点 + (尺寸 * sin正弦 * x半径) - 元素宽度一半
* farScale, xs, xr, ys, yr, itemWidth
*/
parseSXY: function (rotation, self) {
var farScale=self.farScale;
var itemWidth=self.itemWidth;
var xs=self.xs; var xr=self.xr; var ys=self.ys; var yr=self.yr;
var sin = Math.sin(rotation), cos = Math.cos(rotation);
var scale = farScale + ((1 - farScale) * (sin + 1) * 0.5); //单个尺寸

// 按设置尺寸
// var x = xs + (scale * cos * xr) - (itemWidth * 0.5);
// var y = ys + (scale * sin * yr) - (itemWidth * 0.5);
// 不使用压缩
// var x = xs + (cos * xs) - (itemWidth * 0.5);
// var y = ys + (sin * ys) - (itemWidth * 0.5);
// 使用压缩
var x = xs + (cos * xr) - (itemWidth * 0.5);
var y = ys + (sin * yr) - (itemWidth * 0.5);
var distanceNumber = distance([
{x:self.$rotation.width()/2 - self.$item.width()/2, y:self.$rotation.height()/2 - self.$item.height()/2},
{x:x,y:y}]
);

// console.log({x:self.$rotation.width()/2, y:self.$rotation.height()/2})
// console.log('x,y',x,y)
// console.log('两点距离',distanceNumber)

return {
x: x,
y: y,
scale: scale,
distanceNumber: distanceNumber,
}
},
}
/**
* 3D旋转
* @param id
*/
var Rotation3D = window.Rotation3D = function (_opts) {
var self=this;
this.$rotation = $(_opts.id)
this.$lineList = this.$rotation.find('.lineList')
this.$item = this.$rotation.find('.rotation3D__item')
this.$line = this.$rotation.find('.rotation3D__line')
this.itemWidth = this.$item.width();
this.itemHeight = this.$item.height();
this.length = this.$item.length;
// 圆计算
this.rotation = Math.PI / 2; //圆周率/2
this.destRotation = this.rotation;

var xr = this.$rotation.width() * 0.5;
var yr = this.$rotation.height() * 0.5;
var xRadius = _opts.xRadius || 0;
var yRadius = _opts.yRadius || 0;

var opts = Object.assign({
farScale: 1, // 最小尺寸
xs: xr, // x起点
ys: yr, // y起点
xr: xr - xRadius, // x半径-压缩
yr: yr - yRadius, // y半径-压缩
// 播放
autoPlay:false,
autoPlayDelay:3000,
currenIndex:-1,
fps:30,
speed:4,
},_opts)
Object.assign(this, opts)

// 遍历子元素
this.$item.each(function (index) {
$(this).click(function () {
$(this).addClass('active').siblings().removeClass('active')
self.goTo(index)
})
})
// 当前控件进入离开
this.$rotation.mouseenter(function () {
clearInterval(self.autoPlayTimer)
})
this.$rotation.mouseleave(function () {
self.onAutoPlay()
})

this.onAutoPlay()
this.onDrag()
this.render()

}
/**
* item样式
* x x起点 + (尺寸 * 余弦 * x压缩) - 元素宽度一半
* y y起点 + (尺寸 * 正弦 * y压缩) - 元素宽度一半
*/
Rotation3D.prototype.itemStyle = function($item, index, rotation) {
//console.log("itemStyle=" + rotation + " index=" + index);
var parseSXY = circleMath.parseSXY(rotation, this);
var scale = parseSXY.scale;
var x = parseSXY.x;
var y = parseSXY.y;
var $line = this.$lineList.find('.rotation3D__line').eq(index);

//设置当前子菜单的位置(left,top) = (x,y)
$item.find('.scale').css({
'transform': `scale(${scale})`,
// 'top': `${this.itemWidth * (1-scale) }`,
})
$item.css({
position: 'absolute',
display: 'inline-block',
// opacity: scale,
'z-index': parseInt(scale * 100),
'transform-origin': '0px 0px',
// 'transform': `translate(${x}px, ${y}px) scale(${scale})`,
'transform': `translate(${x}px, ${y}px)`,
});

/**
* 线样式
*/
$line.css({
height:parseSXY.distanceNumber,
})
$line.find('svg').css({
height:parseSXY.distanceNumber,
})
$line.find('.dot1').css({
'offset-path':`path("M0 ${parseSXY.distanceNumber}, 0 0")`,
})
$line.find('#path1').attr({
'd':`M0 ${parseSXY.distanceNumber}, 0 0`,
})

$line.find('.dot2').css({
'offset-path':`path("M0 ${parseSXY.distanceNumber/2}, 0 0")`,
})
$line.find('#path2').attr({
'd':`M0 ${parseSXY.distanceNumber}, 0 0`,
})

$line.find('.dot3').css({
'offset-path':`path("M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0")`,
})
$line.find('#path3').attr({
'd':`M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0`,
})

$line.find('.dot4').css({
'offset-path':`path("M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}")`,
})
$line.find('#path4').attr({
'd':`M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}`,
})

}
/**
* line样式
*/
Rotation3D.prototype.lineStyle = function($line, index, rotation) {
var rotate = circleMath.parseRotate(rotation, this)
//console.log("lineStyle=" + rotation + " index=" + index);

$line.css({
transform: 'rotate(' + rotate + 'deg)',
})
this.$lineList.css({
// transform: `rotateX(${this.yRadius / 3}deg)`,
})
}

/**
* 旋转至index
*/
Rotation3D.prototype.goTo = function (index) {
var self = this;
this.currenIndex = index;
//console.log('goTo currenIndex', index);
/**
* 1.计算floatIndex,用于控死amdiff
*/
var itemsRotated = this.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI);
var floatIndex = itemsRotated % this.length;
if (floatIndex < 0) { floatIndex = floatIndex + this.length; }

/**
* 2.计算diff,判断方向正反
*/
var diff = index - (floatIndex % this.length);
if (2 * Math.abs(diff) > this.length) {
diff -= (diff > 0) ? this.length : -this.length;
}
// 停止任何正在进行的旋转
this.destRotation += (2 * Math.PI / this.length) * -diff;
this.scheduleNextFrame();

}
/**
* 定时器渐近旋转
*/
Rotation3D.prototype.scheduleNextFrame = function () {
var self = this
this.lastTime = time();
// 暂停
var pause = function () {
cancelFrame ? cancelFrame(this.timer) : clearTimeout(self.timer);
self.timer = 0;
}
// 渐进播放
var playFrame = function () {
var rem = self.destRotation - self.rotation;
var now = time(), dt = (now - self.lastTime) * 0.002;
self.lastTime = now;
// console.log('rem',rem)

if (Math.abs(rem) < 0.003) {
self.rotation = self.destRotation;
pause();
} else {
// 渐近地接近目的地
self.rotation = self.destRotation - rem / (1 + (self.speed * dt));
self.scheduleNextFrame();
}
self.render();
}

this.timer = cancelFrame ?
requestFrame(playFrame) :
setTimeout(playFrame, 1000 / this.fps);
}
/**
* 更新
*/
Rotation3D.prototype.render = function () {
var self=this;
// 图形间隔:弧度
var spacing = 2 * Math.PI / this.$item.length;
var itemRotation = this.rotation;
var lineRotation = this.rotation + (Math.PI/2);

this.$item.each(function (index) {
self.itemStyle($(this), index, itemRotation)
itemRotation += spacing;
})
this.$line.each(function (index) {
self.lineStyle($(this), index, lineRotation)
lineRotation += spacing;
})
}
/**
* 自动播放
*/
Rotation3D.prototype.onAutoPlay = function () {
var self = this;

if (this.autoPlay) {
this.autoPlayTimer = setInterval(function () {
if (self.currenIndex < 0) {
self.currenIndex = self.length - 1
}
//console.log("autoPlayTimer....");
self.goTo(self.currenIndex);
self.currenIndex--; //倒叙
}, this.autoPlayDelay)
}
}
/**
* 拖拽
*/
Rotation3D.prototype.onDrag = function () {
var self = this;
var startX, startY, moveX, moveY, endX, endY;
//console.log("onDrag....");
// 拖拽:三个事件-按下 移动 抬起
//按下
this.$rotation.mousedown(function (e) {
startX = e.pageX; startY = e.pageY;
//console.log("mousedown....");
// 移动
$(document).mousemove(function (e) {
// console.log('移动');
endX = e.pageX; endY = e.pageY;
moveX = endX - startX; moveY = endY - startY;
// console.log('x,y',moveX,moveY);
})
// 抬起
$(document).mouseup(function (e) {
endX = e.pageX; endY = e.pageY;
moveX = endX - startX; moveY = endY - startY;
//console.log("mouseup....");
// 每40旋转一步
var moveIndex = parseInt(Math.abs(moveX) / 50)
//console.log('moveIndex',moveIndex)
if (moveIndex > 0) {
// console.log(moveX<0 ? '向左' : '向右')
if (moveX < 0) { //向左
self.currenIndex = self.currenIndex - moveIndex
play(moveIndex)
} else { //向右
self.currenIndex = self.currenIndex + moveIndex
play(moveIndex)
}
}

// 解绑
$(document).unbind("mousemove");
$(document).unbind("mouseup");
})

})

function play() {
if (self.currenIndex == 0) {
self.currenIndex = self.length - 1
}
self.goTo(self.currenIndex % self.length);
}

}

+ 6
- 0
custom/public/rotation3D/vue-2.6.10.min.js
File diff suppressed because it is too large
View File


+ 11
- 0
models/attachment.go View File

@@ -43,6 +43,7 @@ type Attachment struct {
Name string
Description string `xorm:"TEXT"`
DownloadCount int64 `xorm:"DEFAULT 0"`
UseNumber int64 `xorm:"DEFAULT 0"`
Size int64 `xorm:"DEFAULT 0"`
IsPrivate bool `xorm:"DEFAULT false"`
DecompressState int32 `xorm:"DEFAULT 0"`
@@ -81,6 +82,7 @@ type AttachmentsOptions struct {
NeedRepoInfo bool
Keyword string
RecommendOnly bool
UserId int64
}

func (a *Attachment) AfterUpdate() {
@@ -107,6 +109,15 @@ func (a *Attachment) IncreaseDownloadCount() error {
return nil
}

func IncreaseAttachmentUseNumber(uuid string) error {
// Update use number.
if _, err := x.Exec("UPDATE `attachment` SET use_number=use_number+1 WHERE uuid=?", uuid); err != nil {
return fmt.Errorf("increase attachment use count: %v", err)
}

return nil
}

func (a *Attachment) UpdateDatasetUpdateUnix() error {
// Update download count.
if _, err := x.Exec("UPDATE `dataset` SET updated_unix="+fmt.Sprint(time.Now().Unix())+" WHERE id=?", a.DatasetID); err != nil {


+ 105
- 2
models/cloudbrain.go View File

@@ -24,6 +24,7 @@ type ModelArtsJobStatus string
const (
TypeCloudBrainOne int = iota
TypeCloudBrainTwo
TypeIntelligentNet

TypeCloudBrainAll = -1
)
@@ -328,6 +329,11 @@ type CloudbrainsOptions struct {
JobTypeNot bool
NeedRepoInfo bool
RepoIDList []int64
BeginTime time.Time
EndTime time.Time
ComputeResource string
BeginTimeUnix int64
EndTimeUnix int64
}

type TaskPod struct {
@@ -1150,6 +1156,17 @@ type LogFile struct {
Name string
}

type GetTrainJobMetricStatisticResult struct {
TrainJobResult
Interval int `json:"interval"` //查询的时间间隔,单位为分钟
MetricsInfo []Metrics `json:"metrics"` //监控详情
}

type Metrics struct {
Metric string `json:"metric"` //监控指标项
Value []string `json:"value"` //获取的监控值的序列,元素为String类型
}

func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
sess := x.NewSession()
defer sess.Close()
@@ -1172,6 +1189,11 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
builder.Eq{"cloudbrain.job_id": opts.JobID},
)
}
if (opts.ComputeResource) != "" {
cond = cond.And(
builder.Eq{"cloudbrain.compute_resource": opts.ComputeResource},
)
}

if (opts.Type) >= 0 {
cond = cond.And(
@@ -1280,7 +1302,8 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error)
builder.Eq{"cloudbrain.job_id": jobId},
)
cond = cond.And(
builder.Eq{"cloudbrain.Status": "COMPLETED"},
builder.In("cloudbrain.Status", "COMPLETED", "SUCCEEDED"),
//builder.Eq{"cloudbrain.Status": "COMPLETED"},
)

sess.OrderBy("cloudbrain.created_unix DESC")
@@ -1301,7 +1324,7 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) {
builder.Eq{"repo_id": repoId},
)
cond = cond.And(
builder.Eq{"Status": "COMPLETED"},
builder.In("Status", "COMPLETED", "SUCCEEDED"),
)
cond = cond.And(
builder.Eq{"job_type": "TRAIN"},
@@ -1395,6 +1418,8 @@ func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) {
if _, err = x.NoAutoTime().Insert(cloudbrain); err != nil {
return err
}

go IncreaseDatasetUseCount(cloudbrain.Uuid)
return nil
}

@@ -1490,6 +1515,11 @@ func UpdateJob(job *Cloudbrain) error {
return updateJob(x, job)
}

func UpdateJobDurationWithDeleted(job *Cloudbrain) error {
_, err := x.Exec("update cloudbrain set start_time=?, end_time=?,train_job_duration=?,duration=? where id=?", job.StartTime, job.EndTime, job.TrainJobDuration, job.Duration, job.ID)
return err
}

func updateJob(e Engine, job *Cloudbrain) error {
_, err := e.ID(job.ID).AllCols().Update(job)
return err
@@ -1560,6 +1590,10 @@ func GetStoppedJobWithNoDurationJob() ([]*Cloudbrain, error) {
Limit(100).
Find(&cloudbrains)
}
func GetStoppedJobWithNoStartTimeEndTime() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.SQL("select * from cloudbrain where status in (?,?,?,?,?,?,?) and (start_time is null or end_time is null) limit 100", ModelArtsTrainJobCompleted, ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed, JobSucceeded).Find(&cloudbrains)
}

func GetCloudbrainCountByUserID(userID int64, jobType string) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", jobType, userID, TypeCloudBrainOne).Count(new(Cloudbrain))
@@ -1629,18 +1663,87 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
return err
}

go IncreaseDatasetUseCount(new.Uuid)

return nil
}
func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
sess := x.NewSession()
defer sess.Close()

var cond = builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(
builder.Eq{"cloudbrain.repo_id": opts.RepoID},
)
}

if opts.UserID > 0 {
cond = cond.And(
builder.Eq{"cloudbrain.user_id": opts.UserID},
)
}

if (opts.JobID) != "" {
cond = cond.And(
builder.Eq{"cloudbrain.job_id": opts.JobID},
)
}
if (opts.ComputeResource) != "" {
cond = cond.And(
builder.Eq{"cloudbrain.compute_resource": opts.ComputeResource},
)
}

if (opts.Type) >= 0 {
cond = cond.And(
builder.Eq{"cloudbrain.type": opts.Type},
)
}

if len(opts.JobTypes) > 0 {
if opts.JobTypeNot {
cond = cond.And(
builder.NotIn("cloudbrain.job_type", opts.JobTypes),
)
} else {
cond = cond.And(
builder.In("cloudbrain.job_type", opts.JobTypes),
)
}
}

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"}))
}

if len(opts.CloudbrainIDs) > 0 {
cond = cond.And(builder.In("cloudbrain.id", opts.CloudbrainIDs))
}

if len(opts.JobStatus) > 0 {
if opts.JobStatusNot {
cond = cond.And(
builder.NotIn("cloudbrain.status", opts.JobStatus),
)
} else {
cond = cond.And(
builder.In("cloudbrain.status", opts.JobStatus),
)
}
}
if len(opts.RepoIDList) > 0 {
cond = cond.And(
builder.In("cloudbrain.repo_id", opts.RepoIDList),
)

}
if opts.BeginTimeUnix > 0 && opts.EndTimeUnix > 0 {
cond = cond.And(
builder.And(builder.Gte{"cloudbrain.created_unix": opts.BeginTimeUnix}, builder.Lte{"cloudbrain.created_unix": opts.EndTimeUnix}),
)
}

var count int64
var err error
condition := "cloudbrain.user_id = `user`.id"


+ 291
- 0
models/cloudbrain_static.go View File

@@ -0,0 +1,291 @@
package models

import (
"strconv"
"time"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)

type TaskDetail struct {
ID int64 `json:"ID"`
JobID string `json:"JobID"`
JobName string `json:"JobName"`
DisplayJobName string `json:"DisplayJobName"`
Status string `json:"Status"`
JobType string `json:"JobType"`
CreatedUnix timeutil.TimeStamp `json:"CreatedUnix"`
WaitTime string `json:"WaitTime"`
RunTime string `json:"RunTime"`
StartTime timeutil.TimeStamp `json:"StartTime"`
EndTime timeutil.TimeStamp `json:"EndTime"`
ComputeResource string `json:"ComputeResource"`
Type int `json:"Type"`
UserName string `json:"UserName"`
RepoName string `json:"RepoName"`
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
}

func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) {
countSql := "SELECT count(distinct user_id) FROM " +
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)
return x.SQL(countSql).Count()
}
func GetTodayCloudbrainCount(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)
return x.SQL(countSql).Count()
}
func GetCreatorCount() (int64, error) {
countSql := "SELECT count(distinct user_id) FROM public.cloudbrain"
return x.SQL(countSql).Count()
}

func GetRecordBeginTime() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()
sess.OrderBy("cloudbrain.id ASC limit 1")
cloudbrains := make([]*CloudbrainInfo, 0)
if err := sess.Table(&Cloudbrain{}).Unscoped().
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}

func GetAllStatusCloudBrain() map[string]int {
sess := x.NewSession()
defer sess.Close()
cloudbrains := make([]*CloudbrainInfo, 0)
if err := sess.Table(&Cloudbrain{}).Unscoped().
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
cloudBrainStatusResult := make(map[string]int)
for _, cloudbrain := range cloudbrains {
if _, ok := cloudBrainStatusResult[cloudbrain.Status]; !ok {
cloudBrainStatusResult[cloudbrain.Status] = 1
} else {
cloudBrainStatusResult[cloudbrain.Status] += 1
}
}
return cloudBrainStatusResult
}

func GetWaittingTop() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"cloudbrain.status": string(JobWaiting)},
)
sess.OrderBy("(cloudbrain.start_time-cloudbrain.created_unix) DESC limit 10")
cloudbrains := make([]*CloudbrainInfo, 0, 10)
if err := sess.Table(&Cloudbrain{}).Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}
func GetRunningTop() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"cloudbrain.status": string(JobRunning)},
)
sess.OrderBy("(cloudbrain.end_time-cloudbrain.start_time) DESC limit 10")
cloudbrains := make([]*CloudbrainInfo, 0, 10)
if err := sess.Table(&Cloudbrain{}).Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}

func getCreatePeriodCount(dateBeginTime string, dateEndTime string, hourBeginTime string, hourEndTime string) (int64, error) {
countSql := "SELECT count(*) FROM " +
"public.cloudbrain where to_char(to_timestamp(created_unix), 'YYYY-MM-DD') >= '" + dateBeginTime +
"' and to_char(to_timestamp(created_unix), 'YYYY-MM-DD') < '" + dateEndTime +
"' and to_char(to_timestamp(created_unix), 'HH24:MI:SS') >= '" + hourBeginTime +
"' and to_char(to_timestamp(created_unix), 'HH24:MI:SS') < '" + hourEndTime + "'"
return x.SQL(countSql).Count()
}

//SELECT * FROM xxx WHERE NOT ((endTime < hourBeginTime) OR (startTime > hourEndTime))
func getRunPeriodCount(dateBeginTime string, dateEndTime string, hourBeginTime string, hourEndTime string) (int64, error) {
countSql := "SELECT count(*) FROM " +
"public.cloudbrain where not ((to_char(to_timestamp(start_time), ' HH24:MI:SS') > '" + hourEndTime +
"') or (to_char(to_timestamp(end_time), 'HH24:MI:SS') < '" + hourBeginTime + "'))" +
" and (to_char(to_timestamp(start_time), 'YYYY-MM-DD') >= '" + dateBeginTime +
"' and to_char(to_timestamp(start_time), 'YYYY-MM-DD') < '" + dateEndTime + "')"
return x.SQL(countSql).Count()

}

func GetCreateHourPeriodCount(dateBeginTime string, dateEndTime string) (map[string]interface{}, error) {
//0 to 23 for each hour,
dateHourMap := make(map[string]interface{})
var slice = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}
for key, value := range slice {
hourBeginHour := util.AddZero(value) + ":00:00"
hourEndHour := util.AddZero(value+1) + ":00:00"
cout, err := getCreatePeriodCount(dateBeginTime, dateEndTime, hourBeginHour, hourEndHour)
if err != nil {
log.Error("Can not query getCreatePeriodCount.", err)
return nil, nil
}
dateHourMap[strconv.Itoa(key)] = cout
}
return dateHourMap, nil
}

func GetRunHourPeriodCount(dateBeginTime string, dateEndTime string) (map[string]interface{}, error) {
dateHourMap := make(map[string]interface{})
var slice = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}
for key, value := range slice {
hourBeginHour := util.AddZero(value) + ":00:00"
hourEndHour := util.AddZero(value+1) + ":00:00"
cout, err := getRunPeriodCount(dateBeginTime, dateEndTime, hourBeginHour, hourEndHour)
if err != nil {
log.Error("Can not query getRunPeriodCount.", err)
return nil, nil
}
dateHourMap[strconv.Itoa(key)] = cout
}
return dateHourMap, nil
}

+ 30
- 3
models/dataset.go View File

@@ -25,8 +25,9 @@ type Dataset struct {
Category string
Description string `xorm:"TEXT"`
DownloadTimes int64
NumStars int `xorm:"INDEX NOT NULL DEFAULT 0"`
Recommend bool `xorm:"INDEX NOT NULL DEFAULT false"`
UseCount int64 `xorm:"DEFAULT 0"`
NumStars int `xorm:"INDEX NOT NULL DEFAULT 0"`
Recommend bool `xorm:"INDEX NOT NULL DEFAULT false"`
License string
Task string
ReleaseID int64 `xorm:"INDEX"`
@@ -106,6 +107,7 @@ type SearchDatasetOptions struct {
Category string
Task string
License string
DatasetIDs []int64
ListOptions
SearchOrderBy
IsOwner bool
@@ -176,6 +178,12 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
}
}

if len(opts.DatasetIDs) > 0 {
subCon := builder.NewCond()
subCon = subCon.And(builder.In("dataset.id", opts.DatasetIDs))
cond = cond.Or(subCon)
}

return cond
}

@@ -212,7 +220,7 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da
defer sess.Close()

datasets := make(DatasetList, 0, opts.PageSize)
selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars,dataset.recommend"
selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars,dataset.recommend,dataset.use_count"

count, err := sess.Distinct("dataset.id").Join("INNER", "repository", "repository.id = dataset.repo_id").
Join("INNER", "attachment", "attachment.dataset_id=dataset.id").
@@ -350,6 +358,17 @@ func UpdateDataset(ctx DBContext, rel *Dataset) error {
return err
}

func IncreaseDatasetUseCount(uuid string) {

IncreaseAttachmentUseNumber(uuid)

attachment, _ := GetAttachmentByUUID(uuid)
if attachment != nil {
x.Exec("UPDATE `dataset` SET use_count=use_count+1 WHERE id=?", attachment.DatasetID)
}

}

// GetDatasetByID returns Dataset with given ID.
func GetDatasetByID(id int64) (*Dataset, error) {
rel := new(Dataset)
@@ -435,3 +454,11 @@ func IncreaseDownloadCount(datasetID int64) error {

return nil
}

func GetCollaboratorDatasetIdsByUserID(userID int64) []int64 {
var datasets []int64
_ = x.Table("dataset").Join("INNER", "collaboration", "dataset.repo_id = collaboration.repo_id and collaboration.mode>0 and collaboration.user_id=?", userID).
Cols("dataset.id").Find(&datasets)
return datasets

}

+ 2
- 0
models/repo_list.go View File

@@ -218,6 +218,8 @@ const (
SearchOrderByForks SearchOrderBy = "num_forks ASC"
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC"
SearchOrderByUseCount SearchOrderBy = "use_count ASC"
SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC"
SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC"
SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC"
SearchOrderByWatches SearchOrderBy = "num_watches DESC"


+ 16
- 13
models/user_business_analysis.go View File

@@ -719,12 +719,11 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
userIndexMap := make(map[int64]float64, 0)
maxUserIndex := 0.0
minUserIndex := 100000000.0
dateRecordBatch := make([]UserBusinessAnalysisAll, 0)
for {
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userList := make([]*User, 0)
sess.Find(&userList)
dateRecordBatch := make([]UserBusinessAnalysisAll, 0)
for _, userRecord := range userList {
var dateRecordAll UserBusinessAnalysisAll
dateRecordAll.ID = userRecord.ID
@@ -789,7 +788,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS

dateRecordBatch = append(dateRecordBatch, dateRecordAll)
if len(dateRecordBatch) >= BATCH_INSERT_SIZE {
insertTable(dateRecordBatch, tableName, statictisSess)
err := insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += BATCH_INSERT_SIZE
if err != nil {
log.Info("insert all data failed." + err.Error())
@@ -804,18 +803,19 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
}
}
}
if len(dateRecordBatch) > 0 {
err := insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += len(dateRecordBatch)
if err != nil {
log.Info("insert all data failed." + err.Error())
}
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
if len(dateRecordBatch) > 0 {
insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += len(dateRecordBatch)
if err != nil {
log.Info("insert all data failed." + err.Error())
}
}

if tableName == "user_business_analysis_all" {
log.Info("TotalHasActivityUser=" + fmt.Sprint(userMetrics["TotalHasActivityUser"]))
}
@@ -835,7 +835,7 @@ func updateUserIndex(tableName string, statictisSess *xorm.Session, userId int64
statictisSess.Exec(updateSql)
}

func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) {
func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) error {

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, " +
@@ -854,7 +854,8 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static
}
}

statictisSess.Exec(insertBatchSql)
_, err := statictisSess.Exec(insertBatchSql)
return err
}

func RefreshUserStaticAllTabel(wikiCountMap map[string]int, userMetrics map[string]int) {
@@ -2057,7 +2058,9 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s
} else {
resultMap[cloudTaskRecord.UserID] += 1
}
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap)
if cloudTaskRecord.Duration < 100000000 && cloudTaskRecord.Duration > 0 {
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap)
}
if cloudTaskRecord.Type == 1 { //npu
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)


+ 1
- 0
modules/auth/repo_form.go View File

@@ -46,6 +46,7 @@ type CreateRepoForm struct {
Webhooks bool
Avatar bool
Labels bool
AutoAgree bool
}

// Validate validates the fields


+ 2
- 1
modules/cloudbrain/cloudbrain.go View File

@@ -187,7 +187,7 @@ func AdminOrImageCreaterRight(ctx *context.Context) {

}

func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description, branchName, bootFile, params string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error {
func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description, branchName, bootFile, params, commitID string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error {

dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" +
@@ -336,6 +336,7 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command,
Parameters: params,
CreatedUnix: createTime,
UpdatedUnix: createTime,
CommitID: commitID,
})

if err != nil {


+ 41
- 0
modules/modelarts/resty.go View File

@@ -1119,3 +1119,44 @@ sendjob:

return &result, nil
}

func GetTrainJobMetricStatistic(jobID, versionID, podName string) (*models.GetTrainJobMetricStatisticResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetTrainJobMetricStatisticResult

retry := 0

sendjob:
res, err := client.R().
SetAuthToken(TOKEN).
SetResult(&result).
Get(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions/" + versionID + "/pod/" + podName + "/metric-statistic?statistic_type=each")

if err != nil {
return nil, fmt.Errorf("resty GetTrainJobMetricStatistic: %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("GetTrainJobMetricStatistic failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("GetTrainJobMetricStatistic failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}

if !result.IsSuccess {
log.Error("GetTrainJobMetricStatistic(%s) failed", jobID)
return &result, fmt.Errorf("获取任务资源占用情况失败:%s", result.ErrorMsg)
}

return &result, nil
}

+ 8
- 0
modules/storage/local.go View File

@@ -39,6 +39,14 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) {
return f, nil
}

func (l *LocalStorage) DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) {
f, err := os.Open(filepath.Join(l.dir, objectName))
if err != nil {
return nil, err
}
return f, nil
}

// Save save a file
func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) {
p := filepath.Join(l.dir, path)


+ 10
- 0
modules/storage/minio.go View File

@@ -59,6 +59,16 @@ func (m *MinioStorage) buildMinioPath(p string) string {
return strings.TrimPrefix(path.Join(m.basePath, p), "/")
}

func (m *MinioStorage) DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) {

var opts = minio.GetObjectOptions{}
object, err := m.client.GetObject(m.bucket, objectName, opts)
if err != nil {
return nil, err
}
return object, nil
}

// Open open a file
func (m *MinioStorage) Open(path string) (io.ReadCloser, error) {
var opts = minio.GetObjectOptions{}


+ 134
- 0
modules/storage/minio_ext.go View File

@@ -113,7 +113,141 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")

return minioClient.GenUploadPartSignedUrl(uploadId, bucketName, objectName, partNumber, partSize, PresignedUploadPartUrlExpireTime, setting.Attachment.Minio.Location)
}

func GetAllObjectByBucketAndPrefixMinio(bucket string, prefix string) ([]FileInfo, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, err
}
prefixLen := len(prefix)
delimiter := ""
marker := ""
index := 1
fileInfoList := FileInfoList{}
for {
output, err := core.ListObjects(bucket, prefix, marker, delimiter, 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
for _, val := range output.Contents {
var isDir bool
if prefixLen == len(val.Key) {
continue
}
if strings.HasSuffix(val.Key, "/") {
isDir = true
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Format("2006-01-02 15:04:05"),
FileName: val.Key[prefixLen:],
Size: val.Size,
IsDir: isDir,
ParenDir: "",
}
fileInfoList = append(fileInfoList, fileInfo)
}
if output.IsTruncated {
marker = output.NextMarker
} else {
break
}
} else {
log.Info("list error." + err.Error())
return nil, err
}
}
sort.Sort(fileInfoList)
return fileInfoList, nil
}

func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, relativePath string) ([]FileInfo, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, err
}

Prefix := prefixRootPath + relativePath
if !strings.HasSuffix(Prefix, "/") {
Prefix += "/"
}
log.Info("bucket=" + bucket + " Prefix=" + Prefix)
output, err := core.ListObjects(bucket, Prefix, "", "", 1000)
fileInfos := make([]FileInfo, 0)
prefixLen := len(Prefix)
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], "/") {
continue
}
if strings.HasSuffix(val.Key, "/") {
isDir = true
fileName = val.Key[prefixLen : len(val.Key)-1]
relativePath += val.Key[prefixLen:]
} 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,
}
fileInfos = append(fileInfos, fileInfo)
}
return fileInfos, err
} else {

log.Error("Message:%s", err.Error())

return nil, err
}

}

func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) {
_, core, err := getClients()
var fileTotalSize int64
fileTotalSize = 0
if err != nil {
log.Error("getClients failed:", err.Error())
return fileTotalSize, err
}
delimiter := ""
marker := ""
for {
output, err := core.ListObjects(bucketName, srcPath, marker, delimiter, 1000)
if err == nil {
for _, val := range output.Contents {
srcObjectName := val.Key
destObjectName := destPath + srcObjectName[len(srcPath):]
log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName)
core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, val.UserMetadata)
fileTotalSize += val.Size
}
if output.IsTruncated {
marker = output.NextMarker
} else {
break
}
} else {
log.Info("list error." + err.Error())
return 0, err
}
}
return fileTotalSize, nil
}

func NewMultiPartUpload(uuid string) (string, error) {


+ 14
- 0
modules/storage/obs.go View File

@@ -564,3 +564,17 @@ func ObsCreateObject(path string) error {

return nil
}

func GetObsLogFileName(prefix string) (string, error) {
input := &obs.ListObjectsInput{}
input.Bucket = setting.Bucket
input.Prefix = prefix

output, err := ObsCli.ListObjects(input)
if err != nil {
log.Error("PutObject failed:", err.Error())
return "", err
}

return output.Contents[0].Key, nil
}

+ 1
- 0
modules/storage/storage.go View File

@@ -22,6 +22,7 @@ const (
type ObjectStorage interface {
Save(path string, r io.Reader) (int64, error)
Open(path string) (io.ReadCloser, error)
DownloadAFile(bucket string, objectName string) (io.ReadCloser, error)
Delete(path string) error
DeleteDir(dir string) error
PresignedGetURL(path string, fileName string) (string, error)


+ 12
- 2
options/locale/locale_en-US.ini View File

@@ -898,6 +898,10 @@ search_dataset = Search Dataset Files
unzip_tooltips = If it has not been decompressed for a long time, please check whether the compressed package has encrypted files or file errors
zip_failed = Decompression failed, please check whether the compressed package is encrypted or contact technical support
dataset_desc = The description should not exceed 1024 characters
unzip_successed=Unzip Successed
unzip_failed=Unzip Failed
unzip_stared=Unzipping
unzip_status=Unzip Status
[repo]
owner = Owner
repo_name = Repository Name
@@ -1088,6 +1092,7 @@ modelarts.train_job.fast_parameter_setting_config_link=fast_parameter_setting_co
modelarts.train_job.frames=frames
modelarts.train_job.algorithm_origin=Algorithm Origin
modelarts.train_job.AI_driver=AI Engine
modelarts.train_job.AI_Engine=AI Engine
modelarts.train_job.start_file=Start File
modelarts.train_job.boot_file_helper=The startup file is the entry file that your program executes, and it must be a file ending in .py
modelarts.train_job.dataset=Dataset
@@ -1141,6 +1146,7 @@ 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.tooltip = The model has been deleted and cannot be viewed.
modelarts.download_log=Download log file


debug_task_not_created = Debug task has not been created
@@ -1179,6 +1185,7 @@ template.topics = Topics
template.avatar = Avatar
template.issue_labels = Issue Labels
template.one_item = Must select at least one template item
template.one_promise = Must agree to use the agreement!
template.invalid = Must select a template repository
template.repo_adress=Adress
template.repo_path=path
@@ -1446,7 +1453,9 @@ issues.filter_sort.feweststars = Fewest stars
issues.filter_sort.mostforks = Most forks
issues.filter_sort.fewestforks = Fewest forks
issues.filter_sort.downloadtimes = Most downloaded
issues.filter_sort.moststars = Most star
issues.filter_sort.citations=Citations
issues.filter_sort.mostusecount = Most Quote
issues.filter_sort.fewestusecount=Fewest Quote
issues.action_open = Open
issues.action_close = Close
issues.action_label = Label
@@ -2252,7 +2261,8 @@ topic.done = Done
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.
[org]
org_name_holder = Organization Name
org_full_name_holder = Organization Full Name


+ 21
- 6
options/locale/locale_zh-CN.ini View File

@@ -226,7 +226,7 @@ contributors=贡献者
contributor=贡献者

page_title=探索更好的AI
page_small_title=启智AI开发协作平台
page_small_title=启智AI协作平台
page_description=面向AI领域的一站式协同开发环境,提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线
page_use=立即使用
page_only_dynamic=仅展示开源项目动态
@@ -903,6 +903,10 @@ search_dataset = 搜索数据集文件
unzip_tooltips = 如果长时间未解压,请检查压缩包是否有加密文件或者文件错误
zip_failed = 解压失败,请检查压缩包是否有加密或者联系技术支持人员。
dataset_desc = 描述字数不超过1024个字符
unzip_successed=解压成功
unzip_failed=解压失败
unzip_stared=解压中
unzip_status=解压状态

[repo]
owner=拥有者
@@ -1016,13 +1020,16 @@ balance.total_view=余额总览
balance.available=可用余额:
cloudbrain1=云脑1
cloudbrain2=云脑2
intelligent_net=智算网络
cloudbrain_selection=云脑选择
cloudbrain_platform_selection=选择您准备使用的云脑平台:
confirm_choice=确定
cloudbran1_tips=只有zip格式的数据集才能发起云脑任务
cloudbrain_creator=创建者
cloudbrain_type=支撑算力
cloudbrain_untype=未知支撑算力
cloudbrain_task=任务名称
cloudbrain_task_type=任务类型
cloudbrain_task_type=云脑任务类型
cloudbrain_task_name=云脑侧任务名称
cloudbrain_operate=操作
cloudbrain_status_createtime=状态/创建时间
@@ -1056,6 +1063,7 @@ computing.success=加入成功

modelarts.status=状态
modelarts.createtime=创建时间
modelarts.deletetime=删除时间
modelarts.version_nums=版本数
modelarts.version=版本
modelarts.computing_resources=计算资源
@@ -1086,8 +1094,8 @@ modelarts.train_job.job_status=任务状态
modelarts.train_job.job_name=任务名称
modelarts.train_job.version=任务版本
modelarts.train_job.start_time=开始运行时间
modelarts.train_job.end_time=运行结束时间
modelarts.train_job.wait_time=等待时
modelarts.train_job.end_time=结束运行时间
modelarts.train_job.wait_time=等待时
modelarts.train_job.dura_time=运行时长
modelarts.train_job.description=任务描述
modelarts.train_job.parameter_setting=参数设置
@@ -1098,6 +1106,7 @@ modelarts.train_job.fast_parameter_setting_config_link=这里
modelarts.train_job.frames=常用框架
modelarts.train_job.algorithm_origin=算法来源
modelarts.train_job.AI_driver=AI引擎
modelarts.train_job.AI_Engine=模型框架
modelarts.train_job.start_file=启动文件
modelarts.train_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。比如train.py、main.py、example/train.py、case/main.py。
modelarts.train_job.boot_file_place=填写启动文件路径,默认为train.py
@@ -1151,6 +1160,7 @@ modelarts.infer_job.model_version = 模型/版本
modelarts.infer_job.select_model = 选择模型
modelarts.infer_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。比如inference.py、main.py、example/inference.py、case/main.py。
modelarts.infer_job.tooltip = 该模型已删除,无法查看。
modelarts.download_log=下载日志文件


debug_task_not_created = 未创建过调试任务
@@ -1189,6 +1199,7 @@ template.topics=主题
template.avatar=头像
template.issue_labels=任务标签
template.one_item=必须至少选择一个模板项
template.one_promise=创建项目时需承诺遵守使用协议
template.invalid=必须选择一个模板项目
template.repo_adress=项目地址
template.repo_path=项目地址
@@ -1452,12 +1463,15 @@ issues.filter_sort.mostcomment=最多评论
issues.filter_sort.leastcomment=最少评论
issues.filter_sort.nearduedate=到期日从近到远
issues.filter_sort.farduedate=到期日从远到近
issues.filter_sort.moststars=点赞由多到少
issues.filter_sort.feweststars=点赞由少到多
issues.filter_sort.mostforks=派生由多到少
issues.filter_sort.fewestforks=派生由少到多
issues.filter_sort.downloadtimes=下载次数
issues.filter_sort.citations=引用次数
issues.filter_sort.moststars=收藏数量
issues.filter_sort.mostusecount=最多引用
issues.filter_sort.fewestusecount=最少引用

issues.action_open=开启
issues.action_close=关闭
issues.action_label=标签
@@ -2262,7 +2276,8 @@ topic.done=保存
topic.count_prompt=您最多选择25个标签
topic.format_prompt=标签必须以中文、字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
imagetopic.format_prompt=标签长度不得超过35个字符

use_repo_agreement=我承诺此仓内容不违反任何国家法律法规,仓库使用过程中遵守OpenI启智社区管理规定和平台使用规则,不进行恶意攻击、挖矿等任何违法或扰乱平台秩序的信息发布和相关行为。更多信息请参考
openi_use_agreement=OpenI启智社区平台使用协议
[org]
org_name_holder=组织名称
org_full_name_holder=组织全名


+ 66
- 5
public/home/home.js View File

@@ -9,7 +9,7 @@ if(isEmpty(token)){

var swiperNewMessage = new Swiper(".newslist", {
direction: "vertical",
slidesPerView: 10,
slidesPerView: 9,
loop: true,
autoplay: {
delay: 2500,
@@ -17,7 +17,7 @@ var swiperNewMessage = new Swiper(".newslist", {
},
});
var swiperEvent = new Swiper(".event-list", {
slidesPerView: 2,
slidesPerView: 3,
spaceBetween: 30,
pagination: {
el: ".swiper-pagination",
@@ -117,6 +117,7 @@ socket.onmessage = function (e) {
continue;
}
}
refresh3DInfo(record);
var recordPrefix = getMsg(record);
if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){
html += recordPrefix + actionName;
@@ -200,6 +201,29 @@ 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);
span.innerText =record.RefName;
//$('.rotation3D__line').find("span").eq(1).text(record.RefName)
//lines[1].find("span").text(record.RefName);
}

}

function getMsg(record){
var html ="";
html += "<div class=\"swiper-slide item\">";
@@ -425,13 +449,50 @@ function queryRecommendData(){
dataType:"json",
async:false,
success:function(json){
displayOrg(json.org);
displayRepo(json.repo);
displayActivity(json.image)
displayOrg(json.org);
displayRepo(json.repo);
displayActivity(json.image);
displayCloudBrain(json.cloudbrain)
},
error:function(response) {
}
});

// $.ajax({
// type:"GET",
// url:"/recommend/repo",
// headers: {
// authorization:token,
// },
// dataType:"json",
// async:false,
// success:function(json){
// displayRepo(json);
// },
// error:function(response) {
// }
// });

// $.ajax({
// type:"GET",
// url:"/recommend/imageinfo",
// headers: {
// authorization:token,
// },
// dataType:"json",
// async:false,
// success:function(json){
// displayActivity(json);
// },
// error:function(response) {
// }
// });
}

function displayCloudBrain(json){
$('#completed_task').text(json.completed_task);
$('#running_task').text(json.running_task);
$('#wait_task').text(json.wait_task);
}

function displayActivity(json){


+ 1
- 0
public/self/css/notebook/katex.min.css
File diff suppressed because it is too large
View File


+ 86
- 0
public/self/css/notebook/notebook.css View File

@@ -0,0 +1,86 @@
.nb-notebook {
line-height: 1.5;
margin-left: 7em;
}

.nb-stdout, .nb-stderr {
white-space: pre-wrap;
margin: 1em 0;
padding: 0.1em 0.5em;
}

.nb-stderr {
background-color: #FAA;
}

.nb-cell + .nb-cell {
margin-top: 0.5em;
}

.nb-output table {
border: 1px solid #000;
border-collapse: collapse;
}

.nb-output th {
font-weight: bold;
}

.nb-output th, .nb-output td {
border: 1px solid #000;
padding: 0.25em;
text-align: left;
vertical-align: middle;
border-collapse: collapse;
}

.nb-notebook blockquote {
border-left: 5px solid #CCC;
margin-left: 0;
padding-left: 1em;
}

.nb-cell {
position: relative;
}

.nb-raw-cell {
white-space: pre-wrap;
background-color: #f5f2f0;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
padding: 1em;
margin: .5em 0;
}

.nb-output {
min-height: 1em;
width: 100%;
overflow-x: scroll;
border-right: 1px dotted #CCC;
}

.nb-output img {
max-width: 100%;
}

.nb-output:before, .nb-input:before {
position: absolute;
font-family: monospace;
color: #999;
left: -7em;
width: 7em;
text-align: right;
}

.nb-input:before {
content: "In [" attr(data-prompt-number) "]:";
}
.nb-output:before {
content: "Out [" attr(data-prompt-number) "]:";
}

// Fix pandas dataframe formatting
div[style="max-height:1000px;max-width:1500px;overflow:auto;"] {
max-height: none !important;
}


+ 142
- 0
public/self/css/notebook/prism.css View File

@@ -0,0 +1,142 @@
/* PrismJS 1.21.0
https://prismjs.com/download.html#themes=prism&languages=markup+clike+javascript+julia+python+r */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/

code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;

-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;

-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}

pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}

pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}

@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}

/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}

.token.punctuation {
color: #999;
}

.token.namespace {
opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}

.token.function,
.token.class-name {
color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
color: #e90;
}

.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}

+ 6
- 0
public/self/js/notebook/ansi_up.min.js View File

@@ -0,0 +1,6 @@
// ansi_up.js
// version : 1.1.0
// author : Dru Nelson
// license : MIT
// http://github.com/drudru/ansi_up
(function(a,b){function g(){this.fg=this.bg=null,this.bright=0}var c,d="1.1.0",e=typeof module!="undefined",f=[[{color:"0, 0, 0","class":"ansi-black"},{color:"187, 0, 0","class":"ansi-red"},{color:"0, 187, 0","class":"ansi-green"},{color:"187, 187, 0","class":"ansi-yellow"},{color:"0, 0, 187","class":"ansi-blue"},{color:"187, 0, 187","class":"ansi-magenta"},{color:"0, 187, 187","class":"ansi-cyan"},{color:"255,255,255","class":"ansi-white"}],[{color:"85, 85, 85","class":"ansi-bright-black"},{color:"255, 85, 85","class":"ansi-bright-red"},{color:"0, 255, 0","class":"ansi-bright-green"},{color:"255, 255, 85","class":"ansi-bright-yellow"},{color:"85, 85, 255","class":"ansi-bright-blue"},{color:"255, 85, 255","class":"ansi-bright-magenta"},{color:"85, 255, 255","class":"ansi-bright-cyan"},{color:"255, 255, 255","class":"ansi-bright-white"}]];g.prototype.escape_for_html=function(a){return a.replace(/[&<>]/gm,function(a){if(a=="&")return"&amp;";if(a=="<")return"&lt;";if(a==">")return"&gt;"})},g.prototype.linkify=function(a){return a.replace(/(https?:\/\/[^\s]+)/gm,function(a){return'<a href="'+a+'">'+a+"</a>"})},g.prototype.ansi_to_html=function(a,b){var c=a.split(/\033\[/),d=c.shift(),e=this,f=c.map(function(a){return e.process_chunk(a,b)});f.unshift(d);var g=f.reduce(function(a,b){return Array.isArray(b)?a.concat(b):(a.push(b),a)},[]),h=g.join("");return h},g.prototype.process_chunk=function(a,b){b=typeof b=="undefined"?{}:b;var c=typeof b.use_classes!="undefined"&&b.use_classes,d=c?"class":"color",e=a.match(/([\d;]*)m([^]*)/m);if(!e)return a;var g=e[2],h=e[1].split(";"),i=this;h.map(function(a){var b=parseInt(a);isNaN(b)||b===0?(i.fg=i.bg=null,i.bright=0):b===1?i.bright=1:b>=30&&b<38?i.fg=f[i.bright][b%10][d]:b>=40&&b<48&&(i.bg=f[0][b%10][d])});if(i.fg===null&&i.bg===null)return g;var j=classes=[];return i.fg&&(c?classes.push(i.fg+"-fg"):j.push("color:rgb("+i.fg+")")),i.bg&&(c?classes.push(i.bg+"-bg"):j.push("background-color:rgb("+i.bg+")")),c?['<span class="'+classes.join(" ")+'">',g,"</span>"]:['<span style="'+j.join(";")+'">',g,"</span>"]},c={escape_for_html:function(a){var b=new g;return b.escape_for_html(a)},linkify:function(a){var b=new g;return b.linkify(a)},ansi_to_html:function(a,b){var c=new g;return c.ansi_to_html(a,b)},ansi_to_html_obj:function(){return new g}},e&&(module.exports=c),typeof window!="undefined"&&typeof ender=="undefined"&&(window.ansi_up=c),typeof define=="function"&&define.amd&&define("ansi_up",[],function(){return c})})(Date);

+ 7
- 0
public/self/js/notebook/es5-shim.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
public/self/js/notebook/katex-auto-render.min.js View File

@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),a=function(e,t,r){for(var n=r,o=0,a=e.length;n<t.length;){var i=t[n];if(o<=0&&t.slice(n,n+a)===e)return n;"\\"===i?n++:"{"===i?o++:"}"===i&&o--,n++}return-1},i=function(e,t,r,n){for(var o=[],i=0;i<e.length;i++)if("text"===e[i].type){var l=e[i].data,d=!0,s=0,f=void 0;for(-1!==(f=l.indexOf(t))&&(s=f,o.push({type:"text",data:l.slice(0,s)}),d=!1);;){if(d){if(-1===(f=l.indexOf(t,s)))break;o.push({type:"text",data:l.slice(s,f)}),s=f}else{if(-1===(f=a(r,l,s+t.length)))break;o.push({type:"math",data:l.slice(s+t.length,f),rawData:l.slice(s,f+r.length),display:n}),s=f+r.length}d=!d}o.push({type:"text",data:l.slice(s)})}else o.push(e[i]);return o},l=function(e,t){var r=function(e,t){for(var r=[{type:"text",data:e}],n=0;n<t.length;n++){var o=t[n];r=i(r,o.left,o.right,o.display||!1)}return r}(e,t.delimiters);if(1===r.length&&"text"===r[0].type)return null;for(var n=document.createDocumentFragment(),a=0;a<r.length;a++)if("text"===r[a].type)n.appendChild(document.createTextNode(r[a].data));else{var l=document.createElement("span"),d=r[a].data;t.displayMode=r[a].display;try{t.preProcess&&(d=t.preProcess(d)),o.a.render(d,l,t)}catch(e){if(!(e instanceof o.a.ParseError))throw e;t.errorCallback("KaTeX auto-render: Failed to parse `"+r[a].data+"` with ",e),n.appendChild(document.createTextNode(r[a].rawData));continue}n.appendChild(l)}return n};t.default=function(e,t){if(!e)throw new Error("No element provided to render");var r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},function e(t,r){for(var n=0;n<t.childNodes.length;n++){var o=t.childNodes[n];if(3===o.nodeType){var a=l(o.textContent,r);a&&(n+=a.childNodes.length-1,t.replaceChild(a,o))}else 1===o.nodeType&&function(){var t=" "+o.className+" ";-1===r.ignoredTags.indexOf(o.nodeName.toLowerCase())&&r.ignoredClasses.every(function(e){return-1===t.indexOf(" "+e+" ")})&&e(o,r)}()}}(e,r)}}]).default});

+ 1
- 0
public/self/js/notebook/katex.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
public/self/js/notebook/marked.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
public/self/js/notebook/notebook.min.js
File diff suppressed because it is too large
View File


+ 7
- 0
public/self/js/notebook/prism.min.js
File diff suppressed because it is too large
View File


+ 3
- 0
public/self/js/notebook/purify.min.js
File diff suppressed because it is too large
View File


+ 4
- 0
routers/admin/dataset.go View File

@@ -61,6 +61,10 @@ func Datasets(ctx *context.Context) {
orderBy = models.SearchOrderByForksReverse
case "fewestforks":
orderBy = models.SearchOrderByForks
case "mostusecount":
orderBy = models.SearchOrderByUseCountReverse
case "fewestusecount":
orderBy = models.SearchOrderByUseCount
default:
ctx.Data["SortType"] = "recentupdate"
orderBy = models.SearchOrderByRecentUpdated


+ 13
- 0
routers/api/v1/api.go View File

@@ -573,7 +573,19 @@ func RegisterRoutes(m *macaron.Macaron) {
//cloudbrain board
m.Group("/cloudbrainboard", func() {
m.Get("/downloadAll", repo.DownloadCloudBrainBoard)
m.Group("/cloudbrain", func() {
m.Get("/overview", repo.GetAllCloudbrainsOverview)
m.Get("/distribution", repo.GetAllCloudbrainsPeriodDistribution)
m.Get("/trend", repo.GetAllCloudbrainsTrend)
m.Get("/trend_detail_data", repo.GetAllCloudbrainsTrendDetail)
m.Get("/status_analysis", repo.GetCloudbrainsStatusAnalysis)
m.Get("/detail_data", repo.GetCloudbrainsDetailData)
m.Get("/hours_data", repo.GetCloudbrainsCreateHoursData)
m.Get("/waitting_top_data", repo.GetWaittingTop)
m.Get("/running_top_data", repo.GetRunningTop)
})
}, operationReq)

// Users
m.Group("/users", func() {
m.Get("/search", user.Search)
@@ -922,6 +934,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/del_version", repo.DelTrainJobVersion)
m.Post("/stop_version", repo.StopTrainJobVersion)
m.Get("/model_list", repo.ModelList)
m.Get("/metric_statistics", repo.TrainJobGetMetricStatistic)
})
})
m.Group("/inference-job", func() {


+ 1257
- 16
routers/api/v1/repo/cloudbrain_dashboard.go View File

@@ -1,8 +1,10 @@
package repo

import (
"fmt"
"net/http"
"net/url"
"strings"
"time"

"code.gitea.io/gitea/models"
@@ -11,6 +13,1142 @@ import (
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

type DateCloudbrainNum struct {
Date string `json:"date"`
CloudOneJobTypeRes map[string]int `json:"cloudOneJobTypeRes"`
CloudTwoJobTypeRes map[string]int `json:"cloudTwoJobTypeRes"`
IntelligentNetJobTypeRes map[string]int `json:"intelligentNetJobTypeRes"`
CloudBrainPeriodNum map[int]int `json:"cloudBrainPeriodNum"`
CloudBrainComputeResource map[string]int `json:"cloudBrainComputeResource"`
}
type DateCloudbrainInfo struct {
Date string `json:"date"`
CloudBrainPeriodNum map[int]int `json:"cloudBrainPeriodNum"`
CloudBrainComputeResource map[string]int `json:"cloudBrainComputeResource"`
}
type CloudbrainsStatusAnalysis struct {
JobWaitingCount int64 `json:"jobWaitingCount"`
JobRunningCount int64 `json:"jobRunningCount"`
JobStoppedCount int64 `json:"jobStoppedCount"`
JobCompletedCount int64 `json:"jobCompletedCount"`
JobFailedCount int64 `json:"jobFailedCount"`
JobKilledCount int64 `json:"jobKilledCount"`
JobInitCount int64 `json:"jobInitCount"`
}

func GetAllCloudbrainsOverview(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
now := time.Now()
beginTime := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endTime := now
todayCreatorCount, err := models.GetTodayCreatorCount(beginTime, endTime)
if err != nil {
log.Error("Can not query todayCreatorCount.", err)
return
}
creatorCount, err := models.GetCreatorCount()
if err != nil {
log.Error("Can not query creatorCount.", err)
return
}
todayStatusResult := make(map[string]int)
cloudBrainNum := make(map[int]int)
cloudBrainOneDuration := int64(0)
cloudBrainTwoDuration := int64(0)
intelligentNetDuration := int64(0)
todayNewJobCount := 0
page := 1
pagesize := 1000
count := pagesize
for count == pagesize && count != 0 {
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pagesize,
},
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
ctx.ServerError("Get cloudbrains failed:", err)
return
}

for _, cloudbrain := range cloudbrains {
if int64(cloudbrain.Cloudbrain.CreatedUnix) >= beginTime.Unix() && int64(cloudbrain.Cloudbrain.CreatedUnix) < endTime.Unix() {
todayNewJobCount += 1
if _, ok := todayStatusResult[cloudbrain.Status]; !ok {
todayStatusResult[cloudbrain.Status] = 1
} else {
todayStatusResult[cloudbrain.Status] += 1
}
}

if _, ok := cloudBrainNum[cloudbrain.Cloudbrain.Type]; !ok {
cloudBrainNum[cloudbrain.Cloudbrain.Type] = 1
} else {
cloudBrainNum[cloudbrain.Cloudbrain.Type] += 1
}

if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
cloudBrainOneDuration = cloudBrainOneDuration + cloudbrain.Cloudbrain.Duration
}
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
cloudBrainTwoDuration = cloudBrainTwoDuration + cloudbrain.Cloudbrain.Duration
}
if cloudbrain.Cloudbrain.Type == models.TypeIntelligentNet {
intelligentNetDuration = intelligentNetDuration + cloudbrain.Cloudbrain.Duration
}

}
count = len(cloudbrains)
page += 1
}

statusNameList := []string{string(models.ModelArtsTrainJobCompleted), string(models.JobFailed), string(models.ModelArtsTrainJobInit),
string(models.JobRunning), string(models.ModelArtsStartFailed), string(models.JobStopped), string(models.JobSucceeded),
string(models.JobWaiting), string(models.ModelArtsTrainJobKilled)}
for _, v := range statusNameList {
if _, ok := todayStatusResult[v]; !ok {
todayStatusResult[v] = 0
}
}

todayRunningCount := todayStatusResult[string(models.JobRunning)]
todayCompletedCount := todayStatusResult[string(models.ModelArtsTrainJobCompleted)] + todayStatusResult[string(models.JobFailed)] +
todayStatusResult[string(models.ModelArtsStartFailed)] + todayStatusResult[string(models.JobStopped)] + todayStatusResult[string(models.JobSucceeded)] + todayStatusResult[string(models.ModelArtsTrainJobKilled)]
todayWaitingCount := todayStatusResult[string(models.ModelArtsTrainJobInit)] + todayStatusResult[string(models.JobWaiting)]

ctx.JSON(http.StatusOK, map[string]interface{}{
"recordBeginTime": recordBeginTime,
"updateTime": now.Unix(),
"cloudBrainNum": cloudBrainNum,
"cloudBrainOneDuration": cloudBrainOneDuration,
"cloudBrainTwoDuration": cloudBrainTwoDuration,
"intelligentNetDuration": intelligentNetDuration,
"todayCreatorCount": todayCreatorCount,
"creatorCount": creatorCount,
"todayRunningCount": todayRunningCount,
"todayCompletedCount": todayCompletedCount,
"todayWaitingCount": todayWaitingCount,
"todayNewJobCount": todayNewJobCount,
})
}

func GetAllCloudbrainsTrend(ctx *context.Context) {

queryType := ctx.QueryTrim("type")
now := time.Now()

beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var beginTime time.Time
var endTime time.Time
dateCloudbrainNum := make([]DateCloudbrainNum, 0)
var err error
if queryType != "" {
if queryType == "all" {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
brainRecordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix.AsTime()
beginTime = brainRecordBeginTime
endTime = now
dateCloudbrainNum, err = getMonthCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getMonthCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getMonthCloudbrainNum_get_error"))
return
}
} else if queryType == "today" {
beginTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// endTimeTemp = now
endTime = beginTime.AddDate(0, 0, 1)
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
} else if queryType == "yesterday" {
beginTime = now.AddDate(0, 0, -1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
} else if queryType == "last_7day" {
beginTime = now.AddDate(0, 0, -6)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
} else if queryType == "last_30day" {
beginTime = now.AddDate(0, 0, -29)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
} else if queryType == "current_month" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), 1, 0, 0, 0, 0, now.Location())
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
} else if queryType == "current_year" {
endTime = now
beginTime = time.Date(endTime.Year(), 1, 1, 0, 0, 0, 0, now.Location())
// endTimeTemp = beginTime.AddDate(0, 1, 0)
dateCloudbrainNum, err = getMonthCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getMonthCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getMonthCloudbrainNum_get_error"))
return
}
} else if queryType == "last_month" {

lastMonthTime := now.AddDate(0, -1, 0)
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 1, 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
}

} else {
if beginTimeStr == "" || endTimeStr == "" {
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
brainRecordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix.AsTime()
beginTime = brainRecordBeginTime
endTime = now
dateCloudbrainNum, err = getMonthCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getMonthCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getMonthCloudbrainNum_get_error"))
return
}
} else {
beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
if endTime.After(time.Now()) {
endTime = time.Now()
}
dateCloudbrainNum, err = getDayCloudbrainNum(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainNum.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainNum_get_error"))
return
}
}

}
ctx.JSON(http.StatusOK, map[string]interface{}{
"timeCloudbrainNum": dateCloudbrainNum,
})

}
func GetAllCloudbrainsTrendDetail(ctx *context.Context) {
queryType := ctx.QueryTrim("type")
now := time.Now()

beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var beginTime time.Time
var endTime time.Time
var endTimeTemp time.Time
dayCloudbrainInfo := make([]DateCloudbrainInfo, 0)
var err error
var count int
if queryType != "" {
if queryType == "all" {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
brainRecordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix.AsTime()
beginTime = brainRecordBeginTime
endTime = now
dayCloudbrainInfo, count, err = getMonthCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}
} else if queryType == "today" {
beginTime = now.AddDate(0, 0, 0)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}

} else if queryType == "yesterday" {
beginTime = now.AddDate(0, 0, -1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}

} else if queryType == "last_7day" {
beginTime = now.AddDate(0, 0, -6)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
endTimeTemp = time.Date(endTimeTemp.Year(), endTimeTemp.Month(), endTimeTemp.Day(), 0, 0, 0, 0, now.Location())
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}
} else if queryType == "last_30day" {
beginTime = now.AddDate(0, 0, -29)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}
} else if queryType == "current_month" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), 1, 0, 0, 0, 0, now.Location())
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}

} else if queryType == "current_year" {
endTime = now
beginTime = time.Date(endTime.Year(), 1, 1, 0, 0, 0, 0, now.Location())
dayCloudbrainInfo, count, err = getMonthCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}

} else if queryType == "last_month" {

lastMonthTime := now.AddDate(0, -1, 0)
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 1, 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}

}

} else {
if beginTimeStr == "" || endTimeStr == "" {
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
brainRecordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix.AsTime()
beginTime = brainRecordBeginTime
endTime = now
dayCloudbrainInfo, count, err = getMonthCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}
} else {
beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
if endTime.After(time.Now()) {
endTime = time.Now()
}
endTimeTemp = beginTime.AddDate(0, 0, 1)
dayCloudbrainInfo, count, err = getDayCloudbrainInfo(beginTime, endTime)
if err != nil {
log.Error("Can not query getDayCloudbrainInfo.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("getDayCloudbrainInfo_get_error"))
return
}
}

}

page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pagesize := ctx.QueryInt("pagesize")
if pagesize <= 0 {
pagesize = 5
}
pageDateCloudbrainInfo := getPageDateCloudbrainInfo(dayCloudbrainInfo, page, pagesize)

ctx.JSON(http.StatusOK, map[string]interface{}{
"totalCount": count,
"timeCloudbrainInfo": pageDateCloudbrainInfo,
})

}
func getPageDateCloudbrainInfo(dateCloudbrainInfo []DateCloudbrainInfo, page int, pagesize int) []DateCloudbrainInfo {
begin := (page - 1) * pagesize
end := (page) * pagesize

if begin > len(dateCloudbrainInfo)-1 {
return nil
}
if end > len(dateCloudbrainInfo)-1 {
return dateCloudbrainInfo[begin:]
} else {
return dateCloudbrainInfo[begin:end]
}

}

func GetAllCloudbrainsPeriodDistribution(ctx *context.Context) {
queryType := ctx.QueryTrim("type")
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
recordBeginTime := time.Unix(int64(recordCloudbrain[0].Cloudbrain.CreatedUnix), 0)
beginTime, endTime, err := getCloudbrainTimePeroid(ctx, recordBeginTime)
if err != nil {
log.Error("Parameter is wrong", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
return
}
cloudOneJobTypeRes := make(map[string]int)
cloudTwoJobTypeRes := make(map[string]int)
intelligentNetJobTypeRes := make(map[string]int)
cloudBrainPeriodNum := make(map[int]int)
cloudBrainComputeResource := make(map[string]int)
beginTimeTemp := beginTime.Unix()
if queryType == "all" || (queryType == "" && (beginTimeStr == "" || endTimeStr == "")) {
beginTimeTemp = int64(recordCloudbrain[0].Cloudbrain.CreatedUnix)
}

page := 1
pagesize := 1000
count := pagesize
//Each time a maximum of 1000 pieces of data are detected to the memory, batch processing
for count == pagesize && count != 0 {
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pagesize,
},
Type: models.TypeCloudBrainAll,
BeginTimeUnix: beginTimeTemp,
EndTimeUnix: endTime.Unix(),
})
if err != nil {
ctx.ServerError("Get cloudbrains failed:", err)
return
}

for _, cloudbrain := range cloudbrains {
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
if _, ok := cloudOneJobTypeRes[cloudbrain.JobType]; !ok {
cloudOneJobTypeRes[cloudbrain.JobType] = 1
} else {
cloudOneJobTypeRes[cloudbrain.JobType] += 1
}
}
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
if _, ok := cloudTwoJobTypeRes[cloudbrain.JobType]; !ok {
cloudTwoJobTypeRes[cloudbrain.JobType] = 1
} else {
cloudTwoJobTypeRes[cloudbrain.JobType] += 1
}
}
if cloudbrain.Cloudbrain.Type == models.TypeIntelligentNet {
if _, ok := intelligentNetJobTypeRes[cloudbrain.JobType]; !ok {
intelligentNetJobTypeRes[cloudbrain.JobType] = 1
} else {
intelligentNetJobTypeRes[cloudbrain.JobType] += 1
}
}

if _, ok := cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type]; !ok {
cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type] = 1
} else {
cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type] += 1
}

if _, ok := cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource]; !ok {
cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource] = 1
} else {
cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource] += 1
}
}
count = len(cloudbrains)
page += 1
}

jobTypeList := []string{string(models.JobTypeDebug), string(models.JobTypeTrain), string(models.JobTypeInference), string(models.JobTypeBenchmark),
string(models.JobTypeBrainScore), string(models.JobTypeSnn4imagenet)}
for _, v := range jobTypeList {
if _, ok := cloudOneJobTypeRes[v]; !ok {
cloudOneJobTypeRes[v] = 0
}
if _, ok := cloudTwoJobTypeRes[v]; !ok {
cloudTwoJobTypeRes[v] = 0
}
if _, ok := intelligentNetJobTypeRes[v]; !ok {
intelligentNetJobTypeRes[v] = 0
}
}
cloudBrainTypeList := []int{0, 1, 2}
for _, v := range cloudBrainTypeList {
if _, ok := cloudBrainPeriodNum[v]; !ok {
cloudBrainPeriodNum[v] = 0
}
}

ComputeResourceList := []string{"CPU/GPU", "NPU"}
for _, v := range ComputeResourceList {
if _, ok := cloudBrainComputeResource[v]; !ok {
cloudBrainComputeResource[v] = 0
}
}

cloudOneJobTypeRes["EVALUATION"] = cloudOneJobTypeRes[string(models.JobTypeBenchmark)] + cloudOneJobTypeRes[string(models.JobTypeSnn4imagenet)] + cloudOneJobTypeRes[string(models.JobTypeBrainScore)]
cloudTwoJobTypeRes["EVALUATION"] = cloudTwoJobTypeRes[string(models.JobTypeBenchmark)] + cloudTwoJobTypeRes[string(models.JobTypeSnn4imagenet)] + cloudTwoJobTypeRes[string(models.JobTypeBrainScore)]
intelligentNetJobTypeRes["EVALUATION"] = intelligentNetJobTypeRes[string(models.JobTypeBenchmark)] + intelligentNetJobTypeRes[string(models.JobTypeSnn4imagenet)] + intelligentNetJobTypeRes[string(models.JobTypeBrainScore)]
ctx.JSON(http.StatusOK, map[string]interface{}{
"cloudOneJobTypeRes": cloudOneJobTypeRes,
"cloudTwoJobTypeRes": cloudTwoJobTypeRes,
"intelligentNetJobTypeRes": intelligentNetJobTypeRes,
"cloudBrainPeriodNum": cloudBrainPeriodNum,
"cloudBrainComputeResource": cloudBrainComputeResource,
})
}

func GetCloudbrainsStatusAnalysis(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
endTime := time.Now()
cloudBrainStatusResult := make(map[string]int)
cloudBrainStatusAnalysis := make(map[string]int)
totalCount := 0

page := 1
pagesize := 1000
count := pagesize
for count == pagesize && count != 0 {
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pagesize,
},
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
ctx.ServerError("Get cloudbrains failed:", err)
return
}
for _, cloudbrain := range cloudbrains {
if _, ok := cloudBrainStatusResult[cloudbrain.Status]; !ok {
cloudBrainStatusResult[cloudbrain.Status] = 1
} else {
cloudBrainStatusResult[cloudbrain.Status] += 1
}
}
count = len(cloudbrains)
totalCount = totalCount + count
page += 1
}

var jobStatuses []string
jobStatuses = append(jobStatuses, string(models.ModelArtsTrainJobWaiting), string(models.ModelArtsTrainJobFailed), string(models.ModelArtsRunning), string(models.ModelArtsTrainJobCompleted),
string(models.ModelArtsStarting), string(models.ModelArtsRestarting), string(models.ModelArtsStartFailed),
string(models.ModelArtsStopping), string(models.ModelArtsStopped), string(models.JobSucceeded))
jobStatusesCount := 0
for _, v := range jobStatuses {
if _, ok := cloudBrainStatusResult[v]; !ok {
cloudBrainStatusAnalysis[v] = 0
} else {
cloudBrainStatusAnalysis[v] = cloudBrainStatusResult[v]
}
jobStatusesCount = jobStatusesCount + cloudBrainStatusResult[v]
}
cloudBrainStatusAnalysis["OTHER"] = totalCount - jobStatusesCount

ctx.JSON(http.StatusOK, map[string]interface{}{
"cloudBrainStatusResult": cloudBrainStatusAnalysis,
})
}

func GetCloudbrainsDetailData(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
endTime := time.Now()
listType := ctx.Query("listType")
jobType := ctx.Query("jobType")
jobStatus := ctx.Query("jobStatus")
cloudBrainType := ctx.QueryInt("Type")

page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pagesize")
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
var jobTypes []string
jobTypeNot := false
if jobType == string(models.JobTypeBenchmark) {
jobTypes = append(jobTypes, string(models.JobTypeBenchmark), string(models.JobTypeBrainScore), string(models.JobTypeSnn4imagenet))
} else if jobType != "all" && jobType != "" {
jobTypes = append(jobTypes, jobType)
}

var jobStatuses []string
jobStatusNot := false
if jobStatus == "other" {
jobStatusNot = true
jobStatuses = append(jobStatuses, string(models.ModelArtsTrainJobWaiting), string(models.ModelArtsTrainJobFailed), string(models.ModelArtsRunning), string(models.ModelArtsTrainJobCompleted),
string(models.ModelArtsStarting), string(models.ModelArtsRestarting), string(models.ModelArtsStartFailed),
string(models.ModelArtsStopping), string(models.ModelArtsStopped), string(models.JobSucceeded))
} else if jobStatus != "all" && jobStatus != "" {
jobStatuses = append(jobStatuses, jobStatus)
}

keyword := strings.Trim(ctx.Query("q"), " ")

ciTasks, count, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
},
Keyword: keyword,
Type: cloudBrainType,
ComputeResource: listType,
JobTypeNot: jobTypeNot,
JobStatusNot: jobStatusNot,
JobStatus: jobStatuses,
JobTypes: jobTypes,
NeedRepoInfo: true,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
ctx.ServerError("Get job failed:", err)
return
}
nilTime := time.Time{}
tasks := []models.TaskDetail{}
for i, task := range ciTasks {
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource

var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
taskDetail.JobType = ciTasks[i].JobType
taskDetail.CreatedUnix = ciTasks[i].Cloudbrain.CreatedUnix
taskDetail.RunTime = ciTasks[i].Cloudbrain.TrainJobDuration
taskDetail.StartTime = ciTasks[i].StartTime
taskDetail.EndTime = ciTasks[i].EndTime
taskDetail.ComputeResource = ciTasks[i].ComputeResource
taskDetail.Type = ciTasks[i].Cloudbrain.Type
taskDetail.UserName = ciTasks[i].User.Name
taskDetail.RepoID = ciTasks[i].RepoID
if ciTasks[i].Repo != nil {
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) {
WaitTimeInt := time.Now().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"
}
}

if ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainTwo || (ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainOne && ciTasks[i].Cloudbrain.JobType == "TRAIN") {
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
}

if ciTasks[i].Cloudbrain.DeletedAt != nilTime {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
}
tasks = append(tasks, taskDetail)
}

pager := context.NewPagination(int(count), pageSize, page, getTotalPage(count, pageSize))
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "listType", "ListType")

ctx.JSON(http.StatusOK, map[string]interface{}{
"Title": ctx.Tr("kanban.cloudBrains"),
"Tasks": tasks,
"Keyword": keyword,
"pager": pager,
"count": count,
})
}

func GetCloudbrainsCreateHoursData(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
recordBeginTime := time.Unix(int64(recordCloudbrain[0].Cloudbrain.CreatedUnix), 0)
// recordBeginTime, _ := time.Parse("2006-01-02 15:04:05", recordTime)
now := time.Now()
queryType := ctx.QueryTrim("type")
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var beginTime time.Time
var endTime time.Time
createHourPeriodCount := make(map[string]interface{})
if queryType != "" {
if queryType == "all" {
beginTime = recordBeginTime
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "today" {
beginTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endTime = now.AddDate(0, 0, 1)
} else if queryType == "yesterday" {
beginTime = now.AddDate(0, 0, -1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "current_week" {
beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+1) //begin from monday
endTime = now
} else if queryType == "current_month" {
beginTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "monthly" {
endTime = now
beginTime = now.AddDate(0, -1, 0)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "current_year" {
beginTime = time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "last_month" {
lastMonthTime := now.AddDate(0, -1, 0)
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 1, 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
} else if queryType == "last_7day" {
beginTime = now.AddDate(0, 0, -6)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "last_30day" {
beginTime = now.AddDate(0, 0, -29)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
}
} else {
if beginTimeStr == "" || endTimeStr == "" {
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理
beginTime = recordBeginTime
endTime = now.AddDate(0, 0, 1)
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else {
beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
if err != nil {
log.Error("Can not ParseInLocation.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("ParseInLocation_get_error"))
return
}
endTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
}
}
dateBeginTime := beginTime.Format("2006-01-02")
dateEndTime := endTime.Format("2006-01-02")
createHourPeriodCount, err = models.GetCreateHourPeriodCount(dateBeginTime, dateEndTime)
if err != nil {
log.Error("Can not query hourPeriodCount.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("hourPeriodCount_get_error"))
return
}

runHourPeriodCount, err := models.GetRunHourPeriodCount(dateBeginTime, dateEndTime)
if err != nil {
log.Error("Can not query runHourPeriodCount.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("runHourPeriodCount_get_error"))
return
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"recordBeginTime": recordCloudbrain[0].Cloudbrain.CreatedUnix,
"updateTime": now.Unix(),
"createHourPeriodCount": createHourPeriodCount,
"runHourPeriodCount": runHourPeriodCount,
})

}
func GetWaittingTop(ctx *context.Context) {
ciTasks, err := models.GetWaittingTop()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
tasks := []models.TaskDetail{}
for i, task := range ciTasks {
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource

var taskDetail models.TaskDetail
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.UserName = ciTasks[i].User.Name
taskDetail.RepoID = ciTasks[i].RepoID
if ciTasks[i].Repo != nil {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
}
WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)

if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}
tasks = append(tasks, taskDetail)
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"tasks": tasks,
})
}
func GetRunningTop(ctx *context.Context) {
ciTasks, err := models.GetRunningTop()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
tasks := []models.TaskDetail{}
for i, task := range ciTasks {
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource

var taskDetail models.TaskDetail
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.RunTime = ciTasks[i].Cloudbrain.TrainJobDuration
taskDetail.UserName = ciTasks[i].User.Name
taskDetail.RepoID = ciTasks[i].RepoID
if ciTasks[i].Repo != nil {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
}

tasks = append(tasks, taskDetail)
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"tasks": tasks,
})
}

func getCloudbrainCount(beginTime time.Time, endTime time.Time, cloudbrains []*models.CloudbrainInfo) (map[string]int, map[string]int, map[string]int, map[int]int, map[string]int) {

cloudOneJobTypeRes := make(map[string]int)
cloudTwoJobTypeRes := make(map[string]int)
intelligentNetJobTypeRes := make(map[string]int)
cloudBrainPeriodNum := make(map[int]int)
cloudBrainComputeResource := make(map[string]int)
for _, cloudbrain := range cloudbrains {
if int64(cloudbrain.Cloudbrain.CreatedUnix) >= beginTime.Unix() && int64(cloudbrain.Cloudbrain.CreatedUnix) < endTime.Unix() {
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
if _, ok := cloudOneJobTypeRes[cloudbrain.Cloudbrain.JobType]; !ok {
cloudOneJobTypeRes[cloudbrain.Cloudbrain.JobType] = 1
} else {
cloudOneJobTypeRes[cloudbrain.Cloudbrain.JobType] += 1
}
}
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
if _, ok := cloudTwoJobTypeRes[cloudbrain.JobType]; !ok {
cloudTwoJobTypeRes[cloudbrain.Cloudbrain.JobType] = 1
} else {
cloudTwoJobTypeRes[cloudbrain.Cloudbrain.JobType] += 1
}
}

if _, ok := cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type]; !ok {
cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type] = 1
} else {
cloudBrainPeriodNum[cloudbrain.Cloudbrain.Type] += 1
}

if _, ok := cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource]; !ok {
cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource] = 1
} else {
cloudBrainComputeResource[cloudbrain.Cloudbrain.ComputeResource] += 1
}

}
}

ComputeResourceList := []string{"CPU/GPU", "NPU"}
for _, v := range ComputeResourceList {
if _, ok := cloudBrainComputeResource[v]; !ok {
cloudBrainComputeResource[v] = 0
}
}

jobTypeList := []string{"DEBUG", "BENCHMARK", "INFERENCE", "TRAIN", "SNN4IMAGENET", "BRAINSCORE"}
cloudBrainTypeList := []int{0, 1, 2}
for _, v := range jobTypeList {
if _, ok := cloudOneJobTypeRes[v]; !ok {
cloudOneJobTypeRes[v] = 0
}
if _, ok := cloudTwoJobTypeRes[v]; !ok {
cloudTwoJobTypeRes[v] = 0
}
if _, ok := intelligentNetJobTypeRes[v]; !ok {
intelligentNetJobTypeRes[v] = 0
}
}
for _, v := range cloudBrainTypeList {
if _, ok := cloudBrainPeriodNum[v]; !ok {
cloudBrainPeriodNum[v] = 0
}
}
cloudBrainPeriodNum[-1] = cloudBrainPeriodNum[0] + cloudBrainPeriodNum[1] + cloudBrainPeriodNum[2]
return cloudOneJobTypeRes, cloudTwoJobTypeRes, intelligentNetJobTypeRes, cloudBrainPeriodNum, cloudBrainComputeResource
}

func getDayCloudbrainNum(beginTime time.Time, endTime time.Time) ([]DateCloudbrainNum, error) {
var endTimeTemp time.Time
endTimeTemp = beginTime.AddDate(0, 0, 1)
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
Type: models.TypeCloudBrainAll,
BeginTimeUnix: beginTime.Unix(),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
log.Error("Get cloudbrains failed:", err)
return nil, err
}
dayCloudbrainNum := make([]DateCloudbrainNum, 0)
for endTimeTemp.Before(endTime) || endTimeTemp.Equal(endTime) {
cloudOneJobTypeRes, cloudTwoJobTypeRes, intelligentNetJobTypeRes, cloudBrainPeriodNum, cloudBrainComputeResource := getCloudbrainCount(beginTime, endTimeTemp, cloudbrains)
dayCloudbrainNum = append(dayCloudbrainNum, DateCloudbrainNum{
Date: beginTime.Format("2006/01/02"),
CloudOneJobTypeRes: cloudOneJobTypeRes,
CloudTwoJobTypeRes: cloudTwoJobTypeRes,
IntelligentNetJobTypeRes: intelligentNetJobTypeRes,
CloudBrainPeriodNum: cloudBrainPeriodNum,
CloudBrainComputeResource: cloudBrainComputeResource,
})
if endTime.Before(endTimeTemp.AddDate(0, 0, 1)) && endTimeTemp.Before(endTime) {
beginTime = endTimeTemp
endTimeTemp = endTime
} else {
beginTime = endTimeTemp
endTimeTemp = beginTime.AddDate(0, 0, 1)
}
}
return dayCloudbrainNum, nil
}
func getMonthCloudbrainNum(beginTime time.Time, endTime time.Time) ([]DateCloudbrainNum, error) {
var endTimeTemp time.Time
now := time.Now()
endTimeTemp = beginTime.AddDate(0, 1, 0)
endTimeTemp = time.Date(endTimeTemp.Year(), endTimeTemp.Month(), 1, 0, 0, 0, 0, now.Location())
monthCloudbrainNum := make([]DateCloudbrainNum, 0)
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
Type: models.TypeCloudBrainAll,
BeginTimeUnix: beginTime.Unix(),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
log.Error("Getcloudbrains failed:%v", err)
return nil, err
}
for endTimeTemp.Before(endTime) || endTimeTemp.Equal(endTime) {
cloudOneJobTypeRes, cloudTwoJobTypeRes, intelligentNetJobTypeRes, cloudBrainPeriodNum, cloudBrainComputeResource := getCloudbrainCount(beginTime, endTimeTemp, cloudbrains)
monthCloudbrainNum = append(monthCloudbrainNum, DateCloudbrainNum{
Date: beginTime.Format("2006/01"),
CloudOneJobTypeRes: cloudOneJobTypeRes,
CloudTwoJobTypeRes: cloudTwoJobTypeRes,
IntelligentNetJobTypeRes: intelligentNetJobTypeRes,
CloudBrainPeriodNum: cloudBrainPeriodNum,
CloudBrainComputeResource: cloudBrainComputeResource,
})
if endTime.Before(endTimeTemp.AddDate(0, 1, 0)) && endTimeTemp.Before(endTime) {
beginTime = endTimeTemp
endTimeTemp = endTime
} else {
beginTime = endTimeTemp
endTimeTemp = beginTime.AddDate(0, 1, 0)
}
}
return monthCloudbrainNum, nil
}

func getDayCloudbrainInfo(beginTime time.Time, endTime time.Time) ([]DateCloudbrainInfo, int, error) {
now := time.Now()
endTimeTemp := time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
if endTimeTemp.Equal(endTime) {
endTimeTemp = endTimeTemp.AddDate(0, 0, -1)
}
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
Type: models.TypeCloudBrainAll,
BeginTimeUnix: beginTime.Unix(),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
log.Error("Getcloudbrains failed:%v", err)
return nil, 0, err
}
dayCloudbrainInfo := make([]DateCloudbrainInfo, 0)
count := 0
for beginTime.Before(endTimeTemp) || beginTime.Equal(endTimeTemp) {
_, _, _, cloudBrainPeriodNum, cloudBrainComputeResource := getCloudbrainCount(endTimeTemp, endTime, cloudbrains)
dayCloudbrainInfo = append(dayCloudbrainInfo, DateCloudbrainInfo{
Date: endTimeTemp.Format("2006/01/02"),
CloudBrainPeriodNum: cloudBrainPeriodNum,
CloudBrainComputeResource: cloudBrainComputeResource,
})
endTime = endTimeTemp
endTimeTemp = endTimeTemp.AddDate(0, 0, -1)
count += 1
}
return dayCloudbrainInfo, count, nil
}

func getMonthCloudbrainInfo(beginTime time.Time, endTime time.Time) ([]DateCloudbrainInfo, int, error) {
now := time.Now()
endTimeTemp := time.Date(endTime.Year(), endTime.Month(), 1, 0, 0, 0, 0, now.Location())
if endTimeTemp.Equal(endTime) {
endTimeTemp = endTimeTemp.AddDate(0, -1, 0)
}
cloudbrains, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
Type: models.TypeCloudBrainAll,
BeginTimeUnix: beginTime.Unix(),
EndTimeUnix: endTime.Unix(),
})
if err != nil {
log.Error("Getcloudbrains failed:%v", err)
return nil, 0, err
}
dayCloudbrainInfo := make([]DateCloudbrainInfo, 0)
count := 0
for beginTime.Before(endTimeTemp) || beginTime.Equal(endTimeTemp) || (endTimeTemp.Before(beginTime) && beginTime.Before(endTime)) {
_, _, _, cloudBrainPeriodNum, cloudBrainComputeResource := getCloudbrainCount(endTimeTemp, endTime, cloudbrains)
dayCloudbrainInfo = append(dayCloudbrainInfo, DateCloudbrainInfo{
Date: endTimeTemp.Format("2006/01"),
CloudBrainPeriodNum: cloudBrainPeriodNum,
CloudBrainComputeResource: cloudBrainComputeResource,
})
endTime = endTimeTemp
endTimeTemp = endTimeTemp.AddDate(0, -1, 0)
count += 1
}
return dayCloudbrainInfo, count, nil
}

func DownloadCloudBrainBoard(ctx *context.Context) {

page := 1
@@ -34,9 +1172,7 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.cloudbrain_query_fail"))
return
}

totalPage := getTotalPage(total, pageSize)

f := excelize.NewFile()

index := f.NewSheet(cloudBrain)
@@ -79,26 +1215,27 @@ func DownloadCloudBrainBoard(ctx *context.Context) {

f.WriteTo(ctx.Resp)
}

func getCloudbrainFileName(baseName string) string {
return baseName + "_" + time.Now().Format(EXCEL_DATE_FORMAT) + ".xlsx"

}
func allCloudbrainHeader(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.wait_time"), "F1": ctx.Tr("repo.modelarts.train_job.dura_time"),
"G1": ctx.Tr("repo.modelarts.train_job.start_time"),
"H1": ctx.Tr("repo.modelarts.train_job.end_time"), "I1": ctx.Tr("repo.modelarts.computing_resources"),
"J1": ctx.Tr("repo.cloudbrain_creator"), "K1": ctx.Tr("repo.repo_name"), "L1": ctx.Tr("repo.cloudbrain_task_name")}
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")}

}
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): rs.JobType, getCellName("C", row): rs.Status,
getCellName("D", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("E", row): getBrainWaitTime(rs),
getCellName("F", row): rs.TrainJobDuration, getCellName("G", row): getBrainStartTime(rs),
getCellName("H", row): getBrainEndTime(rs),
getCellName("I", row): rs.ComputeResource, getCellName("J", row): rs.Name, getCellName("K", row): getBrainRepo(rs),
getCellName("L", row): rs.JobName,
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),
}
}
func getBrainRepo(rs *models.CloudbrainInfo) string {
@@ -126,10 +1263,114 @@ func getBrainEndTime(rs *models.CloudbrainInfo) string {

}
func getBrainWaitTime(rs *models.CloudbrainInfo) string {
waitTime := rs.Cloudbrain.StartTime - rs.Cloudbrain.CreatedUnix
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 "0"
return "00:00:00"
} else {
return models.ConvertDurationToStr(int64(waitTime))
return models.ConvertDurationToStr(waitTime)
}
}
func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string {
if rs.Cloudbrain.Type == models.TypeCloudBrainOne {
return ctx.Tr("repo.cloudbrain1")
} else if rs.Cloudbrain.Type == models.TypeCloudBrainTwo {
return ctx.Tr("repo.cloudbrain2")
} else if rs.Cloudbrain.Type == models.TypeIntelligentNet {
return ctx.Tr("repo.intelligent_net")
} else {
return ctx.Tr("repo.cloudbrain_untype")
}
}

func getBrainDeleteTime(rs *models.CloudbrainInfo) string {
nilTime := time.Time{}
if rs.Cloudbrain.DeletedAt != nilTime {
return rs.Cloudbrain.DeletedAt.Format("2006-01-02 15:04:05")
} else {
return ""
}
}
func getCloudbrainTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) {
queryType := ctx.QueryTrim("type")
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
now := time.Now()

var beginTime time.Time
var endTime time.Time
var err error
if queryType != "" {

if queryType == "all" {
beginTime = recordBeginTime
endTime = now
} else if queryType == "today" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "yesterday" {
endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
beginTime = endTime.AddDate(0, 0, -1)

} else if queryType == "last_7day" {
beginTime = now.AddDate(0, 0, -6)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
} else if queryType == "last_30day" {
beginTime = now.AddDate(0, 0, -29)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
} else if queryType == "current_month" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), 1, 0, 0, 0, 0, now.Location())
} else if queryType == "monthly" {
endTime = now
beginTime = now.AddDate(0, -1, 1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())

} else if queryType == "current_year" {
endTime = now
beginTime = time.Date(endTime.Year(), 1, 1, 0, 0, 0, 0, now.Location())

} else if queryType == "last_month" {

lastMonthTime := now.AddDate(0, -1, 0)
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 1, 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())

} else {
return now, now, fmt.Errorf("The value of type parameter is wrong.")

}

} else {
if beginTimeStr == "" || endTimeStr == "" {
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理
beginTime = recordBeginTime
endTime = now

} else {

beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
if err != nil {
return now, now, err
}

endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
if err != nil {
return now, now, err
}
}

}

if beginTime.Before(recordBeginTime) {
beginTime = recordBeginTime
}

return beginTime, endTime, nil
}

+ 43
- 0
routers/api/v1/repo/modelarts.go View File

@@ -462,3 +462,46 @@ func ResultList(ctx *context.APIContext) {
"PageIsCloudBrain": true,
})
}

func TrainJobGetMetricStatistic(ctx *context.APIContext) {
var (
err error
)

var jobID = ctx.Params(":jobid")
var versionName = ctx.Query("version_name")

result, err := trainJobGetMetricStatistic(jobID, versionName)
if err != nil {
log.Error("trainJobGetMetricStatistic(%s) failed:%v", jobID, err.Error())
return
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"Interval": result.Interval,
"MetricsInfo": result.MetricsInfo,
})
}

func trainJobGetMetricStatistic(jobID string, versionName string) (*models.GetTrainJobMetricStatisticResult, error) {
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName)
if err != nil {
log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", jobID, err.Error())
return nil, err
}

resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
log.Error("GetTrainJobLogFileNames(%s) failed:%v", jobID, err.Error())
return nil, err
}

result, err := modelarts.GetTrainJobMetricStatistic(jobID, strconv.FormatInt(task.VersionID, 10), resultLogFile.LogFileList[0])
if err != nil {
log.Error("GetTrainJobMetricStatistic(%s) failed:%v", jobID, err.Error())
return nil, err
}

return result, err
}

+ 11
- 7
routers/api/v1/repo/repo_dashbord.go View File

@@ -192,7 +192,6 @@ func GetProjectsSummaryData(ctx *context.Context) {

}


projectSummaryPeriodData := ProjectSummaryPeriodData{
TotalCount: count - 1,
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
@@ -203,7 +202,7 @@ func GetProjectsSummaryData(ctx *context.Context) {

}

func reverse(datas []*ProjectSummaryBaseData ) []*ProjectSummaryBaseData {
func reverse(datas []*ProjectSummaryBaseData) []*ProjectSummaryBaseData {
for i := 0; i < len(datas)/2; i++ {
j := len(datas) - i - 1
datas[i], datas[j] = datas[j], datas[i]
@@ -211,8 +210,6 @@ func reverse(datas []*ProjectSummaryBaseData ) []*ProjectSummaryBaseData {
return datas
}



func setStatisticsData(data *ProjectSummaryBaseData, v *models.SummaryStatistic, stats *models.SummaryStatistic) {
data.NumReposAdd = v.NumRepos - stats.NumRepos
data.NumRepoPublicAdd = v.NumRepoPublic - stats.NumRepoPublic
@@ -890,12 +887,19 @@ func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time,
if queryType == "all" {
beginTime = recordBeginTimeTemp
endTime = now
} else if queryType == "yesterday" {
} else if queryType == "today" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
} else if queryType == "yesterday" {
endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
beginTime = endTime.AddDate(0, 0, -1)

} else if queryType == "current_week" {
beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+2) //begin from monday
} else if queryType == "last_7day" {
beginTime = now.AddDate(0, 0, -7)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
} else if queryType == "last_30day" {
beginTime = now.AddDate(0, 0, -30)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
} else if queryType == "current_month" {


+ 44
- 0
routers/home.go View File

@@ -7,6 +7,7 @@ package routers

import (
"bytes"
"fmt"
"net/http"
"strconv"
"strings"
@@ -322,6 +323,10 @@ func ExploreDatasets(ctx *context.Context) {
orderBy = models.SearchOrderByStarsReverse
case "feweststars":
orderBy = models.SearchOrderByStars
case "mostusecount":
orderBy = models.SearchOrderByUseCountReverse
case "fewestusecount":
orderBy = models.SearchOrderByUseCount
case "default":
orderBy = models.SearchOrderByDefault
default:
@@ -338,6 +343,12 @@ func ExploreDatasets(ctx *context.Context) {
if ctx.User != nil && !ctx.User.IsAdmin {
ownerID = ctx.User.ID
}
var datasetsIds []int64
if ownerID > 0 {

datasetsIds = models.GetCollaboratorDatasetIdsByUserID(ownerID)
}

opts := &models.SearchDatasetOptions{
Keyword: keyword,
IncludePublic: true,
@@ -346,6 +357,7 @@ func ExploreDatasets(ctx *context.Context) {
Task: task,
License: license,
OwnerID: ownerID,
DatasetIDs: datasetsIds,
RecommendOnly: ctx.QueryBool("recommend"),
ListOptions: models.ListOptions{
Page: page,
@@ -746,6 +758,15 @@ func GetRankUser(index string) ([]map[string]interface{}, error) {
return resultOrg, nil
}

// func GetImageInfoFromPromote(ctx *context.Context) {
// imageInfo, err := GetImageInfo()
// if err != nil {
// ctx.ServerError("500", err)
// return
// }
// ctx.JSON(200, imageInfo)
// }

func GetUserRankFromPromote(ctx *context.Context) {
index := ctx.Params("index")
resultUserRank, err := GetRankUser(index)
@@ -769,13 +790,36 @@ func RecommendHomeInfo(ctx *context.Context) {
if err != nil {
log.Info("error." + err.Error())
}
resultCloudBrain, err := getCloudbrainNums()
if err != nil {
log.Info("error." + err.Error())
}
mapInterface := make(map[string]interface{})
mapInterface["org"] = resultOrg
mapInterface["repo"] = resultRepo
mapInterface["image"] = resultImage
mapInterface["cloudbrain"] = resultCloudBrain
ctx.JSON(http.StatusOK, mapInterface)
}

func getCloudbrainNums() (map[string]string, error) {
result := make(map[string]string)
cloudStatusMap := models.GetAllStatusCloudBrain()
result["completed_task"] = fmt.Sprint(cloudStatusMap["COMPLETED"])
result["running_task"] = fmt.Sprint(cloudStatusMap["RUNNING"])
result["wait_task"] = fmt.Sprint(cloudStatusMap["WAITING"])
return result, nil
}

// func RecommendOrgFromPromote(ctx *context.Context) {
// resultOrg, err := GetRecommendOrg()
// if err != nil {
// ctx.ServerError("500", err)
// return
// }
// ctx.JSON(200, resultOrg)
// }

func RecommendRepoFromPromote(ctx *context.Context) {
result, err := repository.GetRecommendRepoFromPromote("projects")
if err != nil {


+ 210
- 79
routers/repo/ai_model_manage.go View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"path"
"strings"

@@ -27,19 +28,22 @@ const (
MODEL_NOT_LATEST = 0
)

func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error {
func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error {
aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName)
if err != nil {
log.Info("query task error." + err.Error())
return err
aiTask, err = models.GetRepoCloudBrainByJobID(ctx.Repo.Repository.ID, jobId)
if err != nil {
log.Info("query task error." + err.Error())
return err
} else {
log.Info("query gpu train task.")
}
}

uuid := uuid.NewV4()
id := uuid.String()
modelPath := id
var lastNewModelId string
var modelSize int64
cloudType := models.TypeCloudBrainTwo

log.Info("find task name:" + aiTask.JobName)
aimodels := models.QueryModelByName(name, aiTask.RepoID)
@@ -53,7 +57,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
}
}
}
cloudType = aiTask.Type
cloudType := aiTask.Type
//download model zip //train type
if cloudType == models.TypeCloudBrainTwo {
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl)
@@ -61,6 +65,20 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
log.Info("download model from CloudBrainTwo faild." + err.Error())
return err
}
} else if cloudType == models.TypeCloudBrainOne {
var ResourceSpecs *models.ResourceSpecs
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
for _, tmp := range ResourceSpecs.ResourceSpec {
if tmp.Id == aiTask.ResourceSpecId {
flaverName := ctx.Tr("cloudbrain.gpu_num") + ": " + fmt.Sprint(tmp.GpuNum) + " " + ctx.Tr("cloudbrain.cpu_num") + ": " + fmt.Sprint(tmp.CpuNum) + " " + ctx.Tr("cloudbrain.memory") + "(MB): " + fmt.Sprint(tmp.MemMiB) + " " + ctx.Tr("cloudbrain.shared_memory") + "(MB): " + fmt.Sprint(tmp.ShareMemMiB)
aiTask.FlavorName = flaverName
}
}
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl)
if err != nil {
log.Info("download model from CloudBrainOne faild." + err.Error())
return err
}
}
accuracy := make(map[string]string)
accuracy["F1"] = ""
@@ -87,7 +105,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
UserId: ctx.User.ID,
CodeBranch: aiTask.BranchName,
CodeCommitID: aiTask.CommitID,
Engine: aiTask.EngineID,
Engine: int64(engine),
TrainTaskInfo: string(aiTaskJson),
Accuracy: string(accuracyJson),
}
@@ -131,7 +149,7 @@ func SaveNewNameModel(ctx *context.Context) {
return
}
SaveModel(ctx)
ctx.Status(200)
log.Info("save model end.")
}

@@ -143,8 +161,9 @@ func SaveModel(ctx *context.Context) {
version := ctx.Query("Version")
label := ctx.Query("Label")
description := ctx.Query("Description")
engine := ctx.QueryInt("Engine")
trainTaskCreate := ctx.QueryBool("trainTaskCreate")
log.Info("engine=" + fmt.Sprint(engine))
if !trainTaskCreate {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
//ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -163,14 +182,14 @@ func SaveModel(ctx *context.Context) {
return
}

err := saveModelByParameters(JobId, VersionName, name, version, label, description, ctx)
err := saveModelByParameters(JobId, VersionName, name, version, label, description, engine, ctx)

if err != nil {
log.Info("save model error." + err.Error())
ctx.Error(500, fmt.Sprintf("save model error. %v", err))
return
}
ctx.Status(200)
log.Info("save model end.")
}

@@ -199,6 +218,22 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir
return dataActualPath, size, nil
}

func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) {
modelActualPath := storage.GetMinioPath(jobName, "/model/")
log.Info("modelActualPath=" + modelActualPath)
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
bucketName := setting.Attachment.Minio.Bucket
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName)
size, err := storage.MinioPathCopy(bucketName, modelSrcPrefix, destKeyNamePrefix)
if err == nil {
dataActualPath := bucketName + "/" + destKeyNamePrefix
return dataActualPath, size, nil
} else {
return "", 0, nil
}
}

func DeleteModel(ctx *context.Context) {
log.Info("delete model start.")
id := ctx.Query("ID")
@@ -277,51 +312,117 @@ func DownloadMultiModelFile(ctx *context.Context) {
}

path := Model_prefix + models.AttachmentRelativePath(id) + "/"
if task.Type == models.TypeCloudBrainTwo {
downloadFromCloudBrainTwo(path, task, ctx, id)
} else if task.Type == models.TypeCloudBrainOne {
downloadFromCloudBrainOne(path, task, ctx, id)
}
}

allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path)
func MinioDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) {
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
w := zip.NewWriter(ctx.Resp)
defer w.Close()
for _, oneFile := range allFile {
if oneFile.IsDir {
log.Info("zip dir name:" + oneFile.FileName)
} else {
log.Info("zip file name:" + oneFile.FileName)
fDest, err := w.Create(oneFile.FileName)
if err != nil {
log.Info("create zip entry error, download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
}
log.Info("minio file path=" + (path + oneFile.FileName))
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, path+oneFile.FileName)
if err != nil {
log.Info("download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
} else {
defer body.Close()
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
fDest.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}
}

}

func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *context.Context, id string) {
allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path)
if err == nil {
//count++
models.ModifyModelDownloadCount(id)

returnFileName := task.Name + "_" + task.Version + ".zip"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+returnFileName)
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
w := zip.NewWriter(ctx.Resp)
defer w.Close()
for _, oneFile := range allFile {
if oneFile.IsDir {
log.Info("zip dir name:" + oneFile.FileName)
MinioDownloadManyFile(path, ctx, returnFileName, allFile)
} else {
log.Info("error,msg=" + err.Error())
ctx.ServerError("no file to download.", err)
}
}

func ObsDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) {
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
w := zip.NewWriter(ctx.Resp)
defer w.Close()
for _, oneFile := range allFile {
if oneFile.IsDir {
log.Info("zip dir name:" + oneFile.FileName)
} else {
log.Info("zip file name:" + oneFile.FileName)
fDest, err := w.Create(oneFile.FileName)
if err != nil {
log.Info("create zip entry error, download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
}
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName)
if err != nil {
log.Info("download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
} else {
log.Info("zip file name:" + oneFile.FileName)
fDest, err := w.Create(oneFile.FileName)
if err != nil {
log.Info("create zip entry error, download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
}
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName)
if err != nil {
log.Info("download file failed: %s\n", err.Error())
ctx.ServerError("download file failed:", err)
return
} else {
defer body.Close()
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
fDest.Write(p[:readCount])
}
if readErr != nil {
break
}
defer body.Close()
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
fDest.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}
}
}

func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *context.Context, id string) {
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path)
if err == nil {
//count++
models.ModifyModelDownloadCount(id)
returnFileName := task.Name + "_" + task.Version + ".zip"
ObsDownloadManyFile(path, ctx, returnFileName, allFile)
} else {
log.Info("error,msg=" + err.Error())
ctx.ServerError("no file to download.", err)
@@ -374,42 +475,55 @@ func DownloadSingleModelFile(ctx *context.Context) {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
if setting.PROXYURL != "" {
body, err := storage.ObsDownloadAFile(setting.Bucket, path)
if err != nil {
log.Info("download error.")
if task.Type == models.TypeCloudBrainTwo {
if setting.PROXYURL != "" {
body, err := storage.ObsDownloadAFile(setting.Bucket, path)
if err != nil {
log.Info("download error.")
} else {
//count++
models.ModifyModelDownloadCount(id)
defer body.Close()
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName)
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
//fmt.Printf("%s", p[:readCount])
}
if readErr != nil {
break
}
}
}
} else {
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path)
if err != nil {
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetObsCreateSignedUrl", err)
return
}
//count++
models.ModifyModelDownloadCount(id)
defer body.Close()
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName)
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
//fmt.Printf("%s", p[:readCount])
}
if readErr != nil {
break
}
}
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}
} else {
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path)
} else if task.Type == models.TypeCloudBrainOne {
log.Info("start to down load minio file.")
url, err := storage.Attachments.PresignedGetURL(path, fileName)
if err != nil {
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetObsCreateSignedUrl", err)
log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("Get minio get SignedUrl failed", err)
return
}
//count++
models.ModifyModelDownloadCount(id)
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}

}

func ShowModelInfo(ctx *context.Context) {
@@ -684,14 +798,22 @@ func QueryModelListForPredict(ctx *context.Context) {
func QueryModelFileForPredict(ctx *context.Context) {
id := ctx.Query("ID")
model, err := models.QueryModelById(id)
if err != nil {
if err == nil {
if model.Type == models.TypeCloudBrainTwo {
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, _ := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix)
ctx.JSON(http.StatusOK, fileinfos)
} else if model.Type == models.TypeCloudBrainOne {
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:]
fileinfos, _ := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, prefix)
ctx.JSON(http.StatusOK, fileinfos)
}
} else {
log.Error("no such model!", err.Error())
ctx.ServerError("no such model:", err)
return
}
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix)
ctx.JSON(http.StatusOK, fileinfos)

}

func QueryOneLevelModelFile(ctx *context.Context) {
@@ -703,7 +825,16 @@ func QueryOneLevelModelFile(ctx *context.Context) {
ctx.ServerError("no such model:", err)
return
}
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
ctx.JSON(http.StatusOK, fileinfos)
if model.Type == models.TypeCloudBrainTwo {
log.Info("TypeCloudBrainTwo list model file.")
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
ctx.JSON(http.StatusOK, fileinfos)
} else if model.Type == models.TypeCloudBrainOne {
log.Info("TypeCloudBrainOne list model file.")
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:]
fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir)
ctx.JSON(http.StatusOK, fileinfos)
}

}

+ 19
- 8
routers/repo/cloudbrain.go View File

@@ -283,11 +283,13 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
mkModelPath(modelPath)
uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/")

commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName)

err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description, branchName, form.BootFile, form.Params,
0, 0, resourceSpecId)
commitID, 0, 0, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tpl, &form)
@@ -1150,6 +1152,7 @@ func CloudBrainDownloadModel(ctx *context.Context) {
ctx.ServerError("PresignedGetURL", err)
return
}
ctx.Resp.Header().Set("Cache-Control", "max-age=0")
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}

@@ -1478,11 +1481,19 @@ func SyncCloudbrainStatus() {
}

func HandleTaskWithNoDuration(ctx *context.Context) {
mode := ctx.Query("mode")
log.Info("HandleTaskWithNoDuration start")
count := 0
start := time.Now().Unix()
for {
cloudBrains, err := models.GetStoppedJobWithNoDurationJob()
var cloudBrains []*models.Cloudbrain
var err error
if mode == "1" {
cloudBrains, err = models.GetStoppedJobWithNoStartTimeEndTime()
} else {
cloudBrains, err = models.GetStoppedJobWithNoDurationJob()
}

if err != nil {
log.Error("HandleTaskWithNoTrainJobDuration failed:", err.Error())
break
@@ -1557,7 +1568,7 @@ func handleNoDurationTask(cloudBrains []*models.Cloudbrain) {
}
task.Duration = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix()
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
err = models.UpdateJob(task)
err = models.UpdateJobDurationWithDeleted(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}
@@ -1582,7 +1593,7 @@ func handleNoDurationTask(cloudBrains []*models.Cloudbrain) {
}
task.CorrectCreateUnix()
task.ComputeAndSetDuration()
err = models.UpdateJob(task)
err = models.UpdateJobDurationWithDeleted(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
@@ -1603,7 +1614,7 @@ func handleNoDurationTask(cloudBrains []*models.Cloudbrain) {
task.EndTime = task.StartTime.Add(result.Duration / 1000)
}
task.ComputeAndSetDuration()
err = models.UpdateJob(task)
err = models.UpdateJobDurationWithDeleted(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
@@ -1624,7 +1635,7 @@ func updateDefaultDuration(task *models.Cloudbrain) {
task.StartTime = task.CreatedUnix
task.EndTime = task.UpdatedUnix
task.ComputeAndSetDuration()
err := models.UpdateJob(task)
err := models.UpdateJobDurationWithDeleted(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}
@@ -1975,7 +1986,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), string(models.JobTypeBenchmark), gpuQueue, form.Description, cloudbrain.DefaultBranchName, "", "",
benchmarkTypeID, benchmarkChildTypeID, resourceSpecId)
"", benchmarkTypeID, benchmarkChildTypeID, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainBenchmarkNew, &form)
@@ -2073,7 +2084,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description, branchName, form.BootFile, form.Params,
0, benchmarkChildTypeID, resourceSpecId)
"", 0, benchmarkChildTypeID, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tpl, &form)


+ 136
- 11
routers/repo/dataset.go View File

@@ -172,6 +172,10 @@ func DatasetIndex(ctx *context.Context) {
for _, attachment := range pageAttachments {
uploader, _ := models.GetUserByID(attachment.UploaderID)
attachment.Uploader = uploader
if !strings.HasSuffix(attachment.Name, ".zip") {
attachment.DecompressState = -1 //非zip文件
}

}

ctx.Data["Page"] = pager
@@ -448,10 +452,11 @@ func PublicDataset(ctx *context.Context) {
}

func MyFavoriteDataset(ctx *context.Context) {
page := ctx.QueryInt("page")
UserId := ctx.User.ID
cloudbrainType := ctx.QueryInt("type")
keyword := strings.Trim(ctx.Query("q"), " ")
var datasetIDs []int64
var NotColDatasetIDs []int64
var IsColDatasetIDs []int64
datasetStars, err := models.GetDatasetStarByUser(ctx.User)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("GetDatasetStarByUser failed", err)))
@@ -463,31 +468,82 @@ func MyFavoriteDataset(ctx *context.Context) {
})
return
}
for i, _ := range datasetStars {
datasetIDs = append(datasetIDs, datasetStars[i].DatasetID)
//If the dataset has been deleted, it will not be counted
for _, datasetStar := range datasetStars {
IsExist, repo, dataset, err := IsDatasetStarExist(datasetStar)
if err != nil {
log.Error("IsDatasetStarExist error:", err.Error())
}
if IsExist {
DatasetIsCollaborator := DatasetIsCollaborator(ctx, dataset)
if repo.OwnerID == ctx.User.ID || DatasetIsCollaborator {
IsColDatasetIDs = append(IsColDatasetIDs, datasetStar.DatasetID)
} else {
NotColDatasetIDs = append(NotColDatasetIDs, datasetStar.DatasetID)
}
}
}

datasets, count, err := models.Attachments(&models.AttachmentsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.DatasetPagingNum,
},
NotColDatasets, NotColcount, err := models.Attachments(&models.AttachmentsOptions{
Keyword: keyword,
NeedDatasetIDs: true,
DatasetIDs: datasetIDs,
DatasetIDs: NotColDatasetIDs,
NeedIsPrivate: true,
IsPrivate: false,
Type: cloudbrainType,
JustNeedZipFile: true,
NeedRepoInfo: true,
RecommendOnly: ctx.QueryBool("recommend"),
UserId: UserId,
})
if err != nil {
ctx.ServerError("datasets", err)
return
}
//If is collaborator, there is no need to determine whether the dataset is private or public
IsColDatasets, IsColcount, err := models.Attachments(&models.AttachmentsOptions{
Keyword: keyword,
NeedDatasetIDs: true,
DatasetIDs: IsColDatasetIDs,
NeedIsPrivate: false,
Type: cloudbrainType,
JustNeedZipFile: true,
NeedRepoInfo: true,
RecommendOnly: ctx.QueryBool("recommend"),
UserId: UserId,
})
if err != nil {
ctx.ServerError("datasets", err)
return
}
for _, NotColDataset := range NotColDatasets {
IsColDatasets = append(IsColDatasets, NotColDataset)
}
datasets := IsColDatasets
count := NotColcount + IsColcount
sort.Slice(datasets, func(i, j int) bool {
return datasets[i].Attachment.CreatedUnix > datasets[j].Attachment.CreatedUnix
})

data, err := json.Marshal(datasets)
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pagesize := ctx.QueryInt("pagesize")
if pagesize <= 0 {
pagesize = 5
}
pageDatasetsInfo := getPageDatasets(datasets, page, pagesize)
if pageDatasetsInfo == nil {
ctx.JSON(200, map[string]string{
"result_code": "0",
"data": "[]",
"count": strconv.FormatInt(count, 10),
})
return
}
data, err := json.Marshal(pageDatasetsInfo)
log.Info("data:", data)
if err != nil {
log.Error("json.Marshal failed:", err.Error())
ctx.JSON(200, map[string]string{
@@ -503,6 +559,29 @@ func MyFavoriteDataset(ctx *context.Context) {
"count": strconv.FormatInt(count, 10),
})

}
func getPageDatasets(AttachmentInfos []*models.AttachmentInfo, page int, pagesize int) []*models.AttachmentInfo {
begin := (page - 1) * pagesize
end := (page) * pagesize

if begin > len(AttachmentInfos)-1 {
return nil
}
if end > len(AttachmentInfos)-1 {
return AttachmentInfos[begin:]
} else {
return AttachmentInfos[begin:end]
}

}
func getTotalPage(total int64, pageSize int) int {

another := 0
if int(total)%pageSize != 0 {
another = 1
}
return int(total)/pageSize + another

}

func GetDatasetStatus(ctx *context.Context) {
@@ -529,3 +608,49 @@ func GetDatasetStatus(ctx *context.Context) {
"AttachmentStatus": fmt.Sprint(attachment.DecompressState),
})
}
func DatasetIsCollaborator(ctx *context.Context, dataset *models.Dataset) bool {
repo, err := models.GetRepositoryByID(dataset.RepoID)
if err != nil {
log.Error("query repo error:", err.Error())
} else {
repo.GetOwner()
if ctx.User != nil {
if repo.Owner.IsOrganization() {
if repo.Owner.IsUserPartOfOrg(ctx.User.ID) {
for _, t := range repo.Owner.Teams {
if t.IsMember(ctx.User.ID) && t.HasRepository(repo.ID) {
return true
}
}
isOwner, _ := models.IsOrganizationOwner(repo.OwnerID, ctx.User.ID)
if isOwner {
return isOwner
}
return false
}
}

isCollaborator, _ := repo.IsCollaborator(ctx.User.ID)
if isCollaborator {
return true
}
}
}

return false
}
func IsDatasetStarExist(datasetStar *models.DatasetStar) (bool, *models.Repository, *models.Dataset, error) {
dataset, err := models.GetDatasetByID(datasetStar.DatasetID)
if err != nil {
log.Error("query dataset error:", err.Error())
return false, nil, nil, err
} else {
repo, err := models.GetRepositoryByID(dataset.RepoID)
if err != nil {
log.Error("GetRepositoryByID error:", err.Error())
return false, nil, nil, err
}
return true, repo, dataset, nil
}

}

+ 35
- 5
routers/repo/modelarts.go View File

@@ -1407,7 +1407,7 @@ func readDir(dirname string) ([]os.FileInfo, error) {
return nil, err
}

list, err := f.Readdir(100)
list, err := f.Readdir(0)
f.Close()
if err != nil {
//todo: can not upload empty folder
@@ -2251,7 +2251,6 @@ func ModelDownload(ctx *context.Context) {
versionName := ctx.Query("version_name")
parentDir := ctx.Query("parent_dir")
fileName := ctx.Query("file_name")
log.Info("DownloadSingleModelFile start.")
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error())
@@ -2259,7 +2258,6 @@ func ModelDownload(ctx *context.Context) {
}

path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, setting.OutPutPath, versionName, parentDir, fileName), "/")
log.Info("Download path is:%s", path)

url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path)
if err != nil {
@@ -2267,6 +2265,7 @@ func ModelDownload(ctx *context.Context) {
ctx.ServerError("GetObsCreateSignedUrl", err)
return
}
ctx.Resp.Header().Set("Cache-Control", "max-age=0")
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}

@@ -2278,13 +2277,11 @@ func ResultDownload(ctx *context.Context) {
versionName := ctx.Query("version_name")
parentDir := ctx.Query("parent_dir")
fileName := ctx.Query("file_name")
log.Info("DownloadResult start.")
task := ctx.Cloudbrain
if err != nil {
ctx.Data["error"] = err.Error()
}
path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, "result/", versionName, parentDir, fileName), "/")
log.Info("Download path is:%s", path)

url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path)
if err != nil {
@@ -2292,6 +2289,7 @@ func ResultDownload(ctx *context.Context) {
ctx.ServerError("GetObsCreateSignedUrl", err)
return
}
ctx.Resp.Header().Set("Cache-Control", "max-age=0")
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}
func DeleteJobStorage(jobName string) error {
@@ -2390,3 +2388,35 @@ func SetJobCount(ctx *context.Context) {
}
ctx.Data["jobCount"] = jobCount
}

func TrainJobDownloadLogFile(ctx *context.Context) {
var (
err error
)

var jobID = ctx.Params(":jobid")
versionName := ctx.Query("version_name")
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName)
if err != nil {
log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetCloudbrainByJobIDAndVersionName", err)
return
}

prefix := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, modelarts.LogPath, versionName), "/") + "/job"
key, err := storage.GetObsLogFileName(prefix)
if err != nil {
log.Error("GetObsLogFileName(%s) failed:%v", jobID, err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetObsLogFileName", err)
return
}

url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, key)
if err != nil {
log.Error("GetObsCreateSignedUrlByBucketAndKey failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetObsCreateSignedUrlByBucketAndKey", err)
return
}
ctx.Resp.Header().Set("Cache-Control", "max-age=0")
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}

+ 6
- 2
routers/repo/repo.go View File

@@ -6,7 +6,6 @@
package repo

import (
"code.gitea.io/gitea/modules/validation"
"fmt"
"net/url"
"os"
@@ -15,6 +14,8 @@ import (
"strings"
"unicode/utf8"

"code.gitea.io/gitea/modules/validation"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
@@ -193,7 +194,10 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
return
}
ctx.Data["ContextUser"] = ctxUser

if !form.AutoAgree {
ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form)
return
}
if ctx.HasError() {
ctx.HTML(200, tplCreate)
return


+ 4
- 0
routers/repo/view.go View File

@@ -471,6 +471,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st

readmeExist := markup.IsReadmeFile(blob.Name())
ctx.Data["ReadmeExist"] = readmeExist
isNoteBook := strings.HasSuffix(blob.Name(), ".ipynb")
ctx.Data["IsNoteBook"] = isNoteBook
if markupType := markup.Type(blob.Name()); markupType != "" {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
@@ -480,6 +482,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["FileContent"] = strings.Replace(
gotemplate.HTMLEscapeString(string(buf)), "\n", `<br>`, -1,
)
} else if isNoteBook {
ctx.Data["FileContent"] = string(buf)
} else {
// Building code view blocks with line number on server side.
var fileContent string


+ 9
- 3
routers/routes/routes.go View File

@@ -324,10 +324,14 @@ func RegisterRoutes(m *macaron.Macaron) {
go routers.SocketManager.Run()
m.Get("/action/notification", routers.ActionNotification)
m.Get("/recommend/home", routers.RecommendHomeInfo)
//m.Get("/recommend/org", routers.RecommendOrgFromPromote)
//m.Get("/recommend/repo", routers.RecommendRepoFromPromote)
m.Get("/recommend/userrank/:index", routers.GetUserRankFromPromote)
//m.Get("/recommend/imageinfo", routers.GetImageInfoFromPromote)
m.Post("/all/search/", routers.Search)
m.Get("/all/search/", routers.EmptySearch)
m.Get("/all/dosearch/", routers.SearchApi)
m.Post("/user/login/kanban", user.SignInPostAPI)
m.Get("/home/term", routers.HomeTerm)
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
@@ -362,6 +366,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/user", func() {
m.Get("/login", user.SignIn)
m.Get("/login/cloud_brain", user.SignInCloudBrain)
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
m.Group("", func() {
m.Combo("/login/openid").
@@ -1093,9 +1098,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel)
m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList)
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList)
m.Get("/query_model_for_predict", reqRepoCloudBrainReader, repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", reqRepoCloudBrainReader, repo.QueryModelFileForPredict)
m.Get("/query_onelevel_modelfile", reqRepoCloudBrainReader, repo.QueryOneLevelModelFile)
m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict)
m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile)
m.Group("/:ID", func() {
m.Get("", repo.ShowSingleModel)
m.Get("/downloadsingle", repo.DownloadSingleModelFile)
@@ -1136,6 +1141,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.TrainJobStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.TrainJobDel)
m.Get("/model_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.ModelDownload)
m.Get("/download_log_file", cloudbrain.AdminOrJobCreaterRightForTrain, repo.TrainJobDownloadLogFile)
m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, repo.TrainJobNewVersion)
m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion)
})


+ 97
- 0
routers/user/auth.go View File

@@ -176,6 +176,41 @@ func SignInCloudBrain(ctx *context.Context) {
ctx.HTML(200, tplSignInCloudBrain)
}

func SignInPostAPI(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("sign_in")
UserName := ctx.Query("UserName")
Password := ctx.Query("Password")
log.Info("0000000")
orderedOAuth2Names, oauth2Providers, err := models.GetActiveOAuth2Providers()
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
ctx.Data["Title"] = ctx.Tr("sign_in")
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
ctx.Data["PageIsSignIn"] = true
ctx.Data["PageIsLogin"] = true
ctx.Data["IsCourse"] = ctx.QueryBool("course")
ctx.Data["EnableSSPI"] = models.IsSSPIEnabled()

if ctx.HasError() {
ctx.HTML(200, tplSignIn)
return
}
u, err := models.UserSignIn(UserName, Password)
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
models.SaveLoginInfoToDb(ctx.Req.Request, u)
// If this user is enrolled in 2FA, we can't sign the user in just yet.
// Instead, redirect them to the 2FA authentication page.
//handleSignInFull(ctx, u, form.Remember, false)
handleSignInFullNotRedirect(ctx, u, true, false)
}

// SignInPost response for sign in request
func SignInPost(ctx *context.Context, form auth.SignInForm) {
ctx.Data["Title"] = ctx.Tr("sign_in")
@@ -518,6 +553,68 @@ func handleSignIn(ctx *context.Context, u *models.User, remember bool) {
handleSignInFull(ctx, u, remember, true)
}

func handleSignInFullNotRedirect(ctx *context.Context, u *models.User, remember bool, obeyRedirect bool) string {

log.Info("enter here.")
if remember {
days := 86400 * setting.LogInRememberDays
ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd),
setting.CookieRememberName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
}

_ = ctx.Session.Delete("openid_verified_uri")
_ = ctx.Session.Delete("openid_signin_remember")
_ = ctx.Session.Delete("openid_determined_email")
_ = ctx.Session.Delete("openid_determined_username")
_ = ctx.Session.Delete("twofaUid")
_ = ctx.Session.Delete("twofaRemember")
_ = ctx.Session.Delete("u2fChallenge")
_ = ctx.Session.Delete("linkAccount")
if err := ctx.Session.Set("uid", u.ID); err != nil {
log.Error("Error setting uid %d in session: %v", u.ID, err)
}
if err := ctx.Session.Set("uname", u.Name); err != nil {
log.Error("Error setting uname %s session: %v", u.Name, err)
}
if err := ctx.Session.Release(); err != nil {
log.Error("Unable to store session: %v", err)
}

// If the user does not have a locale set, we save the current one.
if len(u.Language) == 0 {
if len(ctx.GetCookie("lang")) != 0 {
u.Language = ctx.GetCookie("lang")
} else {
u.Language = ctx.Locale.Language()
}

if err := models.UpdateUserCols(u, "language"); err != nil {
log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
return setting.AppSubURL + "/dashboard"
}
} else {
// Language setting of the user use the one previously set
if len(ctx.GetCookie("lang")) != 0 {
u.Language = ctx.GetCookie("lang")
}
}

ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)

// Clear whatever CSRF has right now, force to generate a new one
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)

// Register last login
u.SetLastLogin()
if err := models.UpdateUserCols(u, "last_login_unix"); err != nil {
ctx.ServerError("UpdateUserCols", err)
return setting.AppSubURL + "/dashboard"
}

return setting.AppSubURL + "/dashboard"
}

func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyRedirect bool) string {
if remember {
days := 86400 * setting.LogInRememberDays


+ 44
- 0
templates/base/footer.tmpl View File

@@ -13,6 +13,9 @@
{{template "base/footer_content" .}}

<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script>


{{if .RequireSimpleMDE}}
<script src="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js"></script>
<script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script>
@@ -43,5 +46,46 @@
<script src="{{StaticUrlPrefix}}/fomantic/semantic.min.js?v={{MD5 AppVer}}"></script>
<script src="{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}"></script>
{{template "custom/footer" .}}
{{if .PageIsHome}}
<!--script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script-->
<script src="/rotation3D/vue-2.6.10.min.js"></script>
<script src="/rotation3D/rotation3D.js?v={{MD5 AppVer}}"></script>
<script>
var app = new Vue({
el: "#app",
//数据 blue, green, yellow
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,
// farScale: 1,
xRadius: 0, //x半径压缩
yRadius: 130, //y半径压缩
// yRadius: 0, //y半径压缩
// autoPlay:true,
// autoPlayDelay:6000,
})
},
methods: {},
});
</script>
{{end}}

</body>
</html>

+ 2
- 0
templates/base/head_home.tmpl View File

@@ -192,6 +192,8 @@ var _hmt = _hmt || [];
<!-- Swiper -->
<link rel="stylesheet" href="/swiper/swiper-bundle.min.css">
<script src="/swiper/swiper-bundle.min.js"></script>
<!-- rotation3D -->
<link rel="stylesheet" href="/rotation3D/rotation3D.css">
</head>
<body>
{{template "custom/body_outer_pre" .}}


+ 4
- 4
templates/base/head_navbar.tmpl View File

@@ -34,7 +34,7 @@

<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a>
<div class="ui dropdown item" id='dropdown_explore'>
<div class="ui simple dropdown item" id='dropdown_explore'>
{{.i18n.Tr "explore"}}
<i class="dropdown icon"></i>
<div class="menu">
@@ -65,7 +65,7 @@

<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a>
<div class="ui dropdown item" id='dropdown_PageHome'>
<div class="ui simple dropdown item" id='dropdown_PageHome'>
{{.i18n.Tr "explore"}}
<i class="dropdown icon"></i>
<div class="menu" >
@@ -120,7 +120,7 @@
</span>
</a>

<div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
<div class="ui simple dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
<span class="text">
<span class="fitted">{{svg "octicon-plus" 16}}</span>
<span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span>
@@ -141,7 +141,7 @@
</div><!-- end content create new menu -->
</div><!-- end dropdown menu create new -->

<div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted">
<div class="ui simple dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted">
<span class="text">
<img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}">
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span>


+ 201
- 141
templates/explore/datasets.tmpl View File

@@ -1,133 +1,162 @@
{{template "base/head" .}}
<style>
.mg-b-1{
margin-bottom: 1rem;
}
.mg-b-2{
margin-bottom: 2rem;
}
.mg-l-1{
margin-left: 1rem;
}
.text-gray-400 {
--tw-text-opacity: 1;
color: rgba(156,163,175,var(--tw-text-opacity));
}
.text-sm {
font-size: .875rem;
line-height: 1.25rem;
}
.underline {
text-decoration: underline;
}
.flex{
display: flex;
}
.font-medium{
font-weight: 500;
}
.flex-wrap{
flex-wrap: wrap;
}
.tag {
background-image: linear-gradient(to bottom,var(--tw-gradient-stops));
border-color: transparent;
border-radius: 0.5rem;
border-width: 1px;
font-size: .875rem;
line-height: 1.25rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tag-red {
--tw-gradient-from: #fef2f2;
--tw-gradient-stops: var(--tw-gradient-from),var(--tw-gradient-to,hsla(0,86%,97%,0));
--tw-gradient-to: #fef2f2;
--tw-text-opacity: 1;
color: rgba(153,27,27,var(--tw-text-opacity));
}
.tag-purple {
--tw-gradient-from: #f5f3ff;
--tw-gradient-stops: var(--tw-gradient-from),var(--tw-gradient-to,rgba(245,243,255,0));
--tw-gradient-to: #f5f3ff;
--tw-text-opacity: 1;
color: rgba(91,33,182,var(--tw-text-opacity));
}
.tag-blue {
--tw-gradient-from: #eff6ff;
--tw-gradient-stops: var(--tw-gradient-from),var(--tw-gradient-to,rgba(239,246,255,0));
--tw-gradient-to: #eff6ff;
--tw-text-opacity: 1;
color: rgba(30,64,175,var(--tw-text-opacity));
}
.tag.inactive {
filter: grayscale(100%);
opacity: .5;
}
.tag.tag-active{
background-color: #0366d6;
color: #ffffff;
}
.tag-gray{
background-color: #f8f9fa;
color: #415058;
}
.tag {
align-items: center;
display: inline-flex;
flex: none;
height: 2rem;
margin-bottom: 0.35rem;
margin-right: 0.35rem;
max-width: 100%;
}
.tag>span {
padding: 0.75rem;
font-size: 14px;
}
.repo_dataset_header{
font-size: 12px;
color: #3291F8;
}
.heart-stroke{
stroke: #666;
stroke-width: 2;
fill: #fff
}
.stars_active{
fill: #FA8C16 !important;
stroke:#FA8C16 !important
}
.mg-b-1 {
margin-bottom: 1rem;
}

.mg-b-2 {
margin-bottom: 2rem;
}

.mg-l-1 {
margin-left: 1rem;
}

.text-gray-400 {
--tw-text-opacity: 1;
color: rgba(156, 163, 175, var(--tw-text-opacity));
}

.text-sm {
font-size: .875rem;
line-height: 1.25rem;
}

.underline {
text-decoration: underline;
}

.flex {
display: flex;
}

.font-medium {
font-weight: 500;
}

.flex-wrap {
flex-wrap: wrap;
}

.tag {
background-image: linear-gradient(to bottom, var(--tw-gradient-stops));
border-color: transparent;
border-radius: 0.5rem;
border-width: 1px;
font-size: .875rem;
line-height: 1.25rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.tag-red {
--tw-gradient-from: #fef2f2;
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, hsla(0, 86%, 97%, 0));
--tw-gradient-to: #fef2f2;
--tw-text-opacity: 1;
color: rgba(153, 27, 27, var(--tw-text-opacity));
}

.tag-purple {
--tw-gradient-from: #f5f3ff;
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgba(245, 243, 255, 0));
--tw-gradient-to: #f5f3ff;
--tw-text-opacity: 1;
color: rgba(91, 33, 182, var(--tw-text-opacity));
}

.tag-blue {
--tw-gradient-from: #eff6ff;
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgba(239, 246, 255, 0));
--tw-gradient-to: #eff6ff;
--tw-text-opacity: 1;
color: rgba(30, 64, 175, var(--tw-text-opacity));
}

.tag.inactive {
filter: grayscale(100%);
opacity: .5;
}

.tag.tag-active {
background-color: #0366d6;
color: #ffffff;
}

.tag-gray {
background-color: #f8f9fa;
color: #415058;
}

.tag {
align-items: center;
display: inline-flex;
flex: none;
height: 2rem;
margin-bottom: 0.35rem;
margin-right: 0.35rem;
max-width: 100%;
}

.tag>span {
padding: 0.75rem;
font-size: 14px;
}

.repo_dataset_header {
font-size: 12px;
color: #3291F8;
}

.heart-stroke {
stroke: #FA8C16;
stroke-width: 2;
fill: #fff
}

.stars_active {
fill: #FA8C16 !important;
stroke: #FA8C16 !important
}
</style>
<div class="explore repositories">
{{template "explore/dataset_search" .}}
<div>
<div class="ui container">
<div class="ui grid">
{{template "explore/dataset_left" .}}
<div class="ui sixteen wide mobile sixteen wide tablet twelve wide computer column">
<div class="ui row">
<h2 class="ui left floated medium header">
{{.i18n.Tr "datasets"}}
{{.i18n.Tr "datasets"}}
</h2>
<div class="ui right floated secondary filter menu">
<!-- Sort -->
<div class="ui right dropdown type jump item">
<span class="text">
{{.i18n.Tr "repo.issues.filter_sort"}}
<i class="dropdown icon"></i>
{{.i18n.Tr "repo.issues.filter_sort"}}
<i class="dropdown icon"></i>
</span>
<div class="menu">
<a class="{{if eq .SortType "default"}}active{{end}} item" href="{{$.Link}}?sort=default&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.default"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "downloadtimes"}}active{{end}} item" href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "default"}}active{{end}} item"
href="{{$.Link}}?sort=default&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.default"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item"
href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item"
href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item"
href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item"
href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "downloadtimes"}}active{{end}} item"
href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item"
href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "mostusecount"}}active{{end}} item"
href="{{$.Link}}?sort=mostusecount&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "repo.issues.filter_sort.mostusecount"}}</a>
</div>
</div>
</div>
@@ -141,85 +170,116 @@
{{end}}

<div class="ui row" style="clear: both;" id="dataset-base">
<el-checkbox v-model="checked" style="padding: 0.5rem 1rem;" @change="handleCheckedChange" >仅显示平台推荐</el-checkbox>
<el-checkbox v-model="checked" style="padding: 0.5rem 1rem;" @change="handleCheckedChange">
仅显示平台推荐</el-checkbox>
<div class="ui two cards">
{{range $k, $v :=.Datasets}}
<div class="ui card" @click="gotoDataset('{{.Repo.Link}}/datasets')" style="cursor: pointer;box-shadow: 0px 4px 4px 0px rgba(232,232,232,0.6);border: 1px solid rgba(232, 232, 232, 1);">
<div class="ui card" @click="gotoDataset('{{.Repo.Link}}/datasets')"
style="cursor: pointer;box-shadow: 0px 4px 4px 0px rgba(232,232,232,0.6);border: 1px solid rgba(232, 232, 232, 1);">
<div class="content" style="border-bottom: none;">
<div class="repo_dataset_header" style="display: flex;align-items: center;justify-content: space-between;">
<a href="{{.Repo.Link}}/datasets" style="font-size: 12px;color: #3291F8;height: 24px;">{{.Repo.OwnerName}} / {{.Repo.Alias}}</a>
<div
style="font-size: 16px;color:#0366D6;font-family: SourceHanSansSC-medium;height: 34px;font-weight: bold;display: flex;align-items: center">
<span title="{{.Title}}" class="nowrap"
style="display: inline-block;">{{.Title}}</span>{{if .Recommend}}<img
src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}
{{if $.IsSigned}}
<span style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;" @click.stop="postSquareStar({{.ID}},'{{.Repo.Link}}/datasets',{{$k}})">
<span style="line-height: 1;color: #101010;margin-bottom: -2px;"><i class="ri-download-line" style="font-size: 1.3em;"></i></span>
<span style="line-height: 1;color: #101010;margin-right: 0.6rem;">{{.DownloadTimes}}</span>
<span
style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;font-size: 12px;font-weight: normal;flex: 1;margin-left: 1.5rem;"
@click.stop="postSquareStar({{.ID}},'{{.Repo.Link}}/datasets',{{$k}})">

<div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;">
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke" :class='{stars_active:starActives[{{$k}}]}'><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg>
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32"
class="heart-stroke" :class='{stars_active:starActives[{{$k}}]}'>
<path
d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z">
</path>
</svg>
</div>
<span style="line-height: 1;color: #101010;">${starItems[{{$k}}]}</span>
</span>
{{else}}
<span style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;">
<span style="line-height: 1;color: #101010;margin-bottom: -2px;"><i class="ri-download-line" style="font-size: 1.3em;"></i></span>
<span style="line-height: 1;color: #101010;margin-right: 0.6rem;">{{.DownloadTimes}}</span>
<span
style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;font-size: 12px;font-weight: normal;flex: 1;margin-left: 1.5rem;">
<div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;">
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke" :class='{stars_active:starActives[{{$k}}]}'><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg>
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32"
class="heart-stroke" :class='{stars_active:starActives[{{$k}}]}'>
<path
d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z">
</path>
</svg>
</div>
<span style="line-height: 1;color: #101010;">${starItems[{{$k}}]}</span>
</span>
{{end}}

</div>
<div style="font-size: 16px;color:#0366D6;font-family: SourceHanSansSC-medium;height: 27px;font-weight: bold;display: flex;align-items: center"><span title="{{.Title}}" class="nowrap" style="display: inline-block;">{{.Title}}</span>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</div>
{{if or (.Category) (.Task) (.License)}}
<div style="font-size: 12px;margin-top: 5px;">
{{if .Category}}
{{$category := .Category}}
<a class="ui repo-topic label topic" href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{.Category}}&task={{$.Task}}&license={{$.License}}">{{$.i18n.Tr (printf "dataset.category.%s" $category)}}</a>
<a class="ui repo-topic label topic"
href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{.Category}}&task={{$.Task}}&license={{$.License}}">{{$.i18n.Tr (printf "dataset.category.%s" $category)}}</a>
{{end}}
{{if .Task}}
{{$task := .Task}}
<a class="ui repo-topic label topic" href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{.Task}}&license={{$.License}}">{{$.i18n.Tr (printf "dataset.task.%s" $task)}}</a>
<a class="ui repo-topic label topic"
href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{.Task}}&license={{$.License}}">{{$.i18n.Tr (printf "dataset.task.%s" $task)}}</a>
{{end}}
{{if .License}}
<a class="ui repo-topic label topic" href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{.License}}">{{.License}}</a>
<a class="ui repo-topic label topic"
href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{.License}}">{{.License}}</a>
{{end}}
</div>
{{end}}
<div class="description" style="-webkit-box-orient: vertical;-webkit-line-clamp: 2;display: -webkit-box;overflow: hidden;color:#999999;font-size: 14px;margin-top: 10px;">
<div class="description"
style="-webkit-box-orient: vertical;-webkit-line-clamp: 2;display: -webkit-box;overflow: hidden;color:#999999;font-size: 14px;margin-top: 10px;">
<p>{{.Description}}</p>
</div>
</div>
<div class="extra content" style="border-top: none !important;">
<div style="display: flex;align-items: center;">
{{if eq .UserID 0}}
<a href="{{AppSubUrl}}/{{.Repo.OwnerName}}" title="{{.Repo.OwnerName}}">
<img class="ui avatar image" style="width: 22px;height:22px;" src="/user/avatar/{{.Repo.OwnerName}}/-1">
<img class="ui avatar image" style="width: 22px;height:22px;"
src="/user/avatar/{{.Repo.OwnerName}}/-1">
</a>
{{else}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}">
<img class="ui avatar image" style="width: 22px;height:22px;" src="/user/avatar/{{.User.Name}}/-1">
<img class="ui avatar image" style="width: 22px;height:22px;"
src="/user/avatar/{{.User.Name}}/-1">
</a>
{{end}}
<span style="color: #999999;font-size: 14px;;">创建于:{{TimeSinceUnix1 .CreatedUnix}}</span>
<span
style="color: #999999;font-size: 12px;margin-left: 0.5rem;">{{TimeSinceUnixShort .CreatedUnix}}</span>
<span
style="display: flex;align-items: center;justify-content: center;margin: 0 1rem;"
title="{{$.i18n.Tr "repo.issues.filter_sort.citations"}}">
<i class="ri-link"></i>
<span
style="color: #101010; font-size: 12px;margin-left: 0.2rem;">{{.UseCount}}</span>
</span>
<span style=" display: flex;align-items: center;justify-content: center;"
title='{{$.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}'>
<i class="ri-download-line"></i>
<span
style="color: #101010;font-size: 12px;margin-left: 0.2rem;">{{.DownloadTimes}}</span>
</span>
</div>
</div>
</div>
{{end}}

</div>
</div>

<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[30]"
:page-size="30"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
<el-pagination background @current-change="handleCurrentChange" :current-page="page"
:page-sizes="[30]" :page-size="30" layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>


+ 80
- 25
templates/home.tmpl View File

@@ -1,6 +1,6 @@
{{template "base/head_home" .}}
<div class="ui vertical masthead secondary hometop segment">
<div class="ui container" style="position: relative;">
<div class="ui container" style="position: relative;">
<div class="ui center homebanner">
<h1 class="ui huge header">
{{.page_title}}
@@ -17,7 +17,7 @@
{{end}}
</div>
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
<div id="homenews" class="ui container">
<div id="homenews">
<p>* {{.page_only_dynamic}}</p>
<div class="ui grid">
<div class="sixteen wide mobile twelve wide tablet ten wide computer column homenews">
@@ -35,33 +35,32 @@

<!--组织-->
<div class="ui container homeorg">
<div class="ui stackable grid">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column homeorg-tit">
<h2>{{.page_recommend_activity}}</h2>
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p>
<h2>{{.page_recommend_org}}</h2>
<p><span class="ui text grey">{{.page_recommend_org_desc}}&nbsp;</span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p>
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="event-list">
<div class="swiper-wrapper" id="recommendactivity">
<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>{{.page_recommend_org}}</h2>
<p><span class="ui text grey">{{.page_recommend_org_desc}}&nbsp;</span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p>
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a>
<h2>{{.page_recommend_activity}}</h2>
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="homeorg-list">
<div class="swiper-wrapper" id="recommendorg">
<div class="event-list">
<div class="swiper-wrapper" id="recommendactivity">
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
@@ -87,56 +86,112 @@
</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="aiData">
<p>完成AI任务<br><strong id="completed_task">1716</strong></p>
<p>运行AI任务<br><strong id="running_task">120</strong></p>
<p>等待AI任务<br><strong id="wait_task">80</strong></p>
</div>-->
<!--底座-->
<div class="rotation3D-baseMap"></div>
<!--旋转3D-->
<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><!--rotation3D end-->
</div>
</div>

<a name="fourth"></a>
<div class="ui container i-env">
<div class="ui center am-pb-30">
<div class="leftline03"></div>
<h2>{{.page_dev_env}}</h2>
<p><span class="ui text grey">{{.page_dev_env_desc}}</p>
</div>
<div class="ui four doubling cards">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.svg">
<img src="/img/i-pic-01.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc_title}}</h3>
<div class="description">
<div class="description ui text grey">
{{.page_dev_env_desc_desc}}
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-02.svg">
<img src="/img/i-pic-02.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc1_title}}</h3>
<div class="description">
<div class="description ui text grey">
{{.page_dev_env_desc1_desc}}
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-03.svg">
<img src="/img/i-pic-03.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc2_title}}</h3>
<div class="description">
<div class="description ui text grey">
{{.page_dev_env_desc2_desc}}
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.svg">
<img src="/img/i-pic-04.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc3_title}}</h3>
<div class="description">
<div class="description ui text grey">
{{.page_dev_env_desc3_desc}}
</div>
</div>
@@ -172,8 +227,8 @@
</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={{MD5 AppVer}}" type="text/javascript"></script>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>
<script src="/home/home.js?v={{MD5 AppVer}}" type="text/javascript"></script>


{{template "base/footer" .}}

+ 39
- 19
templates/repo/create.tmpl View File

@@ -15,11 +15,11 @@
<label>{{.i18n.Tr "repo.visibility"}}</label>
<div class="ui checkbox">
{{if .IsForcedPrivate}}
<input name="private" type="checkbox" checked readonly>
<label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label>
<input name="private" type="checkbox" checked readonly>
<label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label>
{{else}}
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
<label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label>
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
<label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label>
{{end}}
</div>
<span class="help">{{.i18n.Tr "repo.visibility_description"}}</span>
@@ -42,33 +42,41 @@
<div class="inline field">
<label>{{.i18n.Tr "repo.template.items"}}</label>
<div class="ui checkbox">
<input class="hidden" name="git_content" type="checkbox" tabindex="0" {{if .git_content}}checked{{end}}>
<input class="hidden" name="git_content" type="checkbox" tabindex="0"
{{if .git_content}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.git_content"}}</label>
</div>
<div class="ui checkbox" {{if not .SignedUser.CanEditGitHook}}data-tooltip="{{.i18n.Tr "repo.template.git_hooks_tooltip"}}"{{end}}>
<input class="hidden" name="git_hooks" type="checkbox" tabindex="0" {{if .git_hooks}}checked{{end}}>
<div class="ui checkbox"
{{if not .SignedUser.CanEditGitHook}}data-tooltip="{{.i18n.Tr "repo.template.git_hooks_tooltip"}}"
{{end}}>
<input class="hidden" name="git_hooks" type="checkbox" tabindex="0"
{{if .git_hooks}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.git_hooks"}}</label>
</div>
</div>
<div class="inline field">
<label></label>
<div class="ui checkbox">
<input class="hidden" name="webhooks" type="checkbox" tabindex="0" {{if .webhooks}}checked{{end}}>
<input class="hidden" name="webhooks" type="checkbox" tabindex="0"
{{if .webhooks}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.webhooks"}}</label>
</div>
<div class="ui checkbox">
<input class="hidden" name="topics" type="checkbox" tabindex="0" {{if .topics}}checked{{end}}>
<input class="hidden" name="topics" type="checkbox" tabindex="0"
{{if .topics}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.topics"}}</label>
</div>
</div>
<div class="inline field">
<label></label>
<div class="ui checkbox">
<input class="hidden" name="avatar" type="checkbox" tabindex="0" {{if .avatar}}checked{{end}}>
<input class="hidden" name="avatar" type="checkbox" tabindex="0"
{{if .avatar}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.avatar"}}</label>
</div>
<div class="ui checkbox">
<input class="hidden" name="labels" type="checkbox" tabindex="0" {{if .labels}}checked{{end}}>
<input class="hidden" name="labels" type="checkbox" tabindex="0"
{{if .labels}}checked{{end}}>
<label>{{.i18n.Tr "repo.template.issue_labels"}}</label>
</div>
</div>
@@ -83,7 +91,8 @@
<div class="menu">
<div class="item" data-value="">{{.i18n.Tr "repo.issue_labels_helper"}}</div>
{{range $template, $labels := .LabelTemplates}}
<div class="item" data-value="{{$template}}">{{$template}}<br/><i>({{$labels}})</i></div>
<div class="item" data-value="{{$template}}">{{$template}}<br /><i>({{$labels}})</i>
</div>
{{end}}
</div>
</div>
@@ -98,7 +107,7 @@
<div class="default text">{{.i18n.Tr "repo.repo_gitignore_helper"}}</div>
<div class="menu">
{{range .Gitignores}}
<div class="item" data-value="{{.}}">{{.}}</div>
<div class="item" data-value="{{.}}">{{.}}</div>
{{end}}
</div>
</div>
@@ -111,7 +120,7 @@
<div class="menu">
<div class="item" data-value="">{{.i18n.Tr "repo.license_helper"}}</div>
{{range .Licenses}}
<div class="item" data-value="{{.}}">{{.}}</div>
<div class="item" data-value="{{.}}">{{.}}</div>
{{end}}
</div>
</div>
@@ -124,24 +133,35 @@
<div class="default text">{{.i18n.Tr "repo.readme_helper"}}</div>
<div class="menu">
{{range .Readmes}}
<div class="item" data-value="{{.}}">{{.}}</div>
<div class="item" data-value="{{.}}">{{.}}</div>
{{end}}
</div>
</div>
</div>
<div class="inline field">
<div class="ui checkbox" id="auto-init">
<input class="hidden" name="auto_init" type="checkbox" tabindex="0" {{if .auto_init}}checked{{end}}>
<input class="hidden" name="auto_init" type="checkbox" tabindex="0"
{{if .auto_init}}checked{{end}}>
<label>{{.i18n.Tr "repo.auto_init"}}</label>
</div>
</div>
<div class="inline field">
<label for="default_branch">{{.i18n.Tr "repo.default_branch"}}</label>
<input id="default_branch" name="default_branch" value="{{.default_branch}}" placeholder="master">
<input id="default_branch" name="default_branch" value="{{.default_branch}}"
placeholder="master">
</div>
<div class="inline field">
<div class="ui checkbox" id="auto-init">
<input class="hidden" name="auto_agree" type="checkbox">
<label
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}}
<a target="_blank"
href="/home/term/">{{.i18n.Tr "repo.openi_use_agreement"}}</a></label>
</div>
</div>
</div>

<br/>
<br />
<div class="inline field">
<label></label>
<button class="ui green button" id="submit_reponame">
@@ -154,4 +174,4 @@
</div>
</div>
</div>
{{template "base/footer" .}}
{{template "base/footer" .}}

+ 29
- 40
templates/repo/datasets/index.tmpl View File

@@ -11,7 +11,7 @@

.dataset_title {
font-size: 14px;
max-width: 80%;
/* max-width: 80%; */
display: inline-block !important;
margin-left: 6px !important;
padding-right: 0 !important;
@@ -105,7 +105,7 @@
}

.heart-stroke {
stroke: #666;
stroke: #FA8C16;
stroke-width: 2;
fill: #fff
}
@@ -148,7 +148,7 @@
<div class="ui mobile reversed stackable grid">
<div class="row">
<div class="column thirteen wide">
<h2>{{.dataset.Title}}</h2>
<h2 class="nowrap">{{.dataset.Title}}</h2>
</div>
<div class="column three wide right aligned">
<span style="display: flex;align-items: center;justify-content: flex-end;height: 36px;">
@@ -276,27 +276,34 @@
<!-- 数据集名称 -->

<div class="four wide column" style="width: 24% !important;display: flex;align-items: center;">
{{if .Description}}
<el-tooltip class="item" effect="dark" placement="top" popper-class="diy-popper">
<div slot="content">{{.Description}}</br><span><i
class="ri-download-line"></i>{{$.i18n.Tr "dataset.download"}}:{{.DownloadCount}}</span></div>
<a class="dataset_title title" href="{{.DownloadURL}}" title="{{.Name}}" style="border: none;">
{{.Name}}
</a>
</el-tooltip>
{{else}}
<el-tooltip class="item" effect="dark" placement="top" popper-class="diy-popper">
<div slot="content"><span><i
class="ri-download-line"></i>{{$.i18n.Tr "dataset.download"}}:{{.DownloadCount}}</span></div>
<a class="dataset_title title" href="{{.DownloadURL}}" title="{{.Name}}" style="border: none;">
{{.Name}}
</a>
<div slot="content"><span class="wrap">

{{if ne .DecompressState -1}}{{$.i18n.Tr "dataset.unzip_status"}}:{{if eq .DecompressState 1}}{{$.i18n.Tr "dataset.unzip_successed"}}{{else if eq .DecompressState 0 2}}{{$.i18n.Tr "dataset.unzip_stared"}}{{else}}{{$.i18n.Tr "dataset.unzip_failed"}}{{end}}
&nbsp;&nbsp;{{end}}<i
class="ri-download-line"></i>{{$.i18n.Tr "dataset.download"}}:{{.DownloadCount}}
{{if .Description}}&nbsp;&nbsp;{{$.i18n.Tr "dataset.description"}}:{{.Description}}{{end}}</span>
</div>
<div style="border: none;display: flex;align-items: center;max-width: 100%;">
{{if eq .DecompressState 1}}
<i class="ri-folder-open-line" style="color: #5bb973;"
title='{{$.i18n.Tr "dataset.unzip_successed"}}'></i>
{{else if eq .DecompressState 0 2}}
<i class="ri-folder-chart-2-line" style="color: #888888;"
title='{{$.i18n.Tr "dataset.unzip_stared"}}'></i>
{{else if eq .DecompressState 3}}
<i class="ri-folder-forbid-line" style="color: #101010;"
title='{{$.i18n.Tr "dataset.unzip_failed"}}'></i>
{{else}}
<i class="ri-folder-forbid-line" style="visibility: hidden;"
title='{{$.i18n.Tr "dataset.unzip_failed"}}'></i>
{{end}}
<a class="dataset_title title" href="{{.DownloadURL}}" title="{{.Name}}">
{{.Name}}
</a>
<i class="ri-lock-2-line" style="color: #fa8c16;" v-if="privates[{{$k}}]"></i>
</div>
</el-tooltip>
{{end}}
<i class="ri-lock-2-line" style="color: #fa8c16;" v-if="privates[{{$k}}]"></i>
<!-- <i class="COMPLETED" v-if="zipStatus[{{$k}}]==1"></i>
<i class="WAITING" v-if="zipStatus[{{$k}}]==2"></i>
<i class="FAILED" v-if="zipStatus[{{$k}}]==3"></i> -->
</div>
<div class="one wide column text center" style="width: 7.25% !important;">
{{.Size | FileSize}}
@@ -322,18 +329,6 @@
{{.CreatedUnix | TimeSinceUnix1}}
</div>
<div class="four wide column text right">
<!-- <el-button type="text">下载</el-button>
<el-button type="text">预览</el-button>
<el-button type="text">标注</el-button>
<el-button type="text">
<el-popover
placement="right"
width="400"
trigger="click">
<span>asdasd</span>
<el-button slot="reference" type="text"><i class="ri-more-line"></i></el-button>
</el-popover>
</el-button> -->
<div class="ui compact buttons">

<a class="ui basic blue button" href="{{.DownloadURL}}">{{$.i18n.Tr "dataset.download"}}</a>
@@ -350,11 +345,6 @@
@click="setPrivate('{{.UUID}}',true,{{$k}})"
v-else="privates[{{$k}}]">{{$.i18n.Tr "dataset.set_private"}}</span>
{{end}}
<!-- {{if $.CanRead}}
<a class="ui basic blue button" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'>标注</a>
{{else}}
<a class="ui basic disabled button">标注</a>
{{end}} -->
<a class="ui basic blue button">
<el-dropdown size="medium">
<span class="el-dropdown-link">
@@ -363,7 +353,6 @@
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="copyUrl('{{.DownloadURL}}')">{{$.i18n.Tr "dataset.copy_url"}}
</el-dropdown-item>
<!-- <el-dropdown-item class="clipboard" data-clipboard-text="{{.Md5}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_md5"}}</el-dropdown-item>-->
{{if and ($.CanWrite) (eq .DecompressState 1) }}
<el-dropdown-item @click.native="gotoAnnotate('{{$.RepoLink}}','{{.UUID}}',{{.Type}})">
{{$.i18n.Tr "dataset.annotation"}}</el-dropdown-item>


+ 12
- 0
templates/repo/header.tmpl View File

@@ -182,3 +182,15 @@


<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/es5-shim.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/marked.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/purify.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/ansi_up.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/prism.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/katex.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/katex-auto-render.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/notebook.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/notebook.min.js"></script>
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/katex.min.css" />
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/prism.css" />
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/notebook.css" />

+ 32
- 1
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -177,6 +177,12 @@
border: 1px solid #dfe1e6;
}

.ti-download-file {
display: flex;
align-items: center;
margin: 0.5rem 0;
}

.disabled {
cursor: default;
pointer-events: none;
@@ -220,6 +226,7 @@
<div class="active section">{{.displayJobName}}</div>
</div>
</h4>

{{range $k ,$v := .version_list_task}}
<div class="ui accordion border-according" id="accordion{{.VersionName}}"
data-repopath="{{$.RepoRelPath}}/modelarts/train-job" data-jobid="{{.JobID}}"
@@ -305,6 +312,7 @@
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item log_bottom" data-tab="second{{$k}}"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}">资源占用情况</a>
<a class="item" data-tab="third{{$k}}"
onclick="loadModelFile({{.VersionName}},'','','init')">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
@@ -478,7 +486,17 @@
</div>
</div>
<div class="ui tab" data-tab="second{{$k}}">
<div style="position: relative;">
<div>
<a id="{{.VersionName}}-log-down"
class='{{if and (.CanModify) (eq .Status "KILLED" "FAILED" "START_FAILED" "STOPPED" "COMPLETED") }}ti-download-file{{else}}disabled{{end}}'
href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/download_log_file?version_name={{.VersionName}}">
<i class="ri-download-cloud-2-line"></i>
<span style="margin-left: 0.3rem;">{{$.i18n.Tr "repo.modelarts.download_log"}}</span>
</a>

</div>
<div
style="position: relative;border: 1px solid rgba(0,0,0,.2);padding: 0 10px;margin-top: 10px;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;"
class="log_top" data-version="{{.VersionName}}"><i class="icon-to-top"></i></a>
@@ -501,6 +519,13 @@
</div>

</div>
<div class="ui tab" data-tab="four{{$k}}" style="position: relative;">
<i class="ri-refresh-line metric_chart"
style="position: absolute;right: 25%;color:#3291f8;z-index:99;cursor: pointer;"
data-version="{{.VersionName}}"></i>
<div id="metric-{{.VersionName}}" style="height: 260px;width: 870px;">
</div>
</div>
<div class="ui tab" data-tab="third{{$k}}">
<input type="hidden" name="model{{.VersionName}}" value="-1">
<input type="hidden" name="modelback{{.VersionName}}" value="-1">
@@ -709,6 +734,12 @@
// detail status and duration
$('#' + version_name + '-duration').text(data.JobDuration)
$('#' + version_name + '-status').text(data.JobStatus)
console.log(data)
if (["KILLED", "FAILED", "START_FAILED", "STOPPED", "COMPLETED"].includes(data.JobStatus)) {
$(`#${version_name}-log-down`).removeClass('disabled').addClass('ti-download-file')
$('#' + version_name + '-stop').addClass('disabled')
}

loadLog(version_name)




+ 203
- 112
templates/repo/modelmanage/index.tmpl View File

@@ -1,5 +1,10 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}
<style>
.inline .ui.dropdown .text {
color: rgba(0, 0, 0, .87) !important
}
</style>
<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
@@ -23,26 +28,29 @@
<div class="column"></div>
<div class="column right aligned">
<!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a>
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}"
onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a>
</div>
</div>
{{if eq $.MODEL_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a
href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>

</div>
<div style="display: none;">
<div id="model_list"></div>
</div>
</div>
<div style="display: none;">
<div id="model_list"></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
@@ -124,135 +132,218 @@
</div>
<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>

<div class="unite min_title inline field required">
<label>模型框架</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">

</div>
</div>

</div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
onkeydown="this.value=this.value.substring(0, 255)"
onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>

<div class="inline field" style="margin-left: 75px;">
<button id="submitId" type="button" class="ui create_train_job green button" style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}}
<button id="submitId" type="button" class="ui create_train_job green button"
style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}}
</button>
</div>
</form>
<div class="actions" style="display: inline-block;margin-left: 180px;">
<button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>


</div>
</div>


{{template "base/footer" .}}
{{template "base/footer" .}}

<script>
let repolink = {{.RepoLink}}
let repoId = {{$repository}}
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;
$('input[name="_csrf"]').val(csrf)
<script>
let repolink = {{.RepoLink }}
let repoId = {{ $repository }}
const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config;
$('input[name="_csrf"]').val(csrf)
let modelData;
function createModelName() {
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}
function showcreate(obj) {
$('.ui.modal.second')
.modal({
centered: false,
onShow: function () {
$('#model_header').text("导入新模型")
$('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
$("#job-name").empty()
createModelName()
loadTrainList()

function createModelName(){
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}
function showcreate(obj){
$('.ui.modal.second')
.modal({
centered: false,
onShow:function(){
$('#model_header').text("导入新模型")
$('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
$("#job-name").empty()
createModelName()
loadTrainList()
},
onHide: function () {
document.getElementById("formId").reset();
$('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear')
$('#choice_Engine').dropdown('clear')
$('.ui.dimmer').css({ "background-color": "" })
$('.ui.error.message').text()
$('.ui.error.message').css('display', 'none')

},
onHide:function(){
document.getElementById("formId").reset();
$('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear')
$('.ui.dimmer').css({"background-color":""})
$('.ui.error.message').text()
$('.ui.error.message').css('display','none')
}
})
.modal('show')
}

}
})
.modal('show')
}
$(function () {
$('#choice_model').dropdown({
onChange: function (value) {
$(".ui.dropdown.selection.search.width70").addClass("loading")
$('#choice_version').dropdown('clear')
$("#job-version").empty()
loadTrainVersion(value)
}
})

$(function(){
$('#choice_model').dropdown({
onChange:function(value){
$(".ui.dropdown.selection.search.width70").addClass("loading")
$('#choice_version').dropdown('clear')
$("#job-version").empty()
loadTrainVersion(value)
}
$('#choice_version').dropdown({
onChange: function (value) {
console.log("model version:" + value);
if (modelData != null) {
for (var i = 0; i < modelData.length; i++) {
if (modelData[i].VersionName == value) {
setEngine(modelData[i])
break;
}
}
}
}
})
})
})
function versionAdd(version){
let versionArray = version.split('.')
if(versionArray[2]=='9'){
if(versionArray[1]=='9'){
versionArray[0] = String(Number(versionArray[1])+1)
versionArray[1] = '0'
}else{
versionArray[1]=String(Number(versionArray[1])+1)
function versionAdd(version) {
let versionArray = version.split('.')
if (versionArray[2] == '9') {
if (versionArray[1] == '9') {
versionArray[0] = String(Number(versionArray[1]) + 1)
versionArray[1] = '0'
} else {
versionArray[1] = String(Number(versionArray[1]) + 1)
}
versionArray[2] = '0'
} else {
versionArray[2] = String(Number(versionArray[2]) + 1)
}
versionArray[2]='0'
}else{
versionArray[2]=String(Number(versionArray[2])+1)
return versionArray.join('.')
}
return versionArray.join('.')
}
function loadTrainList(){
$.get(`${repolink}/modelmanage/query_train_job?repoId=${repoId}`, (data) => {
function loadTrainList() {
$.get(`${repolink}/modelmanage/query_train_job?repoId=${repoId}`, (data) => {

const n_length = data.length
let train_html=''
for (let i=0;i<n_length;i++){
train_html += `<div class="item" data-value="${data[i].JobID}">${data[i].DisplayJobName}</div>`
train_html += '</div>'
}
$("#job-name").append(train_html)
$(".ui.dropdown.selection.search.width83").removeClass("loading")
$('#choice_model .default.text').text(data[0].DisplayJobName)
$('#choice_model input[name="JobId"]').val(data[0].JobID)
loadTrainVersion()
const n_length = data.length
let train_html = ''
for (let i = 0; i < n_length; i++) {
train_html += `<div class="item" data-value="${data[i].JobID}">${data[i].DisplayJobName}</div>`
train_html += '</div>'
}
$("#job-name").append(train_html)
$(".ui.dropdown.selection.search.width83").removeClass("loading")
$('#choice_model .default.text').text(data[0].DisplayJobName)
$('#choice_model input[name="JobId"]').val(data[0].JobID)
loadTrainVersion()

})
}
function loadTrainVersion(value){
let JobID = !value ?$('#choice_model input[name="JobId"]').val(): value
$.get(`${repolink}/modelmanage/query_train_job_version?JobID=${JobID}`, (data) => {
const n_length = data.length
let train_html=''
for (let i=0;i<n_length;i++){
train_html += `<div class="item" data-value="${data[i].VersionName}">${data[i].VersionName}</div>`
train_html += '</div>'
}
if(data.length){
$("#job-version").append(train_html)
$(".ui.dropdown.selection.search.width70").removeClass("loading")
$('#choice_version .default.text').text(data[0].VersionName)
$('#choice_version input[name="VersionName"]').val(data[0].VersionName)
}
})
}
function loadTrainVersion(value) {
let JobID = !value ? $('#choice_model input[name="JobId"]').val() : value
$.get(`${repolink}/modelmanage/query_train_job_version?JobID=${JobID}`, (data) => {
const n_length = data.length
let train_html = '';
modelData = data;
for (let i = 0; i < n_length; i++) {
train_html += `<div class="item" data-value="${data[i].VersionName}">${data[i].VersionName}</div>`
train_html += '</div>'
}
if (data.length) {
$("#job-version").append(train_html)
$(".ui.dropdown.selection.search.width70").removeClass("loading")
var versionName = data[0].VersionName;
if (versionName == null || versionName == "") {
versionName = "V0001";
}
$('#choice_version .default.text').text(versionName)
$('#choice_version input[name="VersionName"]').val(versionName)
console.log("1111111111");
setEngine(data[0])
}

})
}
</script>
})
}

function setEngine(modelVersion) {
console.log("modelVersion=" + modelVersion);
$('#choice_Engine').dropdown('clear')
$("#job-Engine").empty()
if (modelVersion.EngineName != null && modelVersion.EngineName != "") {
srcEngine = modelVersion.EngineName.split('-')[0]
srcEngine = srcEngine.trim();
let selectedText = "Pytorch";
let selectedValue = 0;
let itemHtml = "<option class=\"item\" data-value=\"0\">Pytorch</option>";
if (srcEngine == 'TensorFlow') {
selectedText = "TensorFlow";
selectedValue = 1;
itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>";
} else {
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>";
}
if (srcEngine == 'MindSpore') {
selectedText = "MindSpore";
selectedValue = 2;
itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>";
} else {
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>";
}
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"

$('#choice_Engine .default.text').text(selectedText)
$('#choice_Engine input[name="Engine"]').val(selectedValue)
$("#job-Engine").append(itemHtml);
$("#choice_Engine").addClass('disabled')
} else {
let itemHtml = "<option class=\"active item\" data-value=\"0\">Pytorch</option>";
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"
$('#choice_Engine .default.text').text("Pytorch");
$('#choice_Engine input[name="Engine"]').val(0)
$("#job-Engine").append(itemHtml);
$("#choice_Engine").removeClass('disabled');
}
}
</script>

+ 14
- 3
templates/repo/modelmanage/showinfo.tmpl View File

@@ -141,7 +141,7 @@
<td class="ti-text-form-content word-elipsis"><span id="Parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</td>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_Engine"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="EngineName" title=""></span></td>
</tr>
<tr>
@@ -191,7 +191,6 @@
</div>
</div>
</div>
</div>
</div>
@@ -232,13 +231,25 @@ function loadInfo(){
renderInfo(initObj,initModelAcc,id)
loadModelFile(data[0].ID,data[0].Version,'','','init')
})
}
function getEngineName(model){
if(model.Engine == 0){
return "Pytorch";
}else if(model.Engine == 1 || model.Engine == 121){
return "TensorFlow";
}else if(model.Engine == 2 || model.Engine == 122){
return "MindSpore";
}else{
return "Other"
}
}
function transObj(data){
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy,CodeBranch,CodeCommitID,TrainTaskInfo} = data[0]
let modelAcc = JSON.parse(Accuracy)
TrainTaskInfo = JSON.parse(TrainTaskInfo)
// Parameters = JSON.parse(Parameters)
let {Parameters,EngineName} = TrainTaskInfo
let {Parameters} = TrainTaskInfo
let EngineName = getEngineName(data[0])
Parameters = JSON.parse(Parameters)
Parameters = Parameters.parameter.length === 0 ? '--':Parameters.parameter
let size = tranSize(Size)


+ 14
- 0
templates/repo/view_file.tmpl View File

@@ -108,6 +108,8 @@
<tr>
{{if .IsFileTooLarge}}
<td><strong>{{.i18n.Tr "repo.file_too_large"}}</strong></td>
{{else if .IsNoteBook}}
<td id="notebook"></td>
{{else}}
<td class="lines-num">{{.LineNums}}</td>
<td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol class="linenums">{{.FileContent}}</ol></code></pre></td>
@@ -128,4 +130,16 @@ function submitDeleteForm() {
$("#delete-file-form").submit()
}
}
function showNoteBook(){
var isNoteBook = {{.IsNoteBook}}
if (isNoteBook) {
var jsonStr = "{{.FileContent}}"
var notebook = nb.parse(JSON.parse(jsonStr));
var rendered = notebook.render();
$("#notebook").append(rendered);
Prism.highlightAll();
}
}
showNoteBook()

</script>

+ 4
- 11
templates/user/dashboard/dashboard.tmpl View File

@@ -10,9 +10,9 @@
{{.i18n.Tr "home.wecome_AI_plt"}}
</div>
<div class="content">
<p >{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p>
<p >{{.i18n.Tr "home.use_plt__fuction"}}&nbsp;<a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p>
<p > {{.i18n.Tr "home.provide_resoure"}}</p>
<p class="ui text grey">{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p>
<p><span class="ui text grey">{{.i18n.Tr "home.use_plt__fuction"}}</span>&nbsp;<a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p>
<p class="ui text grey">{{.i18n.Tr "home.provide_resoure"}}</p>
</div>
<div class="guide ">
<a class="mini ui blue basic button" style="font-weight:700" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}} <i class="ri-arrow-right-line" ></i></a>
@@ -66,19 +66,12 @@
}
.w_title{
padding-top: 25px;
margin-bottom: 20px;
color: rgba(16, 16, 16, 100);
font-size: 20px;
text-align: left;
font-weight: 700;
}
.content{
color: rgba(80, 85, 89, 100);
font-size: 14px;
text-align: left;
font-family: SourceHanSansSC-regular;
margin-top: 20px;
}

.guide{
margin-top:30px;
padding-bottom: 30px;


+ 1
- 1
templates/user/dashboard/feeds.tmpl View File

@@ -6,7 +6,7 @@
<div class="ui grid">
<div class="ui fourteen wide column">
<div class="{{if or (eq .GetOpType 5) (eq .GetOpType 18)}}push news{{end}}">
<p>
<p class="text truncate">
{{if gt .ActUser.ID 0}}
<a href="{{AppSubUrl}}/{{.GetActUserName}}" title="{{.GetDisplayNameTitle}}">{{.GetDisplayName}}</a>
{{else}}


+ 16
- 3
web_src/js/components/Model.vue View File

@@ -60,7 +60,7 @@
</el-table-column>
<el-table-column
prop="EngineName"
label="AI引擎"
label="模型框架"
align="center"
min-width="8.5%"
>
@@ -168,7 +168,7 @@ export default {
tableData= res.data
for(let i=0;i<tableData.length;i++){
TrainTaskInfo = JSON.parse(tableData[i].TrainTaskInfo)
tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0]
tableData[i].EngineName = this.getEngineName(tableData[i])
tableData[i].ComputeResource = TrainTaskInfo.ComputeResource
tableData[i].cName=tableData[i].Name
tableData[i].Name=''
@@ -218,6 +218,7 @@ export default {
$('input[name="Name"]').removeAttr('readonly')
$('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear')
$('#choice_Engine').dropdown('clear')
$('.ui.dimmer').css({"background-color":""})
$('.ui.error.message').text()
$('.ui.error.message').css('display','none')
@@ -347,6 +348,18 @@ export default {
})
.modal('show')
},
getEngineName(model){
if(model.Engine == 0){
return "Pytorch";
}else if(model.Engine == 1 || model.Engine == 121){
return "TensorFlow";
}else if(model.Engine == 2 || model.Engine == 122){
return "MindSpore";
}else{
return "Other"
}

},
getModelList(){
try {
this.$refs.table.store.states.lazyTreeNodeMap = {}
@@ -360,7 +373,7 @@ export default {
for(let i=0;i<this.tableData.length;i++){
TrainTaskInfo = JSON.parse(this.tableData[i].TrainTaskInfo)
this.tableData[i].cName=this.tableData[i].Name
this.tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0]
this.tableData[i].EngineName = this.getEngineName(this.tableData[i])
this.tableData[i].ComputeResource = TrainTaskInfo.ComputeResource
this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true
}


+ 109
- 3
web_src/js/index.js View File

@@ -1214,7 +1214,7 @@ async function initRepository() {
files: $attachments
},
(data) => {
if (data.length === 0) {
if (data.length === 0 || data.content === '') {
$renderContent.html($('#no-content').html());
} else {
$renderContent.html(data.content);
@@ -1222,10 +1222,18 @@ async function initRepository() {
highlight(this);
});
}
let imageShow = ''
const $content = $segment.parent();
if (!$content.find('.ui.small.images').length) {
if (data.attachments !== '') {

if (data.attachments !== '' && data.attachments) {
if ($content.find('.ui.middle.aligned').length === 0) {
imageShow += '<div class="ui clearing divider"></div>'
imageShow += '<div class="ui middle aligned padded grid">'
imageShow += data.attachments
imageShow += '</div>'
$content.find('.ui.attached.segment').append(imageShow)
}
else { $content.find('.ui.middle.aligned').html(data.attachments) }
}
} else if (data.attachments === '') {
$content
@@ -5070,3 +5078,101 @@ function initcreateRepo() {
}

initcreateRepo()


function initChartsNpu() {
const url = window.location.href
const urlArr = url.split('/')
let userName = urlArr.slice(-5)[0]
let repoPath = urlArr.slice(-4)[0]
let jobID = urlArr.slice(-1)[0]


let options = {
legend: {
data: []
},
grid: {
top: '35%',
bottom: '2%',
x: '2%',
containLabel: true
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgb(51, 56, 84)',
borderColor: 'rgb(51, 51, 51)',
borderWidth: 0,
textStyle: {
color: '#fff'
},
axisPointer: {
type: 'line'
}
},
xAxis: {
type: 'category',
data: [],
boundaryGap: false,
axisLabel: {
interval: 'auto'
},
name: '时间(min)'
},
yAxis: {

show: true,
name: '占有率(%)',
axisLine: {
show: true
},
axisTick: { show: true }
},

series: []
};
const sortBy = (arr, k) => arr.concat().sort((a, b) => (a[k] > b[k] ? 1 : a[k] < b[k] ? -1 : 0));
$('.metric_chart').click(function (e) {
let versionName = $(this).data('version')
let myCharts = echarts.init(document.getElementById(`metric-${versionName}`))
$.get(`${window.config.AppSubUrl}/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/metric_statistics?version_name=${versionName}&statistic_type=each&metrics=`, (res) => {
let filterDta = res.MetricsInfo.filter((item) => {

return !(['recvBytesRate', 'diskWriteRate', 'sendBytesRate', 'diskReadRate'].includes(item.metric))
})
filterDta = sortBy(filterDta, "metric")
let legenData = filterDta.map((item) => {
return item.metric
})
let seriesData = filterDta.map((item) => {
let value = item.value.map((item) => { return item > 0 ? item : '0' })
let seriesOption = {
name: item.metric,
type: 'line',
symbol: 'circle',
symbolSize: 10,
smooth: true,
showSymbol: false,
lineStyle: {
width: 2,
shadowColor: 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetY: 8
},
data: value
}
return seriesOption
})
let xLength = res.MetricsInfo[0].value.length
options.xAxis.data = Array.from({ length: xLength }, (_, index) => index)
options.legend.data = legenData
options.series = seriesData
options && myCharts.setOption(options);

})
options && myCharts.setOption(options);

})
}

initChartsNpu()

+ 4
- 0
web_src/less/_dashboard.less View File

@@ -82,6 +82,10 @@

line-height: 1.2;

p {
max-width: 100%;
}
> .ui.grid {
margin-left: auto;
margin-right: auto;


Loading…
Cancel
Save