Browse Source

Merge remote-tracking branch 'origin/V20221214' into zouap_static

pull/3373/head
zouap 2 years ago
parent
commit
422266ca79
100 changed files with 5530 additions and 881 deletions
  1. +16
    -9
      custom/public/css/git.openi.css
  2. BIN
      custom/public/img/home-banner-01-en.jpg
  3. BIN
      custom/public/img/home-banner-01.jpg
  4. BIN
      custom/public/img/home-bg-ps.png
  5. +1
    -0
      custom/public/img/logo-footer.svg
  6. +45
    -1
      custom/public/img/logo-w.svg
  7. BIN
      custom/public/rotation3D/img/baseimg.png
  8. +4
    -4
      index.html
  9. +41
    -5
      models/ai_model_manage.go
  10. +183
    -6
      models/cloudbrain.go
  11. +89
    -36
      models/cloudbrain_static.go
  12. +14
    -6
      models/dataset.go
  13. +1
    -1
      models/repo.go
  14. +5
    -1
      models/repo_activity_custom.go
  15. +30
    -3
      models/repo_watch.go
  16. +102
    -0
      models/resource_specification.go
  17. +1
    -1
      models/user.go
  18. +17
    -0
      models/user_analysis_for_activity.go
  19. +20
    -3
      models/user_business_analysis.go
  20. +1
    -0
      models/user_invitation.go
  21. +21
    -0
      models/user_mail.go
  22. +4
    -0
      modules/auth/user_form.go
  23. +20
    -4
      modules/cloudbrain/cloudbrain.go
  24. +1
    -0
      modules/context/repo.go
  25. +1
    -0
      modules/convert/cloudbrain.go
  26. +17
    -2
      modules/cron/tasks_basic.go
  27. +2
    -5
      modules/grampus/grampus.go
  28. +94
    -8
      modules/modelarts/modelarts.go
  29. +1
    -1
      modules/modelarts/resty.go
  30. +8
    -45
      modules/modelarts_cd/modelarts.go
  31. +1
    -1
      modules/repository/hooks.go
  32. +86
    -14
      modules/setting/setting.go
  33. +8
    -0
      modules/structs/cloudbrain.go
  34. +23
    -0
      modules/structs/pipeline.go
  35. +1
    -0
      modules/structs/tagger.go
  36. +3
    -0
      modules/templates/helper.go
  37. +43
    -8
      options/locale/locale_en-US.ini
  38. +41
    -7
      options/locale/locale_zh-CN.ini
  39. +374
    -56
      public/home/home.js
  40. +1
    -1
      public/img/search.svg
  41. +6
    -2
      routers/admin/cloudbrains.go
  42. +17
    -0
      routers/api/v1/api.go
  43. +15
    -0
      routers/api/v1/notify/pipeline.go
  44. +124
    -9
      routers/api/v1/repo/cloudbrain.go
  45. +213
    -98
      routers/api/v1/repo/cloudbrain_dashboard.go
  46. +14
    -0
      routers/api/v1/repo/mlops.go
  47. +5
    -2
      routers/api/v1/repo/modelarts.go
  48. +20
    -0
      routers/api/v1/repo/modelmanage.go
  49. +58
    -15
      routers/home.go
  50. +1
    -0
      routers/private/internal.go
  51. +39
    -9
      routers/repo/ai_model_convert.go
  52. +147
    -42
      routers/repo/ai_model_manage.go
  53. +4
    -5
      routers/repo/aisafety.go
  54. +24
    -53
      routers/repo/cloudbrain.go
  55. +172
    -74
      routers/repo/cloudbrain_statistic.go
  56. +2
    -4
      routers/repo/grampus.go
  57. +47
    -20
      routers/repo/modelarts.go
  58. +3
    -1
      routers/repo/repo.go
  59. +6
    -0
      routers/repo/user_data_analysis.go
  60. +6
    -3
      routers/repo/user_invitation.go
  61. +5
    -2
      routers/routes/routes.go
  62. +2
    -1
      routers/user/Invitation.go
  63. +29
    -1
      routers/user/auth.go
  64. +4
    -0
      routers/user/home.go
  65. +151
    -0
      services/cloudbrain/clear.go
  66. +362
    -0
      services/cloudbrain/cloudbrainTask/notebook.go
  67. +16
    -7
      services/cloudbrain/cloudbrainTask/sync_status.go
  68. +12
    -0
      services/cloudbrain/cloudbrainTask/train.go
  69. +2
    -46
      services/cloudbrain/resource/resource_specification.go
  70. +72
    -7
      services/cloudbrain/util.go
  71. +6
    -10
      services/repository/repository.go
  72. +8
    -6
      templates/admin/cloudbrain/list.tmpl
  73. +4
    -6
      templates/admin/cloudbrain/search.tmpl
  74. +4
    -6
      templates/admin/cloudbrain/search_dashboard.tmpl
  75. +47
    -7
      templates/base/footer_content.tmpl
  76. +2
    -2
      templates/base/footer_content_fluid.tmpl
  77. +1
    -0
      templates/base/head.tmpl
  78. +1
    -0
      templates/base/head_home.tmpl
  79. +42
    -21
      templates/base/head_navbar.tmpl
  80. +1
    -1
      templates/base/head_navbar_fluid.tmpl
  81. +1
    -1
      templates/base/head_navbar_home.tmpl
  82. +1
    -1
      templates/base/head_navbar_pro.tmpl
  83. +1
    -1
      templates/base/head_notice.tmpl
  84. +36
    -0
      templates/custom/home/home_activity.tmpl
  85. +85
    -0
      templates/custom/home/home_dataset.tmpl
  86. +20
    -0
      templates/custom/home/home_org.tmpl
  87. +21
    -0
      templates/custom/home/home_repo.tmpl
  88. +2079
    -0
      templates/custom/home/home_top.tmpl
  89. +134
    -0
      templates/custom/home/home_user_experience.tmpl
  90. +7
    -7
      templates/explore/repo_orgtop.tmpl
  91. +5
    -5
      templates/explore/repo_right.tmpl
  92. +1
    -3
      templates/explore/repos.tmpl
  93. +27
    -89
      templates/home.tmpl
  94. +81
    -0
      templates/notice.tmpl
  95. +2
    -2
      templates/org/home_courses.tmpl
  96. +10
    -10
      templates/repo/cloudbrain/benchmark/new.tmpl
  97. +1
    -1
      templates/repo/cloudbrain/inference/new.tmpl
  98. +2
    -72
      templates/repo/cloudbrain/inference/show.tmpl
  99. +1
    -0
      templates/repo/cloudbrain/show.tmpl
  100. +1
    -1
      templates/repo/cloudbrain/trainjob/new.tmpl

+ 16
- 9
custom/public/css/git.openi.css View File

@@ -72,9 +72,7 @@
z-index: 10;
}
.ui.secondary.c2net.segment{
/* background: #f8faff;
border: none;*/
margin-bottom: 5em;
padding-bottom: 3em;
padding-top: 2em;
color: rgba(0,0,0,.87);
background-image: linear-gradient(to bottom left,var(--tw-gradient-stops));
@@ -176,7 +174,7 @@
}
.homeorg, .homepro, .homemodel, .i-env{
position: relative;
padding-bottom: 5em;
padding-bottom: 3em;
}
.homenews::before{
content: '';
@@ -203,7 +201,7 @@
padding: 0;
}
.newslist{
height: 300px;
height: 260px;
overflow: hidden;
}

@@ -278,7 +276,7 @@
z-index: 9;
}
.homeorg-list .card{
background-image: linear-gradient(#FFF, #FFF 60%, #DFF0EF) !important;
/* background-image: linear-gradient(#FFF, #FFF 60%, #DFF0EF) !important; */
box-shadow: none !important;
}
.homeorg-list .card .ui.small.header .content{
@@ -299,7 +297,7 @@
background-color: #FFF;
box-shadow: 0px 5px 10px 0px rgba(105, 192, 255, .3);
border: 1px solid rgba(105, 192, 255, .4);
min-height: 10.8em;
/* min-height: 10.8em; */
}
.homepro-list .ui.card>.content>.header{
line-height: 40px !important;
@@ -307,7 +305,7 @@

.homepro-list .swiper-pagination-bullet-active, .homeorg-list .swiper-pagination-bullet-active{
width: 40px;
border-radius: 4px;
border-radius: 4px;
}
.i-env > div{
position: relative;
@@ -317,6 +315,15 @@
}

@media only screen and (max-width: 767px) {
.mobile-margin-left-20 {
margin-left: 20px !important;
}
.mobile-text-align-center {
text-align: center !important;
}
.mobile-justify-content-center {
justify-content: center !important;
}
.am-mt-30{ margin-top: 1.5rem !important;}
.ui.secondary.hometop.segment{
margin-bottom: 5.0rem;
@@ -341,7 +348,7 @@
background: #FFF;
}
.homeorg{
padding-left: 3.5em;
/* padding-left: 3.5em; */
}
.homeorg-tit::after {
left: -2.3em;


BIN
custom/public/img/home-banner-01-en.jpg View File

Before After
Width: 1920  |  Height: 580  |  Size: 180 kB

BIN
custom/public/img/home-banner-01.jpg View File

Before After
Width: 1920  |  Height: 580  |  Size: 174 kB

BIN
custom/public/img/home-bg-ps.png View File

Before After
Width: 681  |  Height: 800  |  Size: 62 kB

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


+ 45
- 1
custom/public/img/logo-w.svg View File

@@ -1 +1,45 @@
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 50"><defs><style>.cls-1{fill:#5bb973;}.cls-2{fill:#fff;}</style></defs><title>logo-w</title><path class="cls-1" d="M42.08,12.13l-15.65-9a4.44,4.44,0,0,0-4.43,0l-15.65,9A4.44,4.44,0,0,0,4.13,16V34a4.44,4.44,0,0,0,2.22,3.84l3.83,2.21a2.88,2.88,0,0,0-.06.59,2.95,2.95,0,1,0,1-2.17L7.26,36.3A2.63,2.63,0,0,1,6,34V16A2.62,2.62,0,0,1,7.26,13.7l15.65-9a2.59,2.59,0,0,1,2.61,0l15.65,9A2.63,2.63,0,0,1,42.47,16V34a2.64,2.64,0,0,1-1.3,2.27l-15.65,9a3.16,3.16,0,0,1-.5.22V39.88a1.31,1.31,0,0,0,0-.28V36.35l.1,0,9-6a.92.92,0,0,0,.41-.75V20a3,3,0,1,0-1.82,0v9L25,34.18V15.94a3,3,0,1,0-1.82,0v12l-5.08-2.95V20.19a3,3,0,1,0-1.82,0v5.26a.9.9,0,0,0,.45.79L23.2,30v8.16L12.11,31.73V23.84a2.93,2.93,0,1,0-1.82,0v8.41a.94.94,0,0,0,.46.79l12.45,7.2v6.34a.22.22,0,0,0,0,.08v.09l0,.1s0,0,0,.07l.06.1s0,0,0,0l.08.1,0,0a.39.39,0,0,0,.1.08l0,0,.12.07,0,0,.14,0h0a.39.39,0,0,0,.15,0h.16a4.44,4.44,0,0,0,2.22-.59l15.65-9A4.46,4.46,0,0,0,44.29,34V16a4.45,4.45,0,0,0-2.21-3.83m-29,27.42a1.12,1.12,0,1,1-1.12,1.12,1.12,1.12,0,0,1,1.12-1.12m20.6-23.46a1.12,1.12,0,1,1-1.12,1.12,1.12,1.12,0,0,1,1.12-1.12m-16.45.19a1.12,1.12,0,1,1-1.12,1.12,1.12,1.12,0,0,1,1.12-1.12m-6,3.65a1.12,1.12,0,1,1-1.12,1.12,1.12,1.12,0,0,1,1.12-1.12M24.13,12A1.12,1.12,0,1,1,23,13.14,1.12,1.12,0,0,1,24.13,12"/><path class="cls-2" d="M81.68,26.69H67.86c-2,.1-3.06,1-3.06,2.85v6.33c.1,1.68,1.16,2.53,3.06,2.63H81.57c1.9-.1,2.85-1,3-2.74V29.54A2.71,2.71,0,0,0,81.68,26.69Zm-.53,8c-.11.73-.53,1.16-1.48,1.26H69.54c-1-.21-1.37-.53-1.47-1.26V30.59a1.44,1.44,0,0,1,1.47-1.48h10a1.54,1.54,0,0,1,1.58,1.48Z"/><path class="cls-2" d="M63.21,20.57V17A1.63,1.63,0,0,1,64.8,15.4H79.25c1.06-.11,1.58.42,1.58,1.37V19.3c0,.85-.52,1.27-1.47,1.27H64.59V23H81.47c1.79,0,2.74-.85,2.74-2.43V15.72A2.45,2.45,0,0,0,81.47,13H74.08V11H70.6v2H62.69c-2,0-3,.95-3,3v9.39a42.65,42.65,0,0,1-2,13l3.27.64a43.43,43.43,0,0,0,2.11-13V20.57Z"/><path class="cls-2" d="M90,24.47l3.38,1.8a10.1,10.1,0,0,0,3.9-5.81h5.91V18H97.82a25.57,25.57,0,0,0,.21-3h5V12.55H93.7V11H90.22v4h4.43a17.38,17.38,0,0,1-.21,2.95H89.38v2.53h4.43A7.05,7.05,0,0,1,90,24.47Z"/><path class="cls-2" d="M97.82,21.62A21.82,21.82,0,0,1,100,26.05h3.7a25.8,25.8,0,0,0-2.22-4.43Z"/><path class="cls-2" d="M112.17,26.79H93.39c-1.8.21-2.85,1.06-3,2.64v4.75H112v1c0,.85-.52,1.27-1.58,1.27h-15c-1,0-1.48-.42-1.48-1.16H90.54v1A2.75,2.75,0,0,0,93.18,39h19.09c2-.1,3.06-1,3.06-2.64V29.54A3.21,3.21,0,0,0,112.17,26.79Zm-.32,4.86h-18V30.8a1.43,1.43,0,0,1,1.48-1.47h15c1,0,1.58.52,1.58,1.47Z"/><path class="cls-2" d="M113.64,12h-6.22q-2.53.17-2.85,2.22V23.1a2.33,2.33,0,0,0,2.32,2.22h6.65c1.47-.11,2.32-.85,2.32-2.22V14.24C116,13,115.23,12.23,113.64,12Zm-1,9.29c0,1.05-.53,1.58-1.48,1.58h-1.79A1.39,1.39,0,0,1,108,21.31V16a1.42,1.42,0,0,1,1.47-1.47H111A1.53,1.53,0,0,1,112.59,16Z"/></svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.3.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 160 64" style="enable-background:new 0 0 160 64;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{display:none;fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M105.3,33.3H87.1c-2.6,0.1-4,1.3-4,3.8v8.3c0.1,2.2,1.5,3.3,4,3.5h18c2.5-0.1,3.8-1.3,3.9-3.6v-8.2
c0.1-2-1.4-3.6-3.4-3.8C105.6,33.3,105.4,33.3,105.3,33.3z M104.6,43.9c-0.1,1-0.7,1.5-1.9,1.7H89.3c-1.3-0.3-1.8-0.7-1.9-1.7v-5.4
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0h13.1c1.1,0,2,0.8,2.1,2L104.6,43.9z"/>
<path class="st0" d="M81,25.3v-4.7c0-1.1,0.9-2.1,2.1-2.1h19c1.4-0.1,2.1,0.5,2.1,1.8v3.3c0,1.1-0.7,1.7-1.9,1.7H82.8v3.2H105
c2.3,0,3.6-1.1,3.6-3.2v-6.4c0.2-1.8-1.1-3.4-2.8-3.6c-0.3,0-0.5,0-0.8,0h-9.7v-2.6h-4.6v2.6H80.3c-2.6,0-3.9,1.2-3.9,3.9v12.3
c0,5.8-0.9,11.6-2.6,17.1l4.3,0.8c1.8-5.5,2.7-11.3,2.8-17.1v-7.2H81z"/>
<path class="st0" d="M116.2,30.4l4.4,2.4c2.6-1.9,4.4-4.6,5.1-7.6h7.8v-3.2h-7.1c0.2-1.3,0.3-2.6,0.3-3.9h6.6v-3.2h-12.3v-2h-4.6
V18h5.8c0,1.3-0.1,2.6-0.3,3.9h-6.7v3.3h5.8C120.4,27.5,118.6,29.4,116.2,30.4z"/>
<path class="st0" d="M126.5,26.7c1.2,1.8,2.1,3.8,2.9,5.8h4.9c-0.8-2-1.8-4-2.9-5.8H126.5z"/>
<path class="st0" d="M145.4,33.5h-24.7c-2.4,0.3-3.8,1.4-3.9,3.5v6.2h28.4v1.3c0,1.1-0.7,1.7-2.1,1.7h-19.7c-1.3,0-1.9-0.5-1.9-1.5
h-4.5V46c0,1.9,1.6,3.5,3.5,3.6h25.1c2.6-0.1,4-1.3,4-3.5v-9C149.2,35,147.5,33.5,145.4,33.5z M145,39.9h-23.7v-1.1
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0H143c1.3,0,2.1,0.7,2.1,1.9L145,39.9z"/>
<path class="st0" d="M147.3,14h-8.2c-2.2,0.1-3.5,1.1-3.8,2.9v11.7c0.1,1.6,1.4,2.9,3.1,2.9h8.7c1.9-0.1,3.1-1.1,3.1-2.9V17
C150.4,15.4,149.4,14.3,147.3,14z M146,26.2c0,1.4-0.7,2.1-1.9,2.1h-2.4c-1,0-1.8-0.8-1.8-1.8c0-0.1,0-0.1,0-0.2v-7
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0h2c1.1,0,2.1,0.8,2.1,1.9l0,0L146,26.2z"/>
</g>
<path class="st1" d="M67.2,44.1V20c0-2.6-1.4-5.1-3.7-6.4l-20.9-12c-2.3-1.3-5.1-1.3-7.4,0l-20.9,12c-2.3,1.3-3.7,3.8-3.7,6.4v24.1
c0,2.6,1.4,5.1,3.7,6.4l20.9,12c2.3,1.3,5.1,1.3,7.4,0l20.9-12C65.8,49.2,67.2,46.7,67.2,44.1z"/>
<path class="st0" d="M61.9,15.4L42,3.9c-1.9-1.1-4.3-1.1-6.2,0L15.9,15.4c-1.9,1.1-3.1,3.2-3.1,5.4v22.9c0,2.2,1.2,4.3,3.1,5.4
l3.8,2c0.8,0.4,0.8,1,0.8,1.9c0,0,0,0.1,0,0.1c0.1,1.6,1.8,3.5,4.2,3.5c2.3,0,4.3-1.9,4.4-4.2c0-1.6-0.8-3.1-2.3-3.9
c-0.6-0.3-1.7-0.5-2.9-0.4c-0.9,0.1-1,0.6-2.8-0.5l-2.8-1.6c-0.8-0.5-1.7-1.3-1.6-2.3V22c0-1.8,0.8-2.8,2.1-3.5L37,7.8
C38.1,7,40.2,7.2,41.5,8l16.4,9.5c2.9,1.6,3,3,3,4v19.7c0,2.3-1.5,4-2.3,4.5l-15.1,8.5C42.8,54.5,42,54,42,53.3l0-2.5
c0-0.1,0-0.3,0-0.4v-2.5c0-0.8,0.4-1.6,1.1-2l8.8-5.7c1.4-0.9,2-1.7,2-3.8L53.7,28c0-1,0.4-1.9,1.2-2.5c1.5-1.3,2-3.7,0.8-5.6
c-0.8-1.4-2.4-2.2-4-2c-1.6,0.1-2.8,1-3.5,2.4c-0.5,1-0.6,2.2-0.3,3.3c0.2,0.8,0.7,1.4,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5v7.2
c0,1.1-0.5,2.1-1.5,2.7l-5.5,2.8c-0.7,0.5-1.6,0-1.6-0.8l-0.2-17.1c0-1,0.5-1.9,1.2-2.5c0.4-0.3,0.7-0.8,1-1.3
c0.7-1.3,0.7-2.9-0.1-4.3c-0.8-1.4-2.5-2.2-4.1-2.1c-2.9,0.3-4.6,3.1-3.8,5.7c0.2,0.8,0.7,1.4,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5v9.9
c0,0.8-0.8,1.3-1.5,0.9L34,32.5c-0.7-0.4-1.2-1.2-1.2-2.1v-2.2c0-1,0.4-1.9,1.2-2.5c1.5-1.3,2-3.7,0.8-5.6c-0.8-1.3-2.4-2.1-4-2
c-2.9,0.2-4.7,3.1-3.8,5.7c0.2,0.8,0.7,1.5,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5l0,3.5c0,1,0,2,1.6,3.1l5.5,3c0.7,0.4,1.2,1.2,1.2,2.1v4.5
c0,0.8-0.8,1.3-1.5,0.9L26.6,41c-0.7-0.4-1.2-1.2-1.2-2.1l-0.2-6.1c0-1,0.4-1.8,1.1-2.5c1.4-1.3,1.9-3.4,0.9-5.3
c-0.8-1.4-2.4-2.3-4-2.2c-2.9,0.2-4.6,3-3.8,5.6c0.2,0.7,0.7,1.4,1.2,1.9c0.7,0.6,1.1,1.5,1.1,2.5l-0.5,6.8c0,1.9,0.3,2.8,1.8,3.5
l11.8,6.3c1,0.6,1.6,1.7,1.6,2.8l0,3.1c0,3.1,4.3,5.7,8.7,3.3l16.4-9.8c1.9-1,3.2-3,3.4-5.2V20.7C65,18.5,63.8,16.5,61.9,15.4z
M24.2,50.7c1.1,0,2,0.9,2,2c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2C22.2,51.7,23.1,50.7,24.2,50.7z M48.7,21.5c0-1.1,0.9-2,2-2
s2,0.9,2,2c0,1.1-0.9,2-2,2S48.7,22.6,48.7,21.5z M30.6,23.8c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S31.8,23.8,30.6,23.8z
M22.2,26.4c0-1.1,0.9-2,2-2c1.1,0,2,0.9,2,2s-0.9,2-2,2C23.1,28.4,22.2,27.5,22.2,26.4z M40,17.9c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2
c1.1,0,2,0.9,2,2C42,17,41.1,17.9,40,17.9z"/>
</svg>

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

Before After
Width: 976  |  Height: 850  |  Size: 353 kB

+ 4
- 4
index.html View File

@@ -107,7 +107,7 @@
<meta property="og:title" content="OpenI">
<meta property="og:type" content="website" />
<meta property="og:image" content="/img/gitea-lg.png" />
<meta property="og:url" content="https://git.openi.org.cn/" />
<meta property="og:url" content="https://openi.pcl.ac.cn/" />
<meta property="og:description" content="Efficient code management center, you can host and review code">

<meta property="og:site_name" content="OpenI" />
@@ -250,7 +250,7 @@ var _hmt = _hmt || [];
<a href=https://git.openi.org.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md class="a_width" target="_blank">
<a href=https://openi.pcl.ac.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md class="a_width" target="_blank">
<i class="ri-arrow-right-s-line"></i>
7月中下旬登录启智AI协作平台,需登记手机号码啦&gt;&gt;&gt;
</a>
@@ -308,7 +308,7 @@ var _hmt = _hmt || [];
isNewNotice=false;
}
let isShowNoticeTag = false;
let notices= [{"Title":"“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/notices_0701/636.html","Visible":1},{"Title":"7月中下旬登录启智AI协作平台,需登记手机号码啦\u003e\u003e\u003e","Link":"https://git.openi.org.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md","Visible":1},{"Title":"智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/dongtai_0628/634.html","Visible":1},{"Title":"启智AI协作平台问卷调查,邀请您参加\u003e\u003e\u003e","Link":"https://wj.qq.com/s2/10362208/5c0c","Visible":1}]
let notices= [{"Title":"“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/notices_0701/636.html","Visible":1},{"Title":"7月中下旬登录启智AI协作平台,需登记手机号码啦\u003e\u003e\u003e","Link":"https://openi.pcl.ac.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md","Visible":1},{"Title":"智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/dongtai_0628/634.html","Visible":1},{"Title":"启智AI协作平台问卷调查,邀请您参加\u003e\u003e\u003e","Link":"https://wj.qq.com/s2/10362208/5c0c","Visible":1}]
if(notices != null && notices!=''){
for (i =0;i<notices.length;i++){
if (notices[i].Visible==1){
@@ -604,7 +604,7 @@ var _hmt = _hmt || [];
</div>
</div>

<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">Tutorial</p> </a>
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">Tutorial</p> </a>
<a href="/api/swagger" class=" item a_margin"><i class="ri-exchange-line footer_icon" > </i><p class="footer_icon">API</p> </a>
<a href="/user/login" class=" item a_margin" ><i class="ri-mail-send-line footer_icon" ></i><p class="footer_icon">Feedback</p></a>


+ 41
- 5
models/ai_model_manage.go View File

@@ -33,6 +33,7 @@ type AiModelManage struct {
CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"`
CodeCommitID string `xorm:"NULL" json:"codeCommitID"`
UserId int64 `xorm:"NOT NULL" json:"userId"`
IsPrivate bool `xorm:"DEFAULT true" json:"isPrivate"`
UserName string `json:"userName"`
UserRelAvatarLink string `json:"userRelAvatarLink"`
TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"`
@@ -40,6 +41,7 @@ type AiModelManage struct {
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"`
IsCanOper bool `json:"isCanOper"`
IsCanDelete bool `json:"isCanDelete"`
IsCanDownload bool `json:"isCanDownload"`
}

type AiModelConvert struct {
@@ -84,8 +86,10 @@ type AiModelQueryOptions struct {
SortType string
New int
// JobStatus CloudbrainStatus
Type int
Status int
Type int
Status int
IsOnlyThisRepo bool
IsQueryPrivate bool
}

func (a *AiModelConvert) IsGpuTrainTask() bool {
@@ -217,6 +221,19 @@ func SaveModelToDb(model *AiModelManage) error {
return nil
}

func QueryModelConvertByName(name string, repoId int64) ([]*AiModelConvert, error) {
sess := x.NewSession()
defer sess.Close()
sess.Select("*").Table(new(AiModelConvert)).
Where("name='" + name + "' and repo_id=" + fmt.Sprint(repoId)).OrderBy("created_unix desc")
aiModelManageConvertList := make([]*AiModelConvert, 0)
err := sess.Find(&aiModelManageConvertList)
if err == nil {
return aiModelManageConvertList, nil
}
return nil, err
}

func QueryModelConvertById(id string) (*AiModelConvert, error) {
sess := x.NewSession()
defer sess.Close()
@@ -288,15 +305,30 @@ func ModifyModelDescription(id string, description string) error {
return nil
}

func ModifyLocalModel(id string, name, label, description string, engine int) error {
func ModifyModelPrivate(id string, isPrivate bool) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("is_private").Update(&AiModelManage{
IsPrivate: isPrivate,
})
if err != nil {
return err
}
log.Info("success to update isPrivate from db.re=" + fmt.Sprint((re)))
return nil
}

func ModifyLocalModel(id string, name, label, description string, engine int, isPrivate bool) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("name", "label", "description", "engine").Update(&AiModelManage{
re, err := sess.Cols("name", "label", "description", "engine", "is_private").Update(&AiModelManage{
Description: description,
Name: name,
Label: label,
Engine: int64(engine),
IsPrivate: isPrivate,
})
if err != nil {
return err
@@ -411,7 +443,11 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) {
builder.Eq{"ai_model_manage.status": opts.Status},
)
}

if !opts.IsQueryPrivate {
cond = cond.And(
builder.Eq{"ai_model_manage.is_private": false},
)
}
count, err := sess.Where(cond).Count(new(AiModelManage))
if err != nil {
return nil, 0, fmt.Errorf("Count: %v", err)


+ 183
- 6
models/cloudbrain.go View File

@@ -204,6 +204,7 @@ type Cloudbrain struct {
BenchmarkTypeRankLink string `xorm:"-"`
StartTime timeutil.TimeStamp
EndTime timeutil.TimeStamp
Cleared bool `xorm:"DEFAULT false"`
Spec *Specification `xorm:"-"`
}

@@ -304,6 +305,17 @@ func ConvertDurationToStr(duration int64) string {
}
return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60)
}
func ConvertStrToDuration(trainJobDuration string) int64 {
trainJobDurationList := strings.Split(trainJobDuration, ":")
if len(trainJobDurationList) == 3 {
i, _ := strconv.ParseInt(trainJobDurationList[0], 10, 64)
j, _ := strconv.ParseInt(trainJobDurationList[1], 10, 64)
k, _ := strconv.ParseInt(trainJobDurationList[2], 10, 64)
return i*3600 + j*60 + k
} else {
return 0
}
}

func IsTrainJobTerminal(status string) bool {
return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == GrampusStatusFailed || status == GrampusStatusStopped || status == GrampusStatusSucceeded
@@ -1596,9 +1608,23 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
}
}
if (opts.AiCenter) != "" {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
if opts.AiCenter == AICenterOfCloudBrainOne {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCloudBrainOne},
)
} else if opts.AiCenter == AICenterOfCloudBrainTwo {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCloudBrainTwo},
)
} else if opts.AiCenter == AICenterOfChengdu {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCDCenter},
)
} else {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
}
}
if (opts.Cluster) != "" {
if opts.Cluster == "resource_cluster_openi" {
@@ -1880,6 +1906,12 @@ func GetCloudbrainByID(id string) (*Cloudbrain, error) {
return getRepoCloudBrain(cb)
}

func IsCloudbrainExistByJobName(jobName string)(bool,error){
return x.Unscoped().Exist(&Cloudbrain{
JobName: jobName,
})
}

func GetCloudbrainByIDWithDeleted(id string) (*Cloudbrain, error) {
idInt64, _ := strconv.ParseInt(id, 10, 64)
cb := &Cloudbrain{ID: idInt64}
@@ -1975,7 +2007,7 @@ func UpdateTrainJobVersion(job *Cloudbrain) error {
func updateJobTrainVersion(e Engine, job *Cloudbrain) error {
var sess *xorm.Session
sess = e.Where("job_id = ? AND version_name=?", job.JobID, job.VersionName)
_, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix").Update(job)
_, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix", "ai_center").Update(job)
return err
}

@@ -2025,6 +2057,83 @@ func GetCloudBrainUnStoppedJob() ([]*Cloudbrain, error) {
Find(&cloudbrains)
}

func GetCloudBrainOneStoppedNotDebugJobDaysAgo(days int, limit int) ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0, 10)
endTimeBefore := time.Now().Unix() - int64(days)*24*3600
missEndTimeBefore := endTimeBefore - 24*3600
return cloudbrains, x.Unscoped().Cols("id,job_name,job_id").
In("status",
JobStopped, JobSucceeded, JobFailed, ModelArtsCreateFailed, ModelArtsStartFailed, ModelArtsUnavailable, ModelArtsResizFailed, ModelArtsDeleted,
ModelArtsStopped, ModelArtsTrainJobCanceled, ModelArtsTrainJobCheckFailed, ModelArtsTrainJobCompleted, ModelArtsTrainJobDeleteFailed, ModelArtsTrainJobDeployServiceFailed,
ModelArtsTrainJobFailed, ModelArtsTrainJobImageFailed, ModelArtsTrainJobKilled, ModelArtsTrainJobLost, ModelArtsTrainJobSubmitFailed, ModelArtsTrainJobSubmitModelFailed).
Where("(((end_time is null or end_time=0) and updated_unix<? and updated_unix != 0 ) or (end_time<? and end_time != 0)) and cleared=false and type=0 and job_type != 'DEBUG'", missEndTimeBefore, endTimeBefore).
Limit(limit).
Find(&cloudbrains)
}
/**
本方法考虑了再次调试的情况,多次调试取最后一次的任务的结束时间
*/
func GetCloudBrainOneStoppedDebugJobDaysAgo(days int, limit int) ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0, 10)
endTimeBefore := time.Now().Unix() - int64(days)*24*3600
missEndTimeBefore := endTimeBefore - 24*3600
sql:=`SELECT id,job_name,job_id from (SELECT DISTINCT ON (job_name)
id, job_name, job_id,status,end_time,updated_unix,cleared
FROM cloudbrain
where type=0 and job_type='DEBUG'
ORDER BY job_name, updated_unix DESC) a
where status in ('STOPPED','SUCCEEDED','FAILED') and (((end_time is null or end_time=0) and updated_unix<? and updated_unix != 0 ) or (end_time<? and end_time != 0)) and cleared=false`

return cloudbrains, x.Unscoped().SQL(sql,missEndTimeBefore, endTimeBefore).Limit(limit).Find(&cloudbrains)

}


func UpdateCloudBrainRecordsCleared(ids []int64) error {
pageSize := 150
n := len(ids) / pageSize

var err error

for i := 1; i <= n+1; i++ {
tempIds := getPageIds(ids, i, pageSize)
if len(tempIds) > 0 {
idsIn := ""
for i, id := range tempIds {
if i == 0 {
idsIn += strconv.FormatInt(id, 10)
} else {
idsIn += "," + strconv.FormatInt(id, 10)
}
}

_, errTemp := x.Unscoped().Exec("update cloudbrain set cleared=true where id in (" + idsIn + ")")
if errTemp != nil {
err = errTemp
}

}

}
return err

}

func getPageIds(ids []int64, page int, pagesize int) []int64 {
begin := (page - 1) * pagesize
end := (page) * pagesize

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

}

func GetStoppedJobWithNoDurationJob() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.
@@ -2040,7 +2149,7 @@ func GetStoppedJobWithNoStartTimeEndTime() ([]*Cloudbrain, error) {
func GetC2NetWithAiCenterWrongJob() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.
In("status", ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed).
In("status", ModelArtsTrainJobCompleted, ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed, JobSucceeded).
Where("type = ?", TypeC2Net).
Find(&cloudbrains)
}
@@ -2299,10 +2408,78 @@ func CloudbrainAllStatic(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, er
}
// sess.OrderBy("cloudbrain.created_unix DESC")
cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum)
if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource", "created_unix", "start_time", "end_time", "work_server_number").Table(&Cloudbrain{}).Unscoped().Where(cond).
if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err)
}
if opts.NeedRepoInfo {
var ids []int64
for _, task := range cloudbrains {
ids = append(ids, task.RepoID)
}
repositoryMap, err := GetRepositoriesMapByIDs(ids)
if err == nil {
for _, task := range cloudbrains {
task.Repo = repositoryMap[task.RepoID]
}
}

}
return cloudbrains, count, nil
}

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

var cond = builder.NewCond()

if (opts.Type) >= 0 {
cond = cond.And(
builder.Eq{"cloudbrain.type": opts.Type},
)
}
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
count, err = sess.Unscoped().Where(cond).Count(new(Cloudbrain))

if err != nil {
return nil, 0, fmt.Errorf("Count: %v", err)
}

if opts.Page >= 0 && opts.PageSize > 0 {
var start int
if opts.Page == 0 {
start = 0
} else {
start = (opts.Page - 1) * opts.PageSize
}
sess.Limit(opts.PageSize, start)
}
// sess.OrderBy("cloudbrain.created_unix DESC")
cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum)
if err := sess.Cols("id", "type", "work_server_number", "duration", "train_job_duration", "ai_center", "cluster").Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err)
}
if opts.NeedRepoInfo {
var ids []int64
for _, task := range cloudbrains {
ids = append(ids, task.RepoID)
}
repositoryMap, err := GetRepositoriesMapByIDs(ids)
if err == nil {
for _, task := range cloudbrains {
task.Repo = repositoryMap[task.RepoID]
}
}

}
return cloudbrains, count, nil
}



+ 89
- 36
models/cloudbrain_static.go View File

@@ -1,7 +1,6 @@
package models

import (
"fmt"
"strconv"
"time"

@@ -42,14 +41,15 @@ type TaskDetail struct {
type CloudbrainDurationStatistic struct {
ID int64 `xorm:"pk autoincr"`
Cluster string
AiCenterCode string
AiCenterCode string `xorm:"INDEX"`
AiCenterName string
ComputeResource string
AccCardType string
AccCardType string `xorm:"INDEX"`

DateTime string
DayTime string
HourTime int
DateTime timeutil.TimeStamp `xorm:"INDEX DEFAULT 0"`
DateTimeUnix timeutil.TimeStamp `xorm:"INDEX DEFAULT 0"`
DayTime string `xorm:"INDEX"`
HourTime int `xorm:"INDEX"`
CardsUseDuration int
CardsTotalDuration int
CardsTotalNum int
@@ -183,6 +183,17 @@ func GetWaittingTop() ([]*CloudbrainInfo, error) {
Find(&cloudbrains); err != nil {
log.Info("find error.")
}

var ids []int64
for _, task := range cloudbrains {
ids = append(ids, task.RepoID)
}
repositoryMap, err := GetRepositoriesMapByIDs(ids)
if err == nil {
for _, task := range cloudbrains {
task.Repo = repositoryMap[task.RepoID]
}
}
return cloudbrains, nil
}

@@ -199,6 +210,16 @@ func GetRunningTop() ([]*CloudbrainInfo, error) {
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
var ids []int64
for _, task := range cloudbrains {
ids = append(ids, task.RepoID)
}
repositoryMap, err := GetRepositoriesMapByIDs(ids)
if err == nil {
for _, task := range cloudbrains {
task.Repo = repositoryMap[task.RepoID]
}
}
return cloudbrains, nil
}

@@ -275,17 +296,21 @@ func GetCloudbrainByTime(beginTime int64, endTime int64) ([]*CloudbrainInfo, err
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.And(builder.Gte{"cloudbrain.end_time": beginTime}, builder.Lte{"cloudbrain.end_time": endTime}),
cond = cond.Or(
builder.And(builder.Gte{"cloudbrain.end_time": beginTime}, builder.Lte{"cloudbrain.start_time": beginTime}, builder.Gt{"cloudbrain.start_time": 0}),
)
cond = cond.Or(
builder.Eq{"cloudbrain.status": string(JobRunning)},
builder.And(builder.Gte{"cloudbrain.start_time": beginTime}, builder.Lte{"cloudbrain.start_time": endTime}, builder.Gt{"cloudbrain.start_time": 0}),
)
sess.OrderBy("cloudbrain.created_unix ASC")
cond = cond.Or(
builder.And(builder.Eq{"cloudbrain.status": string(JobRunning)}),
)
sess.OrderBy("cloudbrain.id ASC")
cloudbrains := make([]*CloudbrainInfo, 0, 10)
if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
log.Error("find error.")
return nil, err
}
return cloudbrains, nil
}
@@ -300,7 +325,8 @@ func GetSpecByAiCenterCodeAndType(aiCenterCode string, accCardType string) ([]*C
cloudbrainSpecs := make([]*CloudbrainSpec, 0, 10)
if err := sess.Table(&CloudbrainSpec{}).Where(cond).
Find(&cloudbrainSpecs); err != nil {
log.Info("find error.")
log.Error("find error.")
return nil, err
}
return cloudbrainSpecs, nil
}
@@ -309,33 +335,24 @@ func InsertCloudbrainDurationStatistic(cloudbrainDurationStatistic *CloudbrainDu
return xStatistic.Insert(cloudbrainDurationStatistic)
}

func DeleteCloudbrainDurationStatisticHour(date string, hour int, aiCenterCode string, accCardType string) error {
sess := xStatistic.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return fmt.Errorf("Begin: %v", err)
func getDurationStatistic(cb *CloudbrainDurationStatistic) (*CloudbrainDurationStatistic, error) {
has, err := x.Get(cb)
if err != nil {
return nil, err
} else if !has {
return nil, ErrJobNotExist{}
}

if _, err := sess.Where("day_time = ? AND hour_time = ? AND ai_center_code = ? AND acc_card_type = ?", date, hour, aiCenterCode, accCardType).Delete(&CloudbrainDurationStatistic{}); err != nil {
return fmt.Errorf("Delete: %v", err)
}

if err := sess.Commit(); err != nil {
sess.Close()
return fmt.Errorf("Commit: %v", err)
}

sess.Close()
return nil
return cb, nil
}

func GetCanUseCardInfo() ([]*ResourceQueue, error) {
sess := x.NewSession()
defer sess.Close()
sess.OrderBy("resource_queue.id ASC")
sess.OrderBy("resource_queue.cluster DESC, resource_queue.ai_center_code ASC")
ResourceQueues := make([]*ResourceQueue, 0, 10)
if err := sess.Table(&ResourceQueue{}).Find(&ResourceQueues); err != nil {
log.Info("find error.")
log.Error("find error.")
return nil, err
}
return ResourceQueues, nil
}
@@ -346,7 +363,7 @@ func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDur
var cond = builder.NewCond()
if opts.BeginTime.Unix() > 0 && opts.EndTime.Unix() > 0 {
cond = cond.And(
builder.And(builder.Gte{"cloudbrain_duration_statistic.created_unix": opts.BeginTime.Unix()}, builder.Lte{"cloudbrain_duration_statistic.created_unix": opts.EndTime.Unix()}),
builder.And(builder.Gte{"cloudbrain_duration_statistic.date_time_unix": opts.BeginTime.Unix()}, builder.Lt{"cloudbrain_duration_statistic.date_time_unix": opts.EndTime.Unix()}),
)
}
if opts.AiCenterCode != "" {
@@ -357,7 +374,8 @@ func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDur
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0, 10)
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond).
Find(&CloudbrainDurationStatistics); err != nil {
log.Info("find error.")
log.Error("find error.")
return nil, err
}
return CloudbrainDurationStatistics, nil
}
@@ -365,10 +383,45 @@ func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDur
func GetDurationRecordBeginTime() ([]*CloudbrainDurationStatistic, error) {
sess := xStatistic.NewSession()
defer sess.Close()
sess.OrderBy("cloudbrain_duration_statistic.id ASC limit 1")

var cond = builder.NewCond()

cond = cond.And(
builder.Gt{"cloudbrain_duration_statistic.date_time_unix": 0},
)

sess.OrderBy("cloudbrain_duration_statistic.date_time_unix ASC limit 1")
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0)
if err := sess.Table(&CloudbrainDurationStatistic{}).Find(&CloudbrainDurationStatistics); err != nil {
log.Info("find error.")
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond).Find(&CloudbrainDurationStatistics); err != nil {
log.Error("find error.")
return nil, err
}
return CloudbrainDurationStatistics, nil
}

func GetDurationRecordUpdateTime() ([]*CloudbrainDurationStatistic, error) {
sess := xStatistic.NewSession()
defer sess.Close()
var cond = builder.NewCond()

cond = cond.And(
builder.Gt{"cloudbrain_duration_statistic.date_time_unix": 1577808000},
)
sess.OrderBy("cloudbrain_duration_statistic.date_time_unix DESC limit 1")
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0)
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond).Find(&CloudbrainDurationStatistics); err != nil {
log.Error("find error.")
return nil, err
}
return CloudbrainDurationStatistics, nil
}

func DeleteCloudbrainDurationStatistic(beginTime timeutil.TimeStamp, endTime timeutil.TimeStamp) error {
sess := xStatistic.NewSession()
defer sess.Close()
if _, err := sess.Exec("DELETE FROM cloudbrain_duration_statistic WHERE cloudbrain_duration_statistic.date_time_unix BETWEEN ? AND ?", beginTime, endTime); err != nil {
log.Error("DELETE cloudbrain_duration_statistic data error.")
return err
}
return nil
}

+ 14
- 6
models/dataset.go View File

@@ -122,22 +122,22 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)
for i := range datasets {
if attachment.DatasetID == datasets[i].ID {

if !attachment.IsPrivate{
if !attachment.IsPrivate {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
}else{
} else {
permission, ok := permissionMap[datasets[i].ID]
if !ok {

permission = false
datasets[i].Repo.GetOwner()
if !permission {
if datasets[i].Repo.OwnerID==opts.User.ID{
if datasets[i].Repo.OwnerID == opts.User.ID {
permission = true
}else{
} else {
isCollaborator, _ := datasets[i].Repo.IsCollaborator(opts.User.ID)
isInRepoTeam,_:=datasets[i].Repo.IsInRepoTeam(opts.User.ID)
isInRepoTeam, _ := datasets[i].Repo.IsInRepoTeam(opts.User.ID)

if isCollaborator ||isInRepoTeam {
if isCollaborator || isInRepoTeam {
permission = true
}
}
@@ -603,3 +603,11 @@ func UpdateDatasetCreateUser(ID int64, user *User) error {
}
return nil
}

func QueryDatasetGroupByTask() ([]map[string]interface{}, error) {
rows, err := x.QueryInterface("SELECT count(*) as total,task FROM public.dataset where task <>'' group by task order by total desc limit 7")
if err != nil {
return nil, err
}
return rows, nil
}

+ 1
- 1
models/repo.go View File

@@ -1279,7 +1279,7 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, opts ...Cr
}

if setting.Service.AutoWatchNewRepos {
if err = watchRepo(ctx.e, doer.ID, repo.ID, true); err != nil {
if err = watchRepo(ctx.e, doer.ID, repo.ID, true, ReceiveAllNotification); err != nil {
return fmt.Errorf("watchRepo: %v", err)
}
}


+ 5
- 1
models/repo_activity_custom.go View File

@@ -263,7 +263,11 @@ func GetAllUserKPIStats(startTime time.Time, endTime time.Time) (map[string]*git
log.Warn("get user kpi status err:"+repository.RepoPath(), err1.Error())
continue
}

// if repository.Name == "yolov5" {
// log.Info("repoName=" + repository.Name + " owner=" + repository.RepoPath())
// authorsOneRepoJson, _ := json.Marshal(authorsOneRepo)
// log.Info("authorsOneRepoJson=" + string(authorsOneRepoJson))
// }
for key, value := range authorsOneRepo {
if _, ok := authors[key]; !ok {
authors[key] = &git.UserKPIStats{


+ 30
- 3
models/repo_watch.go View File

@@ -24,6 +24,14 @@ const (
RepoWatchModeAuto // 3
)

// NotifyType specifies what kind of watch the user has on a repository
type NotifyType int8

const (
RejectAllNotification NotifyType = 0
ReceiveAllNotification NotifyType = 9
)

var ActionChan = make(chan *Action, 200)
var ActionChan4Task = make(chan Action, 200)

@@ -34,6 +42,7 @@ type Watch struct {
RepoID int64 `xorm:"UNIQUE(watch)"`
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
CreatedUnix int64 `xorm:"created"`
NotifyType NotifyType `xorm:"SMALLINT NOT NULL DEFAULT 0"`
}

// getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found
@@ -60,8 +69,20 @@ func IsWatching(userID, repoID int64) bool {
return err == nil && isWatchMode(watch.Mode)
}

// GetWatchNotifyType
func GetWatchNotifyType(userID, repoID int64) NotifyType {
watch, err := getWatch(x, userID, repoID)
if err != nil {
return RejectAllNotification
}
return watch.NotifyType
}

func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) {
if watch.Mode == mode {
if _, err := e.ID(watch.ID).Cols("notify_type").Update(watch); err != nil {
return err
}
return nil
}
if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) {
@@ -109,7 +130,7 @@ func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) {
return watchRepoMode(x, watch, mode)
}

func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) {
func watchRepo(e Engine, userID, repoID int64, doWatch bool, notifyTypes ...NotifyType) (err error) {
var watch Watch
if watch, err = getWatch(e, userID, repoID); err != nil {
return err
@@ -119,14 +140,19 @@ func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) {
} else if !doWatch {
err = watchRepoMode(e, watch, RepoWatchModeNone)
} else {
notifyType := RejectAllNotification
if len(notifyTypes) > 0 {
notifyType = notifyTypes[0]
}
watch.NotifyType = notifyType
err = watchRepoMode(e, watch, RepoWatchModeNormal)
}
return err
}

// WatchRepo watch or unwatch repository.
func WatchRepo(userID, repoID int64, watch bool) (err error) {
return watchRepo(x, userID, repoID, watch)
func WatchRepo(userID, repoID int64, watch bool, notifyType ...NotifyType) (err error) {
return watchRepo(x, userID, repoID, watch, notifyType...)
}

func getWatchers(e Engine, repoID int64) ([]*Watch, error) {
@@ -156,6 +182,7 @@ func getRepoWatchersIDs(e Engine, repoID int64) ([]int64, error) {
return ids, e.Table("watch").
Where("watch.repo_id=?", repoID).
And("watch.mode<>?", RepoWatchModeDont).
And("watch.notify_type > ?", RejectAllNotification).
Select("user_id").
Find(&ids)
}


+ 102
- 0
models/resource_specification.go View File

@@ -3,6 +3,7 @@ package models
import (
"code.gitea.io/gitea/modules/timeutil"
"fmt"
"strings"
"xorm.io/builder"
)

@@ -197,12 +198,104 @@ type Specification struct {
AiCenterName string
IsExclusive bool
ExclusiveOrg string
//specs that have the same sourceSpecId, computeResource and cluster as current spec
RelatedSpecs []*Specification
}

func (Specification) TableName() string {
return "resource_specification"
}

func (s *Specification) loadRelatedSpecs() {
if s.RelatedSpecs != nil {
return
}
defaultSpecs := make([]*Specification, 0)
if s.SourceSpecId == "" {
s.RelatedSpecs = defaultSpecs
return
}
r, err := FindSpecs(FindSpecsOptions{
ComputeResource: s.ComputeResource,
Cluster: s.Cluster,
SourceSpecId: s.SourceSpecId,
RequestAll: true,
SpecStatus: SpecOnShelf,
})
if err != nil {
s.RelatedSpecs = defaultSpecs
return
}
s.RelatedSpecs = r
}
func (s *Specification) GetAvailableCenterIds(userIds ...int64) []string {
s.loadRelatedSpecs()

if len(s.RelatedSpecs) == 0 {
return make([]string, 0)
}

var uId int64
if len(userIds) > 0 {
uId = userIds[0]
}
//filter exclusive specs
specs := FilterExclusiveSpecs(s.RelatedSpecs, uId)

centerIds := make([]string, len(specs))
for i, v := range specs {
centerIds[i] = v.AiCenterCode
}
return centerIds
}

func FilterExclusiveSpecs(r []*Specification, userId int64) []*Specification {
if userId == 0 {
return r
}
specs := make([]*Specification, 0, len(r))
specMap := make(map[int64]string, 0)
for i := 0; i < len(r); i++ {
spec := r[i]
if _, has := specMap[spec.ID]; has {
continue
}
if !spec.IsExclusive {
specs = append(specs, spec)
specMap[spec.ID] = ""
continue
}
orgs := strings.Split(spec.ExclusiveOrg, ";")
for _, org := range orgs {
isMember, _ := IsOrganizationMemberByOrgName(org, userId)
if isMember {
specs = append(specs, spec)
specMap[spec.ID] = ""
break
}
}
}
return specs
}

func DistinctSpecs(r []*Specification) []*Specification {
specs := make([]*Specification, 0, len(r))
sourceSpecIdMap := make(map[string]string, 0)
for i := 0; i < len(r); i++ {
spec := r[i]
if spec.SourceSpecId == "" {
specs = append(specs, spec)
continue
}
if _, has := sourceSpecIdMap[spec.SourceSpecId]; has {
continue
}
specs = append(specs, spec)
sourceSpecIdMap[spec.SourceSpecId] = ""
}
return specs
}

func InsertResourceSpecification(r ResourceSpecification) (int64, error) {
return x.Insert(&r)
}
@@ -298,6 +391,15 @@ func ResourceSpecOffShelf(id int64) (int64, error) {
return n, err
}

func GetResourceSpecificationByIds(ids []int64) ([]*Specification, error) {
r := make([]*Specification, 0)
err := x.In("resource_specification.id", ids).
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id").
Find(&r)
return r, err

}

func GetResourceSpecification(r *ResourceSpecification) (*ResourceSpecification, error) {
has, err := x.Get(r)
if err != nil {


+ 1
- 1
models/user.go View File

@@ -346,7 +346,7 @@ func (u *User) DashboardLink() string {
if u.IsOrganization() {
return setting.AppSubURL + "/org/" + u.Name + "/dashboard/"
}
return setting.AppSubURL + "/"
return setting.AppSubURL + "/dashboard"
}

// HomeLink returns the user or organization home page link.


+ 17
- 0
models/user_analysis_for_activity.go View File

@@ -449,3 +449,20 @@ func QueryUserLoginInfo(userIds []int64) []*UserLoginLog {

return loginList
}

func QueryUserAnnualReport(userId int64) *UserSummaryCurrentYear {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
log.Info("userId=" + fmt.Sprint(userId))

reList := make([]*UserSummaryCurrentYear, 0)
err := statictisSess.Select("*").Table(new(UserSummaryCurrentYear)).Where("id=" + fmt.Sprint(userId)).Find(&reList)
if err == nil {
if len(reList) > 0 {
return reList[0]
}
} else {
log.Info("error:=" + err.Error())
}
return nil
}

+ 20
- 3
models/user_business_analysis.go View File

@@ -132,11 +132,17 @@ func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics {
if count > 0 {
for _, userMetrics := range allUserInfo {
dateTime := time.Unix(userMetrics.CountDate, 0)
month := fmt.Sprint(dateTime.Year()) + "-" + fmt.Sprint(int(dateTime.Month()))
mInt := int(dateTime.Month())
mString := fmt.Sprint(mInt)
if mInt < 10 {
mString = "0" + mString
}
month := fmt.Sprint(dateTime.Year()) + "-" + mString
if _, ok := monthMap[month]; !ok {
monthUserMetrics := &UserMetrics{
DisplayDate: month,
ActivateRegistUser: userMetrics.ActivateRegistUser,
RegistActivityUser: userMetrics.RegistActivityUser,
NotActivateRegistUser: userMetrics.NotActivateRegistUser,
TotalUser: userMetrics.TotalUser,
TotalNotActivateRegistUser: userMetrics.TotalUser - userMetrics.TotalActivateRegistUser,
@@ -152,6 +158,7 @@ func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics {
value.ActivateRegistUser += userMetrics.ActivateRegistUser
value.NotActivateRegistUser += userMetrics.NotActivateRegistUser
value.HasActivityUser += userMetrics.HasActivityUser
value.RegistActivityUser += userMetrics.RegistActivityUser
value.TotalRegistUser += userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser
value.ActivateIndex = float64(value.ActivateRegistUser) / float64(value.TotalRegistUser)
value.DaysForMonth += 1
@@ -610,7 +617,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS

DataDate := currentTimeNow.Format("2006-01-02") + " 00:01"
bonusMap := make(map[string]map[string]int)
if tableName == "user_business_analysis_current_year" {
if isUserYearData(tableName) {
bonusMap = getBonusMap()
log.Info("truncate all data from table:user_summary_current_year ")
statictisSess.Exec("TRUNCATE TABLE user_summary_current_year")
@@ -712,7 +719,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
userMetrics["TotalHasActivityUser"] = getMapKeyStringValue("TotalHasActivityUser", userMetrics) + 1
}
}
if tableName == "user_business_analysis_current_year" {
if isUserYearData(tableName) {
//年度数据
subTime := time.Now().UTC().Sub(dateRecordAll.RegistDate.AsTime().UTC())
mostActiveDay := ""
@@ -772,6 +779,16 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount))
}

func isUserYearData(tableName string) bool {
if tableName == "user_business_analysis_current_year" {
currentTimeNow := time.Now()
if currentTimeNow.Year() >= 2023 {
return false
}
}
return true
}

func getBonusMap() map[string]map[string]int {
bonusMap := make(map[string]map[string]int)
url := setting.RecommentRepoAddr + "bonus/record.txt"


+ 1
- 0
models/user_invitation.go View File

@@ -13,6 +13,7 @@ type Invitation struct {
SrcUserID int64 `xorm:"NOT NULL DEFAULT 0"`
UserID int64 `xorm:"NOT NULL DEFAULT 0"`
Phone string `xorm:"INDEX"`
Email string `xorm:"-"`
Avatar string `xorm:"-"`
Name string `xorm:"-"`
InvitationUserNum int `xorm:"-"`


+ 21
- 0
models/user_mail.go View File

@@ -216,6 +216,27 @@ func (email *EmailAddress) updateActivation(e Engine, activate bool) error {
return updateUserCols(e, user, "rands")
}

// UpdateEmailAddress update an email address of given user.
func (email *EmailAddress) UpdateEmailAddress(newEmailAddress string) error {
return email.updateEmailAddress(x, newEmailAddress)
}
func (email *EmailAddress) updateEmailAddress(e Engine, newEmailAddress string) error {
user, err := getUserByID(e, email.UID)
if err != nil {
return err
}
if user.Rands, err = GetUserSalt(); err != nil {
return err
}
user.Email = newEmailAddress
user.AvatarEmail = newEmailAddress
email.Email = newEmailAddress
if _, err := e.ID(email.ID).Cols("email").Update(email); err != nil {
return err
}
return updateUserCols(e, user, "email", "avatar_email")
}

// DeleteEmailAddress deletes an email address of given user.
func DeleteEmailAddress(email *EmailAddress) (err error) {
var deleted int64


+ 4
- 0
modules/auth/user_form.go View File

@@ -88,6 +88,10 @@ type RegisterForm struct {
Agree bool
}

type UpdateEmailForm struct {
NewEmail string `binding:"Required;MaxSize(254)"`
}

// Validate valideates the fields
func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)


+ 20
- 4
modules/cloudbrain/cloudbrain.go View File

@@ -145,7 +145,7 @@ func isAdminOrImageCreater(ctx *context.Context, image *models.Image, err error)
func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {

var id = ctx.Params(":id")
job, err := models.GetCloudbrainByID(id)
job, err := GetCloudBrainByIdOrJobId(id)
if err != nil {
log.Error("GetCloudbrainByID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -161,7 +161,7 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {
func AdminOrJobCreaterRight(ctx *context.Context) {

var id = ctx.Params(":id")
job, err := models.GetCloudbrainByID(id)
job, err := GetCloudBrainByIdOrJobId(id)
if err != nil {
log.Error("GetCloudbrainByID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -177,7 +177,7 @@ func AdminOrJobCreaterRight(ctx *context.Context) {
func AdminOrOwnerOrJobCreaterRightForTrain(ctx *context.Context) {

var jobID = ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID)
job, err := GetCloudBrainByIdOrJobId(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -193,7 +193,7 @@ func AdminOrOwnerOrJobCreaterRightForTrain(ctx *context.Context) {
func AdminOrJobCreaterRightForTrain(ctx *context.Context) {

var jobID = ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID)
job, err := GetCloudBrainByIdOrJobId(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -652,3 +652,19 @@ func IsElementExist(s []string, str string) bool {
}
return false
}

func GetCloudBrainByIdOrJobId(id string) (*models.Cloudbrain,error) {
_, err := strconv.ParseInt(id, 10, 64)
var job *models.Cloudbrain
if err != nil {

job, err = models.GetCloudbrainByJobID(id)
} else {
job, err = models.GetCloudbrainByID(id)
if err!=nil{
job, err = models.GetCloudbrainByJobID(id)
}

}
return job,err
}

+ 1
- 0
modules/context/repo.go View File

@@ -474,6 +474,7 @@ func RepoAssignment() macaron.Handler {

if ctx.IsSigned {
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID)
ctx.Data["WatchNotifyType"] = models.GetWatchNotifyType(ctx.User.ID, repo.ID)
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID)

ctx.Data["IsStaringDataset"] = models.IsDatasetStaringByRepoId(ctx.User.ID, repo.ID)


+ 1
- 0
modules/convert/cloudbrain.go View File

@@ -104,6 +104,7 @@ func ToSpecification(s *models.Specification) *api.SpecificationShow {

func ToTagger(user *models.User) *api.Tagger {
return &api.Tagger{
ID: user.ID,
Name: user.Name,
RelAvatarURL: user.RelAvatarLink(),
Email: user.Email,


+ 17
- 2
modules/cron/tasks_basic.go View File

@@ -5,10 +5,13 @@
package cron

import (
"code.gitea.io/gitea/modules/urfs_client/urchin"
"code.gitea.io/gitea/modules/setting"
"context"
"time"

"code.gitea.io/gitea/modules/urfs_client/urchin"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/services/cloudbrain/resource"
"code.gitea.io/gitea/services/reward"
@@ -190,6 +193,17 @@ func registerHandleRepoAndUserStatistic() {
})
}

func registerHandleClearCloudbrainResult() {
RegisterTaskFatal("handle_cloudbrain_one_result_clear", &BaseConfig{
Enabled: true,
RunAtStart: setting.ClearStrategy.RunAtStart,
Schedule: setting.ClearStrategy.Cron,
}, func(ctx context.Context, _ *models.User, _ Config) error {
cloudbrainService.ClearCloudbrainResultSpace()
return nil
})
}

func registerHandleSummaryStatistic() {
RegisterTaskFatal("handle_summary_statistic", &BaseConfig{
Enabled: true,
@@ -306,6 +320,7 @@ func initBasicTasks() {

registerHandleRepoAndUserStatistic()
registerHandleSummaryStatistic()
registerHandleClearCloudbrainResult()

registerSyncCloudbrainStatus()
registerHandleOrgStatistic()
@@ -317,6 +332,6 @@ func initBasicTasks() {

registerHandleModelSafetyTask()

registerHandleScheduleRecord()
registerHandleScheduleRecord()
registerHandleCloudbrainDurationStatistic()
}

+ 2
- 5
modules/grampus/grampus.go View File

@@ -37,7 +37,7 @@ var (

SpecialPools *models.SpecialPools

CommandPrepareScriptGpu = ";mkdir -p output;mkdir -p code;mkdir -p dataset;mkdir -p pretrainmodel;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/%s/archive/master.zip;" +
CommandPrepareScriptGpu = ";mkdir -p output;mkdir -p code;mkdir -p dataset;mkdir -p pretrainmodel;echo \"start loading script\";wget -q https://openi.pcl.ac.cn/OpenIOSSG/%s/archive/master.zip;" +
"echo \"finish loading script\";unzip -q master.zip;cd %s;chmod 777 downloader_for_obs uploader_for_npu downloader_for_minio uploader_for_gpu;"
)

@@ -105,8 +105,6 @@ func getDatasetGrampus(datasetInfos map[string]models.DatasetInfo) []models.Gram
func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId string, err error) {
createTime := timeutil.TimeStampNow()

centerID, centerName := getCentersParamter(ctx, req)

var datasetGrampus, modelGrampus []models.GrampusDataset
var codeGrampus models.GrampusDataset
if ProcessorTypeNPU == req.ProcessType {
@@ -138,8 +136,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
ResourceSpecId: req.Spec.SourceSpecId,
ImageId: req.ImageId,
ImageUrl: req.ImageUrl,
CenterID: centerID,
CenterName: centerName,
CenterID: req.Spec.GetAvailableCenterIds(ctx.User.ID),
ReplicaNum: 1,
Datasets: datasetGrampus,
Models: modelGrampus,


+ 94
- 8
modules/modelarts/modelarts.go View File

@@ -1,13 +1,18 @@
package modelarts

import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"path"
"strconv"
"strings"

"code.gitea.io/gitea/modules/cloudbrain"

"code.gitea.io/gitea/modules/modelarts_cd"

"code.gitea.io/gitea/models"
@@ -23,7 +28,7 @@ const (
//notebook
storageTypeOBS = "obs"
autoStopDuration = 4 * 60 * 60
autoStopDurationMs = 4 * 60 * 60 * 1000
AutoStopDurationMs = 4 * 60 * 60 * 1000
MORDELART_USER_IMAGE_ENGINE_ID = -1
DataSetMountPath = "/home/ma-user/work"
NotebookEnv = "Python3"
@@ -276,7 +281,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin
return nil
}

func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error {
func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string,autoStopDurationInMs int64) (string, error) {
if poolInfos == nil {
json.Unmarshal([]byte(setting.PoolInfos), &poolInfos)
}
@@ -284,14 +289,14 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
imageName, err := GetNotebookImageName(imageId)
if err != nil {
log.Error("GetNotebookImageName failed: %v", err.Error())
return err
return "", err
}
createTime := timeutil.TimeStampNow()
jobResult, err := createNotebook2(models.CreateNotebook2Params{
JobName: jobName,
Description: description,
Flavor: spec.SourceSpecId,
Duration: autoStopDurationMs,
Duration: autoStopDurationInMs,
ImageID: imageId,
PoolID: poolInfos.PoolInfo[0].PoolId,
Feature: models.NotebookFeature,
@@ -316,10 +321,10 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
return "", errTemp
}
}
return err
return "", err
}
task := &models.Cloudbrain{
Status: jobResult.Status,
@@ -334,6 +339,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
Uuid: uuid,
ComputeResource: models.NPUResource,
Image: imageName,
BootFile: bootFile,
Description: description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
@@ -342,12 +348,12 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc

err = models.CreateCloudbrain(task)
if err != nil {
return err
return "", err
}

stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask)
return nil
return jobResult.ID, nil
}

func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId string, err error) {
@@ -907,6 +913,11 @@ func HandleNotebookInfo(task *models.Cloudbrain) error {
if task.FlavorCode == "" {
task.FlavorCode = result.Flavor
}

if oldStatus != task.Status && task.Status == string(models.ModelArtsRunning) && task.BootFile != "" {
uploadNoteBookFile(task, result)

}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err)
@@ -917,6 +928,81 @@ func HandleNotebookInfo(task *models.Cloudbrain) error {
return nil
}

func uploadNoteBookFile(task *models.Cloudbrain, result *models.GetNotebook2Result) {
jupyterUrl := result.Url + "?token=" + result.Token

cookies, xsrf := getCookiesAndCsrf(jupyterUrl)
if xsrf == "" {
log.Error("browser jupyterUrl failed:%v", task.DisplayJobName)
} else {

codePath := setting.JobPath + task.JobName + cloudbrain.CodeMountPath
fileContents, err := ioutil.ReadFile(codePath + "/" + task.BootFile)
if err != nil {
log.Error("read jupyter file failed:%v", task.DisplayJobName, err)
}

base64Content := base64.StdEncoding.EncodeToString(fileContents)
client := getRestyClient()
uploadUrl := getJupyterBaseUrl(result.Url) + "api/contents/" + path.Base(task.BootFile)
res, err := client.R().
SetCookies(cookies).
SetHeader("X-XSRFToken", xsrf).
SetBody(map[string]interface{}{
"type": "file",
"format": "base64",
"name": path.Base(task.BootFile),
"path": path.Base(task.BootFile),
"content": base64Content}).
Put(uploadUrl)
if err != nil {
log.Error("upload jupyter file failed:%v", task.DisplayJobName, err)
} else if res.StatusCode() != http.StatusCreated {
log.Error("upload jupyter file failed:%v", task.DisplayJobName, err)
}

}

}

func getJupyterBaseUrl(url string) string {
jupyterUrlLength := len(url)
baseUrl := url[0 : jupyterUrlLength-len(path.Base(url))]
return baseUrl
}

func getCookiesAndCsrf(jupyterUrl string) ([]*http.Cookie, string) {
log.Info("jupyter url:"+jupyterUrl)
var cookies []*http.Cookie
const retryTimes = 10
for i := 0; i < retryTimes; i++ {
res, err := http.Get(jupyterUrl)
if err != nil {
log.Error("browser jupyterUrl failed.",err)
if i==retryTimes-1{
return cookies, ""
}

} else {
cookies = res.Cookies()
xsrf := ""
for _, cookie := range cookies {
if cookie.Name == "_xsrf" {
xsrf = cookie.Value
break
}

}
if xsrf != "" {
return cookies, xsrf
}

}
}
return cookies, ""

}

func SyncTempStatusJob() {
jobs, err := models.GetCloudBrainTempJobs()
if err != nil {


+ 1
- 1
modules/modelarts/resty.go View File

@@ -280,7 +280,7 @@ sendjob:
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetResult(&result).
Post(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID + "/" + param.Action + "?duration=" + strconv.Itoa(autoStopDurationMs))
Post(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID + "/" + param.Action + "?duration=" + strconv.Itoa(AutoStopDurationMs))

if err != nil {
return &result, fmt.Errorf("resty ManageNotebook2: %v", err)


+ 8
- 45
modules/modelarts_cd/modelarts.go View File

@@ -88,18 +88,18 @@ type Parameters struct {
} `json:"parameter"`
}

func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error {
func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string,autoStopDurationInMs int64) (string, error) {
imageName, err := GetNotebookImageName(imageId)
if err != nil {
log.Error("GetNotebookImageName failed: %v", err.Error())
return err
return "", err
}
createTime := timeutil.TimeStampNow()
jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{
JobName: jobName,
Description: description,
Flavor: spec.SourceSpecId,
Duration: autoStopDurationMs,
Duration: autoStopDurationInMs,
ImageID: imageId,
Feature: models.NotebookFeature,
Volume: models.VolumeReq{
@@ -123,10 +123,10 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
return "", errTemp
}
}
return err
return "", err
}
task := &models.Cloudbrain{
Status: jobResult.Status,
@@ -145,16 +145,17 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr
CreatedUnix: createTime,
UpdatedUnix: createTime,
Spec: spec,
BootFile: bootFile,
}

err = models.CreateCloudbrain(task)
if err != nil {
return err
return "", err
}

stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask)
return nil
return jobResult.ID, nil
}

func GetNotebookImageName(imageId string) (string, error) {
@@ -175,41 +176,3 @@ func GetNotebookImageName(imageId string) (string, error) {

return imageName, nil
}

/*
func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook(task.JobID)
if err != nil {
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err)
return err
}

if result != nil {
oldStatus := task.Status
task.Status = result.Status
if task.StartTime == 0 && result.Lease.UpdateTime > 0 {
task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
}
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.CorrectCreateUnix()
task.ComputeAndSetDuration()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
if task.FlavorCode == "" {
task.FlavorCode = result.Flavor
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err)
return err
}
}

return nil
}

*/

+ 1
- 1
modules/repository/hooks.go View File

@@ -36,7 +36,7 @@ func getHookTemplates() (hookNames, hookTpls, giteaHookTpls, sizeLimitTpls []str
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
}
sizeLimitTpls = []string{
fmt.Sprintf("#!/usr/bin/env %s\n\n\nset -o pipefail\n\nreadonly DEFAULT_FILE_MAXSIZE_MB=\"30\" \nreadonly CONFIG_NAME=\"hooks.maxfilesize\"\nreadonly NULLSHA=\"0000000000000000000000000000000000000000\"\nreadonly EXIT_SUCCESS=0\nreadonly EXIT_FAILURE=1\nreadonly DEFAULT_REPO_MAXSIZE_MB=\"1024\" \nreadonly CHECK_FLAG_ON=1\n\n\nstatus=\"$EXIT_SUCCESS\"\n\n# skip this hook entirely if shell check is not open\ncheck_flag=${PUSH_SIZE_CHECK_FLAG}\nif [[ $check_flag != $CHECK_FLAG_ON ]]; then\nexit $EXIT_SUCCESS\nfi\n\n\n#######################################\n# check the file max size limit\n#######################################\n\n# get maximum filesize (from repository-specific config)\nmaxsize_mb=\"${REPO_MAX_FILE_SIZE}\"\n\nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\necho \"failed to get ${CONFIG_NAME} from config\"\nexit \"$EXIT_FAILURE\"\nfi\n\npush_size=\"0\"\n# read lines from stdin (format: \"<oldref> <newref> <refname>\\n\")\nwhile read oldref newref refname; do\n# skip branch deletions\nif [[ \"$newref\" == \"$NULLSHA\" ]]; then\n continue\nfi\n\n# find large objects\n# check all objects from $oldref (possible $NULLSHA) to $newref, but\n# skip all objects that have already been accepted (i.e. are referenced by\n# another branch or tag).\n\nnew_branch_flag=0\nif [[ \"$oldref\" == \"$NULLSHA\" ]]; then\n target=\"$newref\"\n new_branch_flag=1\n echo \"You are creating a new remote branch,openI will check all files in commit history to find oversize files\"\nelse\n target=\"${oldref}..${newref}\"\nfi\nmaxsize=`expr $maxsize_mb \\* 1048576` \n\n# find objects in this push_size\n# print like:\n# 08da8e2ab9ae4095bf94dd71ac913132b880b463 commit 214\n# 43e993b768ede5740e8c65de2ed6edec25053ea1 tree 185\n# 4476971d76569039df7569af1b8d03c288f6b193 blob 20167318 b0417e6593a1.zip\nfiles=\"$(git rev-list --objects \"$target\" | \\\n git cat-file $'--batch-check=%%(objectname) %%(objecttype) %%(objectsize) %%(rest)' | \\\n awk -F ' ' -v maxbytes=\"$maxsize\" 'BEGIN {totalIn=0} {if( $3 > maxbytes && $2 == \"blob\") { totalIn+=$3; print $4} else { totalIn+=$3}} END { printf (\"totalIn=\\t%%s\",totalIn)}' )\"\n \nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\n echo \"failed to check for large files in ref ${refname}\"\n continue\nfi\n\nIFS=$'\\n'\n# rewrite IFS to seperate line in $files\nfor file in $files; do\n # if don't unset IFS,temp_array=(${file}) will get error answer\n \n if [[ ${file} == totalIn=* ]]; then\n\tIFS=$'\\t'\n\ttemp_array=(${file})\n\tpush_size=${temp_array[1]}\n\tcontinue\n fi\n\tunset IFS\n if [[ \"$status\" == $EXIT_SUCCESS ]]; then\n\t\techo -e \"Error: Your push was rejected because it contains files larger than $(numfmt --to=iec \"$maxsize_mb\") Mb\"\n\t\techo \"help document -- https://git.openi.org.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n\t\techo \"oversize files:\"\n\t\tstatus=\"$EXIT_FAILURE\"\t\n fi\n echo -e \"\\033[31m- ${file}\\033[0m \"\ndone\n\nif [[ \"$status\" != $EXIT_SUCCESS ]]; then\n\texit \"$status\"\nfi\n\ndone\n\n#######################################\n# check the repo max size limit\n#######################################\nif [[ $push_size -eq \"0\" ]]; then\n\texit $EXIT_SUCCESS\nfi\n\n# if create new branch or tag,use count-objects -v to get pack size\nif [[ $new_branch_flag -eq 1 ]]; then\n size_kb=`git count-objects -v | grep 'size-pack' | sed 's/.*\\(size-pack:\\).//'`\n size_pack_kb=`git count-objects -v | grep 'size:' | sed 's/.*\\(size:\\).//'`\n\ttotal_kb=`expr $size_kb + $size_pack_kb`\n\tlet push_size=$total_kb*1024\nfi\n\nsizelimit_mb=\"${REPO_MAX_SIZE}\"\nlet sizelimit_b=$sizelimit_mb*1024*1024\n\n# repo size at here means the size of repo directory in server \nreposize_b=${REPO_CURRENT_SIZE}\n\ntotal=`expr $push_size + $reposize_b`\n\nif [ $total -gt $sizelimit_b ]; then\n echo \"Error: Your push was rejected because the repository size is large than $sizelimit_mb Mb\"\n echo \"see the help document--https://git.openi.org.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n exit $EXIT_FAILURE\nfi\n\n\nexit $EXIT_SUCCESS", setting.ScriptType),
fmt.Sprintf("#!/usr/bin/env %s\n\n\nset -o pipefail\n\nreadonly DEFAULT_FILE_MAXSIZE_MB=\"30\" \nreadonly CONFIG_NAME=\"hooks.maxfilesize\"\nreadonly NULLSHA=\"0000000000000000000000000000000000000000\"\nreadonly EXIT_SUCCESS=0\nreadonly EXIT_FAILURE=1\nreadonly DEFAULT_REPO_MAXSIZE_MB=\"1024\" \nreadonly CHECK_FLAG_ON=1\n\n\nstatus=\"$EXIT_SUCCESS\"\n\n# skip this hook entirely if shell check is not open\ncheck_flag=${PUSH_SIZE_CHECK_FLAG}\nif [[ $check_flag != $CHECK_FLAG_ON ]]; then\nexit $EXIT_SUCCESS\nfi\n\n\n#######################################\n# check the file max size limit\n#######################################\n\n# get maximum filesize (from repository-specific config)\nmaxsize_mb=\"${REPO_MAX_FILE_SIZE}\"\n\nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\necho \"failed to get ${CONFIG_NAME} from config\"\nexit \"$EXIT_FAILURE\"\nfi\n\npush_size=\"0\"\n# read lines from stdin (format: \"<oldref> <newref> <refname>\\n\")\nwhile read oldref newref refname; do\n# skip branch deletions\nif [[ \"$newref\" == \"$NULLSHA\" ]]; then\n continue\nfi\n\n# find large objects\n# check all objects from $oldref (possible $NULLSHA) to $newref, but\n# skip all objects that have already been accepted (i.e. are referenced by\n# another branch or tag).\n\nnew_branch_flag=0\nif [[ \"$oldref\" == \"$NULLSHA\" ]]; then\n target=\"$newref\"\n new_branch_flag=1\n echo \"You are creating a new remote branch,openI will check all files in commit history to find oversize files\"\nelse\n target=\"${oldref}..${newref}\"\nfi\nmaxsize=`expr $maxsize_mb \\* 1048576` \n\n# find objects in this push_size\n# print like:\n# 08da8e2ab9ae4095bf94dd71ac913132b880b463 commit 214\n# 43e993b768ede5740e8c65de2ed6edec25053ea1 tree 185\n# 4476971d76569039df7569af1b8d03c288f6b193 blob 20167318 b0417e6593a1.zip\nfiles=\"$(git rev-list --objects \"$target\" | \\\n git cat-file $'--batch-check=%%(objectname) %%(objecttype) %%(objectsize) %%(rest)' | \\\n awk -F ' ' -v maxbytes=\"$maxsize\" 'BEGIN {totalIn=0} {if( $3 > maxbytes && $2 == \"blob\") { totalIn+=$3; print $4} else { totalIn+=$3}} END { printf (\"totalIn=\\t%%s\",totalIn)}' )\"\n \nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\n echo \"failed to check for large files in ref ${refname}\"\n continue\nfi\n\nIFS=$'\\n'\n# rewrite IFS to seperate line in $files\nfor file in $files; do\n # if don't unset IFS,temp_array=(${file}) will get error answer\n \n if [[ ${file} == totalIn=* ]]; then\n\tIFS=$'\\t'\n\ttemp_array=(${file})\n\tpush_size=${temp_array[1]}\n\tcontinue\n fi\n\tunset IFS\n if [[ \"$status\" == $EXIT_SUCCESS ]]; then\n\t\techo -e \"Error: Your push was rejected because it contains files larger than $(numfmt --to=iec \"$maxsize_mb\") Mb\"\n\t\techo \"help document -- https://openi.pcl.ac.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n\t\techo \"oversize files:\"\n\t\tstatus=\"$EXIT_FAILURE\"\t\n fi\n echo -e \"\\033[31m- ${file}\\033[0m \"\ndone\n\nif [[ \"$status\" != $EXIT_SUCCESS ]]; then\n\texit \"$status\"\nfi\n\ndone\n\n#######################################\n# check the repo max size limit\n#######################################\nif [[ $push_size -eq \"0\" ]]; then\n\texit $EXIT_SUCCESS\nfi\n\n# if create new branch or tag,use count-objects -v to get pack size\nif [[ $new_branch_flag -eq 1 ]]; then\n size_kb=`git count-objects -v | grep 'size-pack' | sed 's/.*\\(size-pack:\\).//'`\n size_pack_kb=`git count-objects -v | grep 'size:' | sed 's/.*\\(size:\\).//'`\n\ttotal_kb=`expr $size_kb + $size_pack_kb`\n\tlet push_size=$total_kb*1024\nfi\n\nsizelimit_mb=\"${REPO_MAX_SIZE}\"\nlet sizelimit_b=$sizelimit_mb*1024*1024\n\n# repo size at here means the size of repo directory in server \nreposize_b=${REPO_CURRENT_SIZE}\n\ntotal=`expr $push_size + $reposize_b`\n\nif [ $total -gt $sizelimit_b ]; then\n echo \"Error: Your push was rejected because the repository size is large than $sizelimit_mb Mb\"\n echo \"see the help document--https://openi.pcl.ac.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n exit $EXIT_FAILURE\nfi\n\n\nexit $EXIT_SUCCESS", setting.ScriptType),
fmt.Sprintf(""),
fmt.Sprintf(""),
}


+ 86
- 14
modules/setting/setting.go View File

@@ -519,6 +519,7 @@ var (
CullIdleTimeout string
CullInterval string


//benchmark config
IsBenchmarkEnabled bool
BenchmarkOwner string
@@ -584,6 +585,8 @@ var (
TrainJobFLAVORINFOS string
ModelArtsSpecialPools string
ModelArtsMultiNode string
//kanban
IsCloudbrainTimingEnabled bool

// modelarts-cd config
ModelartsCD = struct {
@@ -598,20 +601,33 @@ var (

//grampus config
Grampus = struct {
Env string
Host string
UserName string
Password string
SpecialPools string
C2NetSequence string
SyncScriptProject string
LocalCenterID string
AiCenterInfo string
Env string
Host string
UserName string
Password string
SpecialPools string
C2NetSequence string
SyncScriptProject string
LocalCenterID string
AiCenterInfo string
AiCenterCodeAndNameInfo string
UsageRateBeginTime string
}{}

ClearStrategy= struct {
Enabled bool
ResultSaveDays int
BatchSize int
DebugJobSize int
TrashSaveDays int
Cron string
RunAtStart bool
}{}

C2NetInfos *C2NetSqInfos
CenterInfos *AiCenterInfos
C2NetMapInfo map[string]*C2NetSequenceInfo
C2NetInfos *C2NetSqInfos
CenterInfos *AiCenterInfos
C2NetMapInfo map[string]*C2NetSequenceInfo
AiCenterCodeAndNameMapInfo map[string]*C2NetSequenceInfo

//elk config
ElkUrl string
@@ -712,6 +728,21 @@ var (
TeamName string
}{}

FileNoteBook = struct {
ProjectName string
ImageGPU string
SpecIdGPU int64
SpecIdCPU int64
ImageIdNPU string
SpecIdNPU int64
ImageIdNPUCD string
SpecIdNPUCD int64
ImageCPUDescription string
ImageGPUDescription string
ImageNPUDescription string
ImageNPUCDDescription string
}{}

ModelConvert = struct {
GPU_PYTORCH_IMAGE string
GpuQueue string
@@ -1426,7 +1457,7 @@ func NewContext() {
DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue")

sec = Cfg.Section("homepage")
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/")
RecommentRepoAddr = sec.Key("Address").MustString("https://openi.pcl.ac.cn/OpenIOSSG/promote/raw/branch/master/")
ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200")
INDEXPOSTFIX = sec.Key("INDEXPOSTFIX").MustString("")

@@ -1577,11 +1608,29 @@ func NewContext() {
Course.OrgName = sec.Key("org_name").MustString("")
Course.TeamName = sec.Key("team_name").MustString("")

sec = Cfg.Section("file_notebook")
FileNoteBook.ProjectName = sec.Key("project_name").MustString("openi-notebook")
FileNoteBook.ImageIdNPU = sec.Key("imageid_npu").MustString("")
FileNoteBook.ImageGPU = sec.Key("image_gpu").MustString("")
FileNoteBook.SpecIdCPU = sec.Key("specid_cpu").MustInt64(-1)
FileNoteBook.SpecIdGPU = sec.Key("specid_gpu").MustInt64(-1)
FileNoteBook.SpecIdNPU = sec.Key("specid_npu").MustInt64(-1)
FileNoteBook.ImageIdNPUCD = sec.Key("imageid_npu_cd").MustString("")
FileNoteBook.SpecIdNPUCD = sec.Key("specid_npu_cd").MustInt64(-1)
FileNoteBook.ImageCPUDescription = sec.Key("image_cpu_desc").MustString("")
FileNoteBook.ImageGPUDescription = sec.Key("image_gpu_desc").MustString("")
FileNoteBook.ImageNPUDescription = sec.Key("image_npu_desc").MustString("")
FileNoteBook.ImageNPUCDDescription = sec.Key("image_npu_cd_desc").MustString("")

sec = Cfg.Section("kanban")
IsCloudbrainTimingEnabled = sec.Key("ENABLED").MustBool(false)

getGrampusConfig()
getModelartsCDConfig()
getModelConvertConfig()
getModelSafetyConfig()
getModelAppConfig()
getClearStrategy()
}

func getModelSafetyConfig() {
@@ -1609,7 +1658,7 @@ func getModelConvertConfig() {
ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py")
ModelConvert.TensorFlowNpuBootFile = sec.Key("TensorFlowNpuBootFile").MustString("convert_tensorflow.py")
ModelConvert.TensorFlowGpuBootFile = sec.Key("TensorFlowGpuBootFile").MustString("convert_tensorflow_gpu.py")
ModelConvert.ConvertRepoPath = sec.Key("ConvertRepoPath").MustString("https://git.openi.org.cn/zouap/npu_test")
ModelConvert.ConvertRepoPath = sec.Key("ConvertRepoPath").MustString("https://openi.pcl.ac.cn/zouap/npu_test")
ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1)
ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1")
ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a")
@@ -1642,6 +1691,18 @@ func getModelartsCDConfig() {
getNotebookFlavorInfos()
}

func getClearStrategy(){

sec := Cfg.Section("clear_strategy")
ClearStrategy.Enabled=sec.Key("ENABLED").MustBool(false)
ClearStrategy.ResultSaveDays=sec.Key("RESULT_SAVE_DAYS").MustInt(30)
ClearStrategy.BatchSize=sec.Key("BATCH_SIZE").MustInt(500)
ClearStrategy.DebugJobSize=sec.Key("DEBUG_BATCH_SIZE").MustInt(100)
ClearStrategy.TrashSaveDays=sec.Key("TRASH_SAVE_DAYS").MustInt(90)
ClearStrategy.Cron=sec.Key("CRON").MustString("* 0,30 2-8 * * ?")
ClearStrategy.RunAtStart=sec.Key("RUN_AT_START").MustBool(false)
}

func getGrampusConfig() {
sec := Cfg.Section("grampus")

@@ -1651,6 +1712,8 @@ func getGrampusConfig() {
Grampus.Password = sec.Key("PASSWORD").MustString("")
Grampus.SpecialPools = sec.Key("SPECIAL_POOL").MustString("")
Grampus.C2NetSequence = sec.Key("C2NET_SEQUENCE").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\",\"content_en\":\"Pencheng Cloudbrain Ⅰ\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\",\"content_en\":\"Pencheng Cloudbrain Ⅱ\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\",\"content_en\":\"Peking University AI Center\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\",\"content_en\":\"Hefei AI Center\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\",\"content_en\":\"Wuhan AI Center\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\",\"content_en\":\"Xi'an AI Center\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\",\"content_en\":\"Pengcheng Cloud Computing Institute\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\",\"content_en\":\"Zhongyuan AI Center\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\",\"content_en\":\"Chengdu AI Center\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\",\"content_en\":\"Hengqin AI Center\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\",\"content_en\":\"HPC & AI Center\"}]}")
Grampus.AiCenterCodeAndNameInfo = sec.Key("AI_CENTER_CODE_AND_NAME").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\",\"content_en\":\"Pencheng Cloudbrain Ⅰ\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\",\"content_en\":\"Pencheng Cloudbrain Ⅱ\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\",\"content_en\":\"Peking University AI Center\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\",\"content_en\":\"Hefei AI Center\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\",\"content_en\":\"Wuhan AI Center\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\",\"content_en\":\"Xi'an AI Center\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\",\"content_en\":\"Pengcheng Cloud Computing Institute\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\",\"content_en\":\"Zhongyuan AI Center\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\",\"content_en\":\"Chengdu AI Center\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\",\"content_en\":\"Hengqin AI Center\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\",\"content_en\":\"HPC & AI Center\"}]}")
Grampus.UsageRateBeginTime = sec.Key("USAGE_RATE_BEGIN_TIME").MustString("2021-01-01 00:00:00")
if Grampus.C2NetSequence != "" {
if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil {
log.Error("Unmarshal(C2NetSequence) failed:%v", err)
@@ -1660,6 +1723,15 @@ func getGrampusConfig() {
C2NetMapInfo[value.Name] = value
}
}
if Grampus.AiCenterCodeAndNameInfo != "" {
if err := json.Unmarshal([]byte(Grampus.AiCenterCodeAndNameInfo), &C2NetInfos); err != nil {
log.Error("Unmarshal(AiCenterCodeAndNameInfo) failed:%v", err)
}
AiCenterCodeAndNameMapInfo = make(map[string]*C2NetSequenceInfo)
for _, value := range C2NetInfos.C2NetSqInfo {
AiCenterCodeAndNameMapInfo[value.Name] = value
}
}
Grampus.SyncScriptProject = sec.Key("SYNC_SCRIPT_PROJECT").MustString("script_for_grampus")
Grampus.LocalCenterID = sec.Key("LOCAL_CENTER_ID").MustString("cloudbrain2")
Grampus.AiCenterInfo = sec.Key("AI_CENTER_INFO").MustString("")


+ 8
- 0
modules/structs/cloudbrain.go View File

@@ -41,6 +41,14 @@ type CreateTrainJobOption struct {
SpecId int64 `json:"spec_id" binding:"Required"`
}

type CreateFileNotebookJobOption struct {
Type int `json:"type"` //0 CPU 1 GPU 2 NPU
File string `json:"file" binding:"Required"`
BranchName string `json:"branch_name" binding:"Required"`
OwnerName string `json:"owner_name" binding:"Required"`
ProjectName string `json:"project_name" binding:"Required"`
}

type Cloudbrain struct {
ID int64 `json:"id"`
JobID string `json:"job_id"`


+ 23
- 0
modules/structs/pipeline.go View File

@@ -0,0 +1,23 @@
package structs

type Pipeline struct {
ID int64 `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}
type NodeInfo struct {
Name string `json:"name"`
Status string `json:"status"`
Code string `json:"code"`
Message string `json:"message"`
}

type PipelineNotification struct {
Type int `json:"type"`
Username string `json:"username"`
Reponame string `json:"reponame"`
Pipeline Pipeline `json:"pipeline"`
PipelineRunId string `json:"pipeline_run_id"`
Node NodeInfo `json:"node"`
OccurTime int64 `json:"occur_time"`
}

+ 1
- 0
modules/structs/tagger.go View File

@@ -1,6 +1,7 @@
package structs

type Tagger struct {
ID int64 `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
RelAvatarURL string `json:"relAvatarURL"`


+ 3
- 0
modules/templates/helper.go View File

@@ -151,6 +151,9 @@ func NewFuncMap() []template.FuncMap {
"EscapePound": func(str string) string {
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
},
"IpynbBool":func(str string) bool{
return strings.Contains(str, ".ipynb")
},
"nl2br": func(text string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "<br>", -1))
},


+ 43
- 8
options/locale/locale_en-US.ini View File

@@ -24,6 +24,7 @@ enable_javascript = This website works better with JavaScript.
toc = Table of Contents
return=Back OpenI
calculation_points = Calculation Points
notice_announcement = Notice Announcement

username = Username
email = Email Address
@@ -236,7 +237,7 @@ page_title=Explore Better AI
page_small_title=OpenI AI Development Cooperation Platform
page_description=The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation
page_use=Use Now
page_only_dynamic=Only show the dynamics of open source projects
page_only_dynamic=The dynamics of open source projects
page_recommend_org=Recommended Organizations
page_recommend_org_desc=These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here,
page_recommend_org_commit=Click here to submit.
@@ -260,7 +261,7 @@ page_dev_env_desc3_title=Once Configuration, Multiple Reuse
page_dev_env_desc3_desc=Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments.
page_dev_yunlao=OpenI AI Collaboration Platform
page_dev_yunlao_desc1=OpenI AI collaboration platform has cooperated with Pengcheng cloud brain and China computing power network (C²NET) can be used to complete AI development tasks by using the rich computing resources of Pengcheng cloud brain and China computing network.
page_dev_yunlao_desc2=Pengcheng CloudBrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure consists of GPU servers equipped with NVIDIA Tesla V100 and A100, and Atlas 900 AI clusters equipped with Kunpeng and shengteng processors.
page_dev_yunlao_desc2=Pengcheng CloudBrain is existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure consists of GPU servers equipped with NVIDIA Tesla V100 and A100, and Atlas 900 AI clusters equipped with Kunpeng and shengteng processors.
page_dev_yunlao_desc3=China computing power network (C²NET) phase I can realize high-speed network interconnection between different artificial intelligence computing centers, and realize reasonable scheduling of computing power and flexible allocation of resources. At present, 11 intelligent computing centers have been connected, and the total scale of computing power is 1924p OPS@FP16. OpenI AI collaboration platform has been connected to Pengcheng Cloud Computing Institute, Chengdu Intelligent Computing Center, Zhongyuan Intelligent Computing Center, Hefei brain and other nodes.
page_dev_yunlao_desc4=Developers can freely select the corresponding computing resources according to the use needs, and can test the adaptability, performance, stability, etc. of the model in different hardware environments.
page_dev_yunlao_desc5=If your model requires more computing resources, you can also apply for it separately.
@@ -283,6 +284,7 @@ search_ge=
wecome_AI_plt = Welcome to OpenI AI Collaboration Platform!
explore_AI = Explore better AI, come here to find more interesting
datasets = Datasets
datasets_descr = Open source dataset base, seamlessly integrated with your project. View all
repositories = Repositories
use_plt__fuction = To use the AI collaboration functions provided by this platform, such as: hosting code, sharing data, debugging algorithms or training models, start with
provide_resoure = Computing resources of CPU/GPU/NPU are provided freely for various types of AI tasks.
@@ -290,6 +292,12 @@ activity = Activity
no_events = There are no events related
or_t = or
powerdby=Powered_by Pengcheng CloudBrain、China Computing NET(C²NET)、
experience_officer=Experience Officer
openi_experience_officer_plan=OpenI AI experience officer growth plan
more_benefits=, More benefits
org_see=See
more_notice=More notices
vedio_detail=Video details

[explore]
repos = Repositories
@@ -345,8 +353,10 @@ account_activated = Account has been activated
prohibit_login = Sign In Prohibited
prohibit_login_desc = Your account is prohibited to sign in, please contact your site administrator.
resent_limit_prompt = You have already requested an activation email recently. Please wait 3 minutes and try again.
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
resend_mail = Click here to resend your activation email
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>).
has_unconfirmed_mail_resend = If you did not receive the activation email, or need to resend it, please click the "Resend your activation email" button below.
has_unconfirmed_mail_change =If you need to change your email address before sending an activation email, please click the "Change email" button below.
resend_mail = Resend your activation email
email_not_associate = The email address is not associated with any account.
email_not_main=The email address is wrong, please input your primary email address.
email_not_right=The email address is not associated with any account, please input the right email address.
@@ -383,15 +393,19 @@ openid_register_desc = The chosen OpenID URI is unknown. Associate it with a new
openid_signin_desc = Enter your OpenID URI. For example: https://anne.me, bob.openid.org.cn or gnusocial.net/carry.
disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator.
email_domain_blacklisted = You cannot register with this kind of email address.
email_domain_blacklisted_change = This type of email address is not currently supported.
authorize_application = Authorize Application
authorize_redirect_notice = You will be redirected to %s if you authorize this application.
authorize_application_created_by = This application was created by %s.
authorize_application_description = If you grant the access, it will be able to access and write to all your account information, including private repos and organisations.
authorize_title = Authorize "%s" to access your account?
authorization_failed = Authorization failed
authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you've tried to authorize.
authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you have tried to authorize.
disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator.
sspi_auth_failed = SSPI authentication failed
change_email = Change email
change_email_address = Change email address
new_email_address = New email address
[phone]
format_err=The format of phone number is wrong.
query_err=Fail to query phone number, please try again later.
@@ -1007,6 +1021,8 @@ readme = README
readme_helper = Select a README file template.
auto_init = Initialize Repository (Adds .gitignore, License and README)
create_repo = Create Repository
failed_to_create_repo=Failed to create repository, please try again later.
failed_to_create_notebook_repo=Failed to create %s repository, please check whether you have the same name project, if yes please update or delete it first.
create_course = Publish Course
failed_to_create_course=Failed to publish course, please try again later.
default_branch = Default Branch
@@ -1041,6 +1057,10 @@ model_experience = Model Experience
model_noright=You have no right to do the operation.
model_rename=Duplicate model name, please modify model name.

notebook_file_not_exist=Notebook file does not exist.
notebook_select_wrong=Please select a Notebook(.ipynb) file first.
notebook_file_no_right=You have no right to access the Notebook(.ipynb) file.

date=Date
repo_add=Project Increment
repo_total=Project Total
@@ -1217,10 +1237,10 @@ cloudbrain.benchmark.evaluate_child_type=Child Type
cloudbrain.benchmark.evaluate_mirror=Mirror
cloudbrain.benchmark.evaluate_train=Train Script
cloudbrain.benchmark.evaluate_test=Test Script
cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=detection","first":"Target detection","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=reid","first":"Target re-identification","second":[{"id":1,"value":"Vehicle re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"Image-based person re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=tracking","first":"Multi-target tracking","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=detection","first":"Target detection","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=reid","first":"Target re-identification","second":[{"id":1,"value":"Vehicle re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"Image-based person re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=tracking","first":"Multi-target tracking","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.morethanonejob=You already have a running or waiting task, create it after that task is over.
cloudbrain.morethanonejob1=You have created an <span style="color:rgba(242, 113, 28, 1);"> equivalent task </span> that is waiting or running, please wait for the task to finish before creating it.
cloudbrain.morethanonejob2=You can view all your Cloud Brain tasks in <a href="/cloudbrains" target="_blank"> Home > Cloudbrain Task </a>.
cloudbrain.morethanonejob2=You can view all your Cloud Brain tasks in <a href="/cloudbrains" target="_blank"> Home > Cloudbrain Task </a>.

modelarts.infer_job_model = Model
modelarts.infer_job_model_file = Model File
@@ -1243,7 +1263,7 @@ model_Evaluation_not_created = Model evaluation has not been created
repo_not_initialized = Code version: You have not initialized the code repository, please <a href="%s"> initialized </a> first ;
debug_task_running_limit =Running time: no more than 4 hours, it will automatically stop if it exceeds 4 hours;
dataset_desc = Dataset: Cloud Brain 1 provides CPU/GPU,Cloud Brain 2 provides Ascend NPU.And dataset also needs to be uploaded to the corresponding environment;
platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning"> OpenI_Learning </a> course of Qizhi AI collaboration platform.
platform_instructions = Instructions for use: You can refer to the <a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning"> OpenI_Learning </a> course of Qizhi AI collaboration platform.
platform_instructions1 = Instructions for use: You can refer to the
platform_instructions2 = OpenI_Learning
platform_instructions3 = course of Openi AI collaboration platform.
@@ -1285,6 +1305,11 @@ model.manage.select.engine=Select model engine
model.manage.modelfile=Model file
model.manage.modellabel=Model label
model.manage.modeldesc=Model description
model.manage.modelaccess=Model Access
model.manage.modelaccess.public=Public
model.manage.modelaccess.private=Private
model.manage.modelaccess.setpublic=Set Public
model.manage.modelaccess.setprivate=Set Private
model.manage.baseinfo=Base Information
modelconvert.notcreate=No model conversion task has been created.
modelconvert.importfirst1=Please import the
@@ -1394,6 +1419,11 @@ star = Star
fork = Fork
download_archive = Download Repository
star_fail=Failed to %s the dataset.
watched=Watched
notWatched=Not watched
un_watch=Unwatch
watch_all=Watch all
watch_no_notify=Watch but not notify

no_desc = No Description
no_label = No labels
@@ -1435,6 +1465,7 @@ blame = Blame
normal_view = Normal View
line = line
lines = lines
notebook_open = Open in Notebook

editor.new_file = New File
editor.upload_file = Upload File
@@ -3188,6 +3219,9 @@ foot.copyright= Copyright: New Generation Artificial Intelligence Open Source Op
Platform_Tutorial = Tutorial
foot.advice_feedback = Feedback
resource_description = Resource Note
foot.openi_subscription_number = OpenI subscription number
foot.user_communication_group = User communication group

[cloudbrain]
all_resource_cluster=All Cluster
all_ai_center=All Computing NET
@@ -3217,6 +3251,7 @@ specification = specification
select_specification = select specification
description = description
wrong_specification=You cannot use this specification, please choose another item.
result_cleared=The files of the task have been cleared, can not restart any more, please create a new debug task instead.
resource_use=Resource Occupancy

job_name_rule = Please enter letters, numbers, _ and - up to 64 characters and cannot end with a dash (-).


+ 41
- 7
options/locale/locale_zh-CN.ini View File

@@ -24,6 +24,7 @@ enable_javascript=使用 JavaScript能使本网站更好的工作。
toc=目录
return=返回OpenI
calculation_points=算力积分
notice_announcement=通知公告

username=用户名
email=电子邮件地址
@@ -238,7 +239,7 @@ page_title=探索更好的AI
page_small_title=启智AI协作平台
page_description=面向AI领域的一站式协同开发环境,提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线
page_use=立即使用
page_only_dynamic=仅展示开源项目动态
page_only_dynamic=社区开源项目动态
page_recommend_org=推荐组织
page_recommend_org_desc=这些优秀的组织正在使用启智AI开发协作平台;你的组织也想展示到这里,
page_recommend_org_commit=点此提交
@@ -285,6 +286,7 @@ search_ge=个
wecome_AI_plt=欢迎来到启智AI协作平台!
explore_AI = 探索更好的AI,来这里发现更有意思的
datasets = 数据集
datasets_descr=开源数据集大本营,同你的项目无缝集成。查看所有
repositories = 项目
use_plt__fuction = 使用本平台提供的AI协作功能,如:托管代码、共享数据、调试算法或训练模型,请先
provide_resoure = 平台目前提供CPU、GPU、NPU的普惠算力资源,可进行多种类型的AI任务。
@@ -293,7 +295,12 @@ activity = 活动
no_events = 还没有与您相关的活动
or_t = 或
powerdby=Powered_by 鹏城实验室云脑、中国算力网(C²NET)、

experience_officer=体验官
openi_experience_officer_plan=启智社区体验官成长计划
more_benefits=,超多福利大放送
org_see=。查看
more_notice=更多通知
vedio_detail=详细介绍视频

[explore]
repos=项目
@@ -349,8 +356,10 @@ account_activated=帐户已激活
prohibit_login=禁止登录
prohibit_login_desc=您的帐户被禁止登录,请与网站管理员联系。
resent_limit_prompt=您请求发送激活邮件过于频繁,请等待 3 分钟后再试!
has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 <b>%s</b> 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。
resend_mail=单击此处重新发送确认邮件
has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 <b>%s</b> 但未被确认的邮件。
has_unconfirmed_mail_resend=如果您未收到激活邮件,或需要重新发送,请单击下方的 "重新发送确认邮件 " 按钮。
has_unconfirmed_mail_change=如果您需要更改邮箱后再发送激活邮件,请单击下方的 "修改邮箱" 按钮。
resend_mail=重新发送确认邮件
email_not_associate=您输入的邮箱地址未被关联到任何帐号!
email_not_main=电子邮箱地址不正确,请输入您设置的主要邮箱地址。
email_not_right=您输入了不存在的邮箱地址,请输入正确的邮箱地址。
@@ -387,6 +396,7 @@ openid_register_desc=所选的 OpenID URI 未知。在这里关联一个新帐
openid_signin_desc=输入您的 OpenID URI。例如: https://anne.me、bob.openid.org.cn 或 gnusocial.net/carry。
disable_forgot_password_mail=帐户恢复功能已被禁用。请与网站管理员联系。
email_domain_blacklisted=暂不支持此类电子邮件地址注册。
email_domain_blacklisted_change=暂不支持此类电子邮件地址。
authorize_application=应用授权
authorize_redirect_notice=如果您授权此应用,您将会被重定向到 %s。
authorize_application_created_by=此应用由%s创建。
@@ -396,6 +406,9 @@ authorization_failed=授权失败
authorization_failed_desc=授权失败,这是一个无效的请求。请联系尝试授权应用的管理员。
disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator.
sspi_auth_failed=SSPI 认证失败
change_email=修改邮箱
change_email_address=修改邮箱地址
new_email_address=新邮箱地址
[phone]
format_err=手机号格式错误。
query_err=查询手机号失败,请稍后再试。
@@ -1013,6 +1026,8 @@ readme=自述
readme_helper=选择自述文件模板。
auto_init=初始化存储库 (添加. gitignore、许可证和自述文件)
create_repo=创建项目
failed_to_create_repo=创建项目失败,请稍后再试。
failed_to_create_notebook_repo=创建项目%s失败,请检查您是否有同名的项目,如果有请先手工修改或删除后重试。
create_course=发布课程
failed_to_create_course=发布课程失败,请稍后再试。
default_branch=默认分支
@@ -1041,6 +1056,9 @@ model_experience = 模型体验
model_noright=您没有操作权限。
model_rename=模型名称重复,请修改模型名称

notebook_file_not_exist=Notebook文件不存在。
notebook_select_wrong=请先选择Notebook(.ipynb)文件。
notebook_file_no_right=您没有这个Notebook文件的读权限。

date=日期
repo_add=新增项目
@@ -1230,8 +1248,8 @@ cloudbrain.benchmark.evaluate_child_type=子类型
cloudbrain.benchmark.evaluate_mirror=镜像
cloudbrain.benchmark.evaluate_train=训练程序
cloudbrain.benchmark.evaluate_test=测试程序
cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=detection","first":"目标检测","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=reid","first":"目标重识别","second":[{"id":1,"value":"车辆重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"基于图像的行人重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=tracking","first":"多目标跟踪","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.benchmark.model.types={"type":[{"id":1,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=detection","first":"目标检测","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=reid","first":"目标重识别","second":[{"id":1,"value":"车辆重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"基于图像的行人重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=tracking","first":"多目标跟踪","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=detection","first":"目标检测","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=reid","first":"目标重识别","second":[{"id":1,"value":"车辆重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"基于图像的行人重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=tracking","first":"多目标跟踪","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.benchmark.model.types={"type":[{"id":1,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=detection","first":"目标检测","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=reid","first":"目标重识别","second":[{"id":1,"value":"车辆重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"基于图像的行人重识别","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://openi.pcl.ac.cn/benchmark/?username=admin&algType=tracking","first":"多目标跟踪","second":[{"id":1,"value":"无","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]}
cloudbrain.morethanonejob=您已经创建了一个正在等待或运行中的同类任务,请等待任务结束再创建。
cloudbrain.morethanonejob1=您已经有 <span style="color:rgba(242, 113, 28, 1);">同类任务</span> 正在等待或运行中,请等待任务结束再创建;
cloudbrain.morethanonejob2=可以在 “<a href="/cloudbrains" target="_blank" >个人中心 > 云脑任务</a>” 查看您所有的云脑任务。
@@ -1257,7 +1275,7 @@ model_Evaluation_not_created = 未创建过评测任务
repo_not_initialized = 代码版本:您还没有初始化代码仓库,请先<a href=%s>创建代码版本</a>;
debug_task_running_limit = 运行时长:最长不超过4个小时,超过4个小时将自动停止;
dataset_desc = 数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境;
platform_instructions = 使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程</a>。
platform_instructions = 使用说明:可以参考启智AI协作平台<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning">小白训练营课程</a>。
platform_instructions1 = 使用说明:可以参考启智AI协作平台
platform_instructions2 = 小白训练营课程
platform_instructions3 = 。
@@ -1300,6 +1318,11 @@ model.manage.select.engine=选择模型框架
model.manage.modelfile=模型文件
model.manage.modellabel=模型标签
model.manage.modeldesc=模型描述
model.manage.modelaccess=模型权限
model.manage.modelaccess.public=公开
model.manage.modelaccess.private=私有
model.manage.modelaccess.setpublic=设为公开
model.manage.modelaccess.setprivate=设为私有
model.manage.baseinfo=基本信息
modelconvert.notcreate=未创建过模型转换任务
modelconvert.importfirst1=请您先导入
@@ -1411,6 +1434,11 @@ star=点赞
fork=派生
download_archive=下载此项目
star_fail=%s失败。
watched=已关注
notWatched=未关注
un_watch=不关注
watch_all=关注所有动态
watch_no_notify=关注但不提醒动态


no_desc=暂无描述
@@ -1454,6 +1482,8 @@ normal_view=普通视图
line=行
lines=行

notebook_open = 在Notebook中打开

editor.new_file=新建文件
editor.upload_file=上传文件
editor.edit_file=编辑文件
@@ -3206,6 +3236,8 @@ foot.copyright= 版权所有:新一代人工智能开源开放平台(OpenI
Platform_Tutorial=新手指引
foot.advice_feedback = 意见反馈
resource_description = 资源说明
foot.openi_subscription_number = 启智社区订阅号
foot.user_communication_group = 用户交流群

[cloudbrain]
all_resource_cluster=全部集群
@@ -3239,6 +3271,8 @@ card_duration = 运行卡时
card_type = 卡类型
wrong_specification=您目前不能使用这个资源规格,请选择其他资源规格。

result_cleared=本任务的文件已被清理,无法再次调试,请新建调试任务。

job_name_rule = 请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。
train_dataset_path_rule = 数据集位置存储在运行参数 <strong style="color:#010101">data_url</strong> 中,预训练模型存放在运行参数 <strong style="color:#010101">ckpt_url</strong> 中,训练输出路径存储在运行参数 <strong style="color:#010101">train_url</strong> 中。
infer_dataset_path_rule = 数据集位置存储在运行参数 <strong style="color:#010101">data_url</strong> 中,推理输出路径存储在运行参数 <strong style="color:#010101">result_url</strong> 中。


+ 374
- 56
public/home/home.js View File

@@ -9,16 +9,20 @@ if(isEmpty(token)){

var swiperNewMessage = new Swiper(".newslist", {
direction: "vertical",
slidesPerView: 9,
slidesPerView: 6,
loop: true,
spaceBetween: 8,
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
});
var swiperEvent = new Swiper(".event-list", {
slidesPerView: 3,
spaceBetween: 30,

var swiperRepo = new Swiper(".homepro-list", {
slidesPerView: 1,
// slidesPerColumn: 2,
// slidesPerColumnFill:'row',
spaceBetween: 20,
pagination: {
el: ".swiper-pagination",
clickable: true,
@@ -27,49 +31,130 @@ var swiperEvent = new Swiper(".event-list", {
delay: 2500,
disableOnInteraction: false,
},
breakpoints: {
768: {
slidesPerView: 2,
},
1024: {
slidesPerView: 2,
},
1200: {
slidesPerView: 3,
},
1440: {
slidesPerView: 3,
},
1840: {
slidesPerView: 3,
},
1920: {
slidesPerView: 3,
},
},
});
var swiperRepo = new Swiper(".homepro-list", {

var swiperOrg = new Swiper(".homeorg-list", {
slidesPerView: 1,
slidesPerColumn: 2,
slidesPerColumnFill:'row',
spaceBetween: 30,
spaceBetween: 25,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
autoplay: {
delay: 2500,
delay: 4500,
disableOnInteraction: false,
},
breakpoints: {
768: {
slidesPerView: 2,
slidesPerView: 3,
slidesPerColumn: 2,
},
1024: {
slidesPerView: 3,
slidesPerColumn: 2,
},
1200: {
slidesPerView: 4,
slidesPerColumn: 2,
},
1440: {
slidesPerView: 4,
slidesPerColumn: 2,
},
1840: {
slidesPerView: 4,
slidesPerColumn: 2,
},
1920: {
slidesPerView: 4,
slidesPerColumn: 2,
},
},
});

var swiperOrg = new Swiper(".homeorg-list", {
var swiperUserExp = new Swiper(".home-user-exp-list", {
slidesPerView: 1,
slidesPerColumn: 4,
spaceBetween: 0,
navigation: {
nextEl: '.homeuserexp .swiper-prev',
prevEl: '.homeuserexp .swiper-next',
},
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
breakpoints: {
768: {
slidesPerView: 2,
},
1200: {
slidesPerView: 3,
},
1440: {
slidesPerView: 4,
},
1840: {
slidesPerView: 4,
},
1920: {
slidesPerView: 5,
},
},
});

var swiperDataset = new Swiper(".home-dataset-list", {
slidesPerView: 2,
slidesPerColumn: 1,
slidesPerColumnFill:'row',
spaceBetween: 15,
spaceBetween: 30,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
autoplay: {
delay: 4500,
delay: 2500,
disableOnInteraction: false,
},
breakpoints: {
676: {
slidesPerView: 3,
},
768: {
slidesPerView: 2,
slidesPerView: 4,
},
1024: {
slidesPerView: 3,
1320: {
slidesPerView: 5,
},
1520: {
slidesPerView: 6,
},
1720: {
slidesPerView: 7,
},
1920: {
slidesPerView: 7,
},
},
});
@@ -85,7 +170,7 @@ document.onreadystatechange = function () {
if(document.readyState != "complete"){
return;
}
console.log("Start to open WebSocket." + document.readyState);
console.log("Start to open WebSocket." + document.readyState);
queryRecommendData();

var output = document.getElementById("newmessage");
@@ -101,6 +186,7 @@ document.onreadystatechange = function () {
};

socket.onmessage = function (e) {
if (!output) return;
var data =JSON.parse(e.data)
var html = "";
if (data != null){
@@ -177,18 +263,17 @@ document.onreadystatechange = function () {
var time = getTime(record.CreatedUnix,currentTime);
html += " " + time;
}
html += "</div>";
html += "</div></div>";
html += "</div>";
}
}
output.innerHTML = html;
$('#homenews p').show();
swiperNewMessage.updateSlides();
swiperNewMessage.updateProgress();
};
}



function getTaskLink(record){
var re = getRepoLink(record);
if(record.OpType == 24){
@@ -223,7 +308,7 @@ function getMsg(record){
}else{
console.log("act user is null.");
}
html += " <img class=\"ui avatar image\" src=\"/user/avatar/" + name + "/-1\" alt=\"\">"
html += "<div class=\"content-c\"><img class=\"ui avatar image\" src=\"/user/avatar/" + name + "/-1\" alt=\"\">"
html += " <div class=\"middle aligned content nowrap\">"
html += " <a href=\"/" + encodeURI(name) + "\" title=\"\">" + name + "</a>"
return html;
@@ -236,6 +321,7 @@ function getRepotext(record){
return record.Repo.OwnerName + "/" + record.Repo.Name;
}
}

function getRepoLink(record){
return encodeURI(record.Repo.OwnerName + "/" + record.Repo.Name);

@@ -437,10 +523,6 @@ function getAction(opType,isZh){
}
}





function queryRecommendData(){
$.ajax({
type:"GET",
@@ -453,7 +535,10 @@ function queryRecommendData(){
success:function(json){
displayOrg(json.org);
displayRepo(json.repo);
displayActivity(json.image);
displayActivity(json.activity);
displayDataset(json.dataset);
displayUserExp(json.user_experience);
LetterAvatar && LetterAvatar.transform();
},
error:function(response) {
}
@@ -463,49 +548,99 @@ function queryRecommendData(){

function displayActivity(json){
var activityDiv = document.getElementById("recommendactivity");
if (!activityDiv) return;
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"swiper-slide\">";
html += "<a href=\"" + record["image_link"] + "\" class=\"ui fluid card\">";
html += " <div class=\"image\"><img src=\"" + record["url"] + "\"></div>"
var record = json[i];
var name = isZh ? (record["name"] || '') : (record["name_en"] || record["name"]);
html += "<div class=\"swiper-slide\" style=\"text-align:center;\">";
html += "<a href=\"" + record["image_link"] + "\">";
html += " <div class=\"image ui card\"><img src=\"" + record["url"] + "\">";
html += ' <div class="image-name" title="' + name + '">' + name + "</div>";
html += "</div>";
html += "</a>";
html += "</div>";
}
var swiperEvent = new Swiper(".event-list", {
slidesPerView: 1,
spaceBetween: 30,
// pagination: {
// el: ".swiper-pagination",
// clickable: true,
// },
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
breakpoints: {
768: {
slidesPerView: Math.min(2, json.length),
},
1024: {
slidesPerView: Math.min(3, json.length),
},
1200: {
slidesPerView: Math.min(3, json.length),
},
1440: {
slidesPerView: Math.min(4, json.length),
},
1840: {
slidesPerView: Math.min(4, json.length),
},
1920: {
slidesPerView: Math.min(4, json.length),
},
},
});
activityDiv.innerHTML = html;
swiperEvent.updateSlides();
swiperEvent.updateProgress();
}
activityDiv.innerHTML = html;
swiperEvent.updateSlides();
swiperEvent.updateProgress();
}

function displayRepo(json){
var orgRepo = document.getElementById("recommendrepo");
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"swiper-slide\">";
html += " <div class=\"ui fluid card\">";
html += " <div class=\"content\">";
html += " <span class=\"right floated meta\">";
html += " <i class=\"ri-star-line\"></i>" + record["NumStars"] + "<i class=\"ri-git-branch-line am-ml-10\"></i>" + record["NumForks"];
html += " </span>";
html += " <img class=\"left floated mini ui image\" src=\"" + record["Avatar"] + "\">";
html += " <a class=\"header nowrap\" href=\"/" + record["OwnerName"] + "/" + record["Name"] + "\">" + record["Alias"] +"</a>";
html += " <div class=\"description nowrap-2\">" + record["Description"] + " </div>";
html += " <div class=\"ui tags nowrap am-mt-10\">"
if(record["Topics"] != null){
for(var j = 0; j < record["Topics"].length; j++){
topic = record["Topics"][j];
url = "/explore/repos?q=" + (topic) + "&amp;topic="
html += "<a class=\"ui small label topic\" href=\"" + url + "\">" + topic + "</a>";
}
var repoMap = {};
for (var i = 0, iLen = json.length; i < iLen; i++) {
var repo = json[i];
var label = isZh ? repo.Label : repo.Label_en;
if (repoMap[label]) {
repoMap[label].push(repo);
} else {
repoMap[label] = [repo];
}
html += " </div>";
html += " </div>";
html += " </div>";
html += "</div>";
}

for (var label in repoMap) {
var repos = repoMap[label];
var labelSearch = repos[0].Label;
html += `<div class="swiper-slide"><div><a style="color:rgb(50, 145, 248);font-size:16px;font-weight:550;" href="/explore/repos?q=&topic=${labelSearch}&sort=hot"># ${label}</a></div>`;
for (var i = 0, iLen = repos.length; i < iLen; i++) {
if (i >= 4) break;
var repo = repos[i];
// <i class="ri-star-line"></i>${repo["NumStars"]}<i class="ri-git-branch-line am-ml-10"></i>${repo["NumForks"]}</span> <div class="ui tags nowrap am-mt-10"></div>
html += `<div class="ui fluid card" style="border-radius:6px;">
<div class="content">
${repo["Avatar"] ? `<img class="left floated mini ui image" src="${repo["Avatar"]}">` : `<img class="left floated mini ui image" avatar="${repo["OwnerName"]}">`}
<a class="header nowrap" style="color:rgb(50, 145, 248);font-size:14px;" href="/${repo["OwnerName"]}/${repo["Name"]}" title="${repo["Alias"]}">${repo["Alias"]}</a>
<div class="description nowrap-2" style="rgba(136,136,136,1);;font-size:12px;" title="${repo["Description"]}">${repo["Description"]}</div>
`;
// if (repo["Topics"] != null) {
// for(var j = 0; j < repo["Topics"].length; j++){
// var topic = repo["Topics"][j];
// var url = "/explore/repos?q=" + (topic) + "&amp;topic="
// html += `<a class="ui small label topic" href=" ${url}">${topic}</a>`;
// }
// }
html += `
</div>
</div>`;
}
html += '</div>'
}
}
orgRepo.innerHTML = html;
@@ -513,7 +648,6 @@ function displayRepo(json){
swiperRepo.updateProgress();
}


function getRepoOrOrg(key,isZhLang,numbers=1){
if(numbers > 1){
key+="1";
@@ -537,7 +671,7 @@ function displayOrg(json){
html += " <img class=\"ui image\" src=\"" + record["Avatar"] + "\">";
html += " <div class=\"content nowrap\">";
html += " <span class=\"ui blue\">" + record["Name"] + "</span> " + record["FullName"];
html += " <div class=\"sub header\">" + record["NumRepos"] +" " + getRepoOrOrg(1,isZh,record["NumRepos"]) + " ・ " + record["NumMembers"] +" " + getRepoOrOrg(2,isZh,record["NumMembers"]) + " ・ " + record["NumTeams"] + " " + getRepoOrOrg(3,isZh,record["NumTeams"]) + "</div>";
html += " <div class=\"sub header\" style=\"margin-top:4px;\"><span style=\"color:rgb(54, 56, 64)\">" + record["NumRepos"] +"</span> " + getRepoOrOrg(1,isZh,record["NumRepos"]) + " ・ <span style=\"color:rgb(54, 56, 64)\">" + record["NumMembers"] +"</span> " + getRepoOrOrg(2,isZh,record["NumMembers"]) + " ・ <span style=\"color:rgb(54, 56, 64)\">" + record["NumTeams"] + "</span> " + getRepoOrOrg(3,isZh,record["NumTeams"]) + "</div>";
html += " </div>";
html += " </div>";
html += " </div>";
@@ -548,3 +682,187 @@ function displayOrg(json){
orgDiv.innerHTML = html;
swiperOrg.updateSlides();
}

function displayDataset(data) {
var homeDatasetEl = document.getElementById("home_dataset");
if (!homeDatasetEl) return;
var html = '';
var svgStrMap = {
'0': '<svg xmlns="http://www.w3.org/2000/svg" class="svg svg-icon-path-icon fill" viewBox="0 0 32 32" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93em9ydx6bi61,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><path d="M16 4c7.189 0 13.171 5.173 14.425 12-1.253 6.827-7.236 12-14.425 12s-13.171-5.173-14.425-12c1.253-6.827 7.236-12 14.425-12zM16 25.333c5.682-0.001 10.442-3.949 11.687-9.252l0.016-0.081c-1.265-5.379-6.024-9.322-11.703-9.322s-10.437 3.943-11.686 9.241l-0.016 0.081c1.261 5.384 6.021 9.332 11.703 9.333h0zM16 22c-3.314 0-6-2.686-6-6s2.686-6 6-6v0c3.314 0 6 2.686 6 6s-2.686 6-6 6v0zM16 19.333c1.841 0 3.333-1.492 3.333-3.333s-1.492-3.333-3.333-3.333v0c-1.841 0-3.333 1.492-3.333 3.333s1.492 3.333 3.333 3.333v0z"></path></g></svg>',
'1': '<svg xmlns="http://www.w3.org/2000/svg" class="svg svg-icon-path-icon fill" viewBox="0 0 32 32" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93gapd7aoa4d1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><path d="M2.667 16c0-7.364 5.969-13.333 13.333-13.333s13.333 5.969 13.333 13.333-5.969 13.333-13.333 13.333h-13.333l3.905-3.905c-2.413-2.407-3.905-5.735-3.905-9.411 0-0.006 0-0.012 0-0.018v0.001zM9.104 26.667h6.896c5.891 0 10.667-4.776 10.667-10.667s-4.776-10.667-10.667-10.667c-5.891 0-10.667 4.776-10.667 10.667v0c0 2.869 1.135 5.553 3.124 7.543l1.885 1.885-1.239 1.239zM14.667 8h2.667v16h-2.667v-16zM9.333 12h2.667v8h-2.667v-8zM20 12h2.667v8h-2.667v-8z"></path></g></svg>',
'2': '<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 lhfskE svg-icon-path-icon fill" viewBox="0 0 48 48" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93j5tkotzm421,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><rect width="48" height="48" fill-opacity="0.01" fill="url(#ila93j5tkotzm421,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" storke="none"></rect><path stroke="url(#ila93j5tkotzm421,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" d="M4 24C4 24 10 15 14 15C18 15 22 17 24 17C26 17 30 15 34 15C38 15 44 24 44 24C44 24 34 34 24 34C14 34 4 24 4 24Z" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path stroke="url(#ila93j5tkotzm421,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" d="M4 24H44" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>',
'3': '<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 beWLko svg-icon-path-icon fill" viewBox="0 0 48 48" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><path d="M6 25C6 15.0589 14.0589 7 24 7C30.8669 7 36.8357 10.8453 39.8706 16.5" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M41 25H43L42 24L41 25Z" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M31 34L28.375 27L25 18H23L19.625 27L17 34" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M28.375 27H19.625" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M7 25H5L6 26L7 25Z" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M42 25C42 34.9411 33.9411 43 24 43C17.1331 43 11.1643 39.1547 8.12939 33.5" stroke="url(#ila93k86om2ayqg1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path></g></svg>',
'4': '<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 kqqJug svg-icon-path-icon fill" viewBox="0 0 48 48" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93lcoqm7710i1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><path d="M33 4.99976H41C42.1046 4.99976 43 5.89519 43 6.99976V14.9998M43 32.9998V40.9998C43 42.1043 42.1046 42.9998 41 42.9998H33M15 42.9998H7C5.89543 42.9998 5 42.1043 5 40.9998V32.9998M5 14.9998V6.99976C5 5.89519 5.89543 4.99976 7 4.99976H15" stroke="url(#ila93lcoqm7710i1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M24 38C30.6274 38 36 31.732 36 24C36 16.268 30.6274 10 24 10C17.3726 10 12 16.268 12 24C12 31.732 17.3726 38 24 38Z" stroke="url(#ila93lcoqm7710i1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M6 24H42" stroke="url(#ila93lcoqm7710i1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path><path d="M20.0693 30.1057C21.3372 31.0429 22.6473 31.5115 23.9996 31.5115C25.3519 31.5115 26.698 31.0429 28.0378 30.1057" stroke="url(#ila93lcoqm7710i1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path></g></svg>',
'5': '<svg xmlns="http://www.w3.org/2000/svg" class="svg svg-icon-path-icon fill" viewBox="0 0 32 32" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93mrrwzocn0r1,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><path d="M16 26.667c5.891 0 10.667-4.776 10.667-10.667s-4.776-10.667-10.667-10.667v0c-5.891 0-10.667 4.776-10.667 10.667s4.776 10.667 10.667 10.667v0zM16 29.333c-7.364 0-13.333-5.969-13.333-13.333s5.969-13.333 13.333-13.333 13.333 5.969 13.333 13.333-5.969 13.333-13.333 13.333zM16 21.333c2.946 0 5.333-2.388 5.333-5.333s-2.388-5.333-5.333-5.333v0c-2.946 0-5.333 2.388-5.333 5.333s2.388 5.333 5.333 5.333v0zM16 24c-4.418 0-8-3.582-8-8s3.582-8 8-8v0c4.418 0 8 3.582 8 8s-3.582 8-8 8v0zM16 18.667c-1.473 0-2.667-1.194-2.667-2.667s1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667s-1.194 2.667-2.667 2.667v0z"></path></g></svg>',
'6': '<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 cAmoNA svg-icon-path-icon fill" viewBox="0 0 48 48" width="32" height="32"><defs data-reactroot=""><linearGradient id="ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#82d1f6" stop-opacity="1" offset="0"></stop><stop stop-color="#29b6f4" stop-opacity="1" offset="0.5"></stop><stop stop-color="#0089cd" stop-opacity="1" offset="0.99"></stop></linearGradient></defs><g><rect width="48" height="48" fill="white" fill-opacity="0.01"></rect><path d="M14.5397 20.0186C12.8522 17.9434 11.2675 17.4979 9.78564 18.6821C7.5629 20.4583 6.92453 26.6496 8.71324 32.1086C10.502 37.5676 13.9801 45.0017 21.0016 45.0017C28.0231 45.0017 29.684 37.5222 32.5485 33.0001C35.413 28.478 36.9285 24.1152 34.1208 18.6821" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11 18.0368C9.29707 15.4428 7.96374 13.4306 6.99996 12.0002C5.5543 9.85464 9.25107 7.08164 11 8.96807C12.1659 10.2257 13.7148 12.078 15.6466 14.5249" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path><path d="M15.0236 25.6396C14.5391 19.5759 14.9333 15.6276 16.2062 13.7947C18.1155 11.0455 21.6631 10.0031 25.0035 10.0031C26.9924 10.0031 28.8087 10.8502 30.4525 12.5444" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M41.0003 12.6128C41.5858 14.6492 40.6294 16.5097 37.6844 16.931C34.7393 17.3523 32.5313 18.8332 30.9388 20.079C29.3463 21.3248 26.4983 25.1046 25.9361 27.0023C25.3738 28.9 22.1602 27.1547 21.2971 26.3971C20.434 25.6394 19.5855 23.9806 21.2971 22.2457C23.0086 20.5108 22.6383 20.1646 22.6383 18.4052C22.6383 16.6459 32.0003 10.8263 37.2729 10.2941C38.4449 10.2257 40.4147 10.5763 41.0003 12.6128Z" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4"></path><path d="M23.0078 4.00014V9.26283" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path><path d="M20.3066 10.7178C17.2888 6.92534 14.8555 4.80868 13.0068 4.36781" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path><path d="M17.0039 7.02894L17.9944 2.96156" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path><path d="M35.6128 10.7174C35.2905 11.8219 35.2905 12.8575 35.6128 13.8241C35.935 14.7908 36.6255 15.8264 37.6842 16.9308" stroke="url(#ila93oiqy4t1x861,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs)" fill="none" stroke-width="4" stroke-linecap="round"></path></g></svg>',
}
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
html += `<div class="swiper-slide">
<a href="/explore/datasets?sort=default&q=&tab=&category=&task=${dataI.task}&license=">
<div class="ui fluid dataset-card">
<div><div class="content icon-c">
${svgStrMap[i % 7]}
</div></div>
<div><div class="content label" title="${i18n[dataI.task] || dataI.task}">${i18n[dataI.task] || dataI.task}</div></div>
<div><div class="content count" style="">${i18n['about']} ${dataI.total} ${i18n['count']}</div></div>
</div>
</a>
</div>`
}
homeDatasetEl.innerHTML = html;
swiperDataset.updateSlides();
swiperDataset.updateProgress();
}

function displayUserExp(data) {
var homeUserExpEl = document.getElementById("home_user-exp");
if (!homeUserExpEl) return;
var html = '';
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
html += `<div class="swiper-slide">
<div class="ui fluid user-card">
<div><div class="content img-c">
<a href="/${dataI.name}">
<div class="img" style="width:60px;height:60px;background-image:url('${dataI.avatar}')"></div>
</a>
</div></div>
<div><div class="content label" title="${dataI.fullname || dataI.name}">${dataI.fullname || dataI.name}</div></div>
<div><div class="content descr" title="${dataI.desc}">${dataI.desc}</div></div>
</div>
</div>`
}
homeUserExpEl.innerHTML = html;
swiperUserExp.updateSlides();
swiperUserExp.updateProgress();
}

function getNotice() {
$.ajax({
type:"GET",
url:"/dashboard/invitation",
headers: { authorization:token, },
dataType:"json",
data: {
filename: 'notice/notice.json',
},
success:function(json){
if (json) {
try {
var noticeList = JSON.parse(json).Notices || [];
var noticeEls = $('._hm-recommend-info-area-1 a._hm-notice');
for (var i = 0, iLen = noticeEls.length; i < iLen; i++) {
var noticeEl = noticeEls.eq(i);
var noticeObj = noticeList[i];
if (noticeObj) {
var title = isZh ? noticeObj.Title : (noticeObj.Title_en || noticeObj.Title);
noticeEl.attr('href', noticeObj.Link);
noticeEl.find('span').text(title).attr('title', title);
noticeEl.show();
} else {
noticeEl.hide();
}
}
} catch (e) {
console.info(e);
}
}
},
error:function(response) {
}
});
}

function getRecommendModule() {
$.ajax({
type:"GET",
url:"/dashboard/invitation",
headers: { authorization:token, },
dataType:"json",
data: {
filename: 'home/newfunction',
},
success:function(json){
if (json) {
try {
var recommendModuleList = JSON.parse(json) || [];
var recommendModuleEls = $('._hm-recommend-info-area a._hm-link');
for (var i = 0, iLen = recommendModuleEls.length; i < iLen; i++) {
var recommendModuleEl = recommendModuleEls.eq(i);
var recommendModuleObj = recommendModuleList[i];
if (recommendModuleObj) {
recommendModuleEl.attr('href', recommendModuleObj.image_link);
recommendModuleEl.text(isZh ? recommendModuleObj.name : (recommendModuleObj.name_en || recommendModuleObj.name));
} else {
}
}
} catch (e) {
console.info(e);
}
}
},
error:function(response) {
}
});
}

function initHomeTopBanner() {
var homeSlideTimer = null;
var homeSlideDuration = 8000;
function homeSlide(direction, index) {
var slidePages = $('._hm-pg-c ._hm-pg');
var currentPage = slidePages.filter('._hm-pg-show');
var slidePagination = $('._hm-slide-pagination-c ._hm-slide-pagination-item');
var currentIndex = currentPage.index();
var next = 0;
if (direction) {
next = direction == 'left' ? currentIndex - 1 : currentIndex + 1;
} else {
next = index || 0;
}
if (next < 0) next = slidePages.length - 1;
if (next == slidePages.length) next = 0;
slidePages.removeClass('_hm-pg-show');
slidePages.eq(next).addClass('_hm-pg-show');
slidePagination.removeClass('_hm-slide-pagination-item-active');
slidePagination.eq(next).addClass('_hm-slide-pagination-item-active');
}

function startSlide() {
homeSlideTimer && clearTimeout(homeSlideTimer);
homeSlideTimer = setTimeout(function() {
homeSlide('right');
startSlide();
}, homeSlideDuration);
}

function stopSlide() {
homeSlideTimer && clearTimeout(homeSlideTimer);
}

$('._hm-slide-btn').on('click', function () {
if ($(this).hasClass('_hm-slide-btn-left')) {
homeSlide('left');
} else {
homeSlide('right');
}
startSlide();
});
$('._hm-pg #homenews').on('mouseenter', function() {
stopSlide();
}).on('mouseleave', function() {
startSlide();
});
$('._hm-slide-pagination-c ._hm-slide-pagination-item').on('click', function() {
var self = $(this);
if (self.hasClass('_hm-slide-pagination-item-active')) return;
homeSlide('', self.index());
startSlide();
});
setTimeout(function() { startSlide(); }, 500);
}

initHomeTopBanner();
getNotice();
getRecommendModule();

+ 1
- 1
public/img/search.svg View File

@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638433773401" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2884" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M469.333333 768c-166.4 0-298.666667-132.266667-298.666666-298.666667s132.266667-298.666667 298.666666-298.666666 298.666667 132.266667 298.666667 298.666666-132.266667 298.666667-298.666667 298.666667z m0-85.333333c119.466667 0 213.333333-93.866667 213.333334-213.333334s-93.866667-213.333333-213.333334-213.333333-213.333333 93.866667-213.333333 213.333333 93.866667 213.333333 213.333333 213.333334z m251.733334 0l119.466666 119.466666-59.733333 59.733334-119.466667-119.466667 59.733334-59.733333z" fill="#5BB973" p-id="2885"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 fPsHiw svg-icon-path-icon fill" viewBox="0 0 32 32" width="24" height="24"><defs data-reactroot=""></defs><g><path fill="rgb(255, 255, 255)" d="M14.667 2.667c6.624 0 12 5.376 12 12s-5.376 12-12 12-12-5.376-12-12 5.376-12 12-12zM14.667 24c5.156 0 9.333-4.177 9.333-9.333 0-5.157-4.177-9.333-9.333-9.333-5.157 0-9.333 4.176-9.333 9.333 0 5.156 4.176 9.333 9.333 9.333zM25.98 24.095l3.772 3.771-1.887 1.887-3.771-3.772 1.885-1.885z"></path></g></svg>

+ 6
- 2
routers/admin/cloudbrains.go View File

@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
)

const (
@@ -95,6 +96,8 @@ func CloudBrains(ctx *context.Context) {
models.LoadSpecs4CloudbrainInfo(ciTasks)

for i, task := range ciTasks {
ciTasks[i] = cloudbrainService.UpdateCloudbrainAiCenter(ciTasks[i])
ciTasks[i].Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(ciTasks[i].Cloudbrain.AiCenter, ctx.Language())
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
@@ -186,7 +189,8 @@ func DownloadCloudBrains(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(pageRecords)
for _, record := range pageRecords {

record = cloudbrainService.UpdateCloudbrainAiCenter(record)
record.Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(record.Cloudbrain.AiCenter, ctx.Language())
for k, v := range allValues(row, record, ctx) {
f.SetCellValue(cloudBrain, k, v)
}
@@ -208,7 +212,7 @@ func allValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[str
return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): repo.GetCloudbrainCluster(rs.Cloudbrain, ctx),
getCellName("C", row): rs.JobType, getCellName("D", row): rs.Status, getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT),
getCellName("F", row): getDurationTime(rs), getCellName("G", row): rs.ComputeResource,
getCellName("H", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("I", row): getCloudbrainCardType(rs),
getCellName("H", row): rs.Cloudbrain.AiCenter, getCellName("I", row): getCloudbrainCardType(rs),
getCellName("J", row): rs.Name, getCellName("K", row): getRepoPathName(rs), getCellName("L", row): rs.JobName,
}
}


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

@@ -544,6 +544,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/complete_multipart", repo.CompleteMultipart)

}, reqToken())
m.Group("/pipeline", func() {
m.Post("/notification", bind(api.PipelineNotification{}), notify.PipelineNotify)

}, reqToken())

// Notifications
m.Group("/notifications", func() {
@@ -610,10 +614,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/query_invitation_yesterday", operationReq, repo_ext.QueryInvitationYesterday)
m.Get("/query_invitation_all", operationReq, repo_ext.QueryInvitationAll)
m.Get("/query_invitation_userdefine", operationReq, repo_ext.QueryUserDefineInvitationPage)
m.Get("/query_user_annual_report", repo_ext.QueryUserAnnualReport)

m.Get("/download_invitation_detail", operationReq, repo_ext.DownloadInvitationDetail)

//cloudbrain board
m.Get("/cloudbrainboard/cloudbrain/resource_queues", repo.GetResourceQueues)
m.Group("/cloudbrainboard", func() {
m.Get("/downloadAll", repo.DownloadCloudBrainBoard)
m.Group("/cloudbrain", func() {
@@ -736,6 +742,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/my_favorite", repo.MyFavoriteDatasetMultiple)
}, reqToken(), repoAssignment())

m.Group("/file_notebook", func() {
m.Get("", repo.GetFileNoteBookInfo)
m.Post("/create", reqToken(), reqWeChat(), bind(api.CreateFileNotebookJobOption{}), repo.CreateFileNoteBook)

})

m.Group("/repos", func() {
m.Get("/search", repo.Search)

@@ -751,6 +763,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/:username/:reponame", func() {
m.Get("/right", reqToken(), repo.GetRight)
m.Get("/tagger", reqToken(), repo.ListTagger)
m.Get("/cloudBrainJobId", repo.GetCloudBrainJobId)
m.Combo("").Get(reqAnyRepoReader(), repo.Get).
Delete(reqToken(), reqOwner(), repo.Delete).
Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit)
@@ -987,6 +1000,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/detail", reqToken(), reqRepoReader(models.UnitTypeCloudBrain), repo.CloudBrainShow)
m.Get("/model_list", repo.CloudBrainModelList)
m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop)
m.Put("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.GeneralCloudBrainJobStop)
})
})
m.Group("/inference-job", func() {
@@ -1007,12 +1021,15 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Delete("/delete_model", repo.DeleteModel)
m.Get("/downloadall", repo.DownloadModel)
m.Get("/query_model_byId", repo.QueryModelById)
m.Get("/query_model_byName", repo.QueryModelByName)
m.Get("/query_model_for_predict", repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", repo.QueryModelFileForPredict)
m.Get("/query_train_model", repo.QueryTrainModelList)
m.Post("/create_model_convert", repo.CreateModelConvert)
m.Post("/convert_stop", repo.StopModelConvert)
m.Get("/show_model_convert_page", repo.ShowModelConvertPage)
m.Get("/query_model_convert_byId", repo.QueryModelConvertById)
m.Get("/query_model_convert_byName", repo.QueryModelConvertByName)

m.Get("/:id", repo.GetCloudbrainModelConvertTask)
m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog)


+ 15
- 0
routers/api/v1/notify/pipeline.go View File

@@ -0,0 +1,15 @@
package notify

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
)

func PipelineNotify(ctx *context.APIContext, form api.PipelineNotification) {

ctx.JSON(http.StatusOK, models.BaseOKMessageApi)

}

+ 124
- 9
routers/api/v1/repo/cloudbrain.go View File

@@ -11,11 +11,14 @@ import (
"io"
"net/http"
"os"
"path"
"sort"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/grampus"

cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/modules/convert"
@@ -79,6 +82,98 @@ func CloudBrainShow(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)})

}
func GeneralCloudBrainJobStop(ctx *context.APIContext) {
task := ctx.Cloudbrain
if task.IsTerminal() {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("cloudbrain.Already_stopped"))
return
}
var err error

if ctx.Cloudbrain.Type == models.TypeCloudBrainOne {
err = cloudbrain.StopJob(task.JobID)
} else if ctx.Cloudbrain.Type == models.TypeCloudBrainTwo {
_, err = modelarts.StopTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
} else {
_, err = grampus.StopJob(task.JobID)
}

if err != nil {
log.Warn("cloud brain stopped failed.", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("cloudbrain.Stopped_failed"))
return
}

ctx.JSON(http.StatusOK, models.BaseOKMessageApi)
}
func CreateFileNoteBook(ctx *context.APIContext, option api.CreateFileNotebookJobOption) {
cloudbrainTask.FileNotebookCreate(ctx.Context, option)
}

func GetFileNoteBookInfo(ctx *context.APIContext) {
//image description spec description waiting count

specs, err := models.GetResourceSpecificationByIds([]int64{setting.FileNoteBook.SpecIdCPU, setting.FileNoteBook.SpecIdGPU, setting.FileNoteBook.SpecIdNPU, setting.FileNoteBook.SpecIdNPUCD})
if err != nil {
log.Error("Fail to query specifications", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_query_fail")))
return
}

var specCPU, specGpu, specNPU, specNPUCD *api.SpecificationShow
var specGpuQueueCode string
for _, spec := range specs {
if spec.ID == setting.FileNoteBook.SpecIdCPU {
specCPU = convert.ToSpecification(spec)
} else if spec.ID == setting.FileNoteBook.SpecIdGPU {
specGpu = convert.ToSpecification(spec)
specGpuQueueCode = spec.QueueCode
} else if spec.ID == setting.FileNoteBook.SpecIdNPU {
specNPU = convert.ToSpecification(spec)
} else if spec.ID == setting.FileNoteBook.SpecIdNPUCD {
specNPUCD = convert.ToSpecification(spec)
}
}

waitCountNpu := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")

queuesMap, err := cloudbrain.GetQueuesDetail()
if err != nil {
log.Error("Fail to query gpu queues waiting count", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_query_fail")))
return
}
waitCountGPU := (*queuesMap)[specGpuQueueCode]
if !setting.ModelartsCD.Enabled {
ctx.JSON(http.StatusOK, map[string]interface{}{
"code": 0,
"projectName": setting.FileNoteBook.ProjectName,
"specCpu": specCPU,
"specGpu": specGpu,
"specNpu": specNPU,
"waitCountGpu": waitCountGPU,
"waitCountNpu": waitCountNpu,
"imageCpuDescription": setting.FileNoteBook.ImageCPUDescription,
"imageGpuDescription": setting.FileNoteBook.ImageGPUDescription,
"imageNpuDescription": setting.FileNoteBook.ImageNPUDescription,
})
} else {
ctx.JSON(http.StatusOK, map[string]interface{}{
"code": 0,
"projectName": setting.FileNoteBook.ProjectName,
"specCpu": specCPU,
"specGpu": specGpu,
"specNpu": specNPUCD,
"waitCountGpu": waitCountGPU,
"waitCountNpu": waitCountNpu,
"imageCpuDescription": setting.FileNoteBook.ImageCPUDescription,
"imageGpuDescription": setting.FileNoteBook.ImageGPUDescription,
"imageNpuDescription": setting.FileNoteBook.ImageNPUCDDescription,
})

}

}

func CreateCloudBrain(ctx *context.APIContext, option api.CreateTrainJobOption) {
if option.Type == cloudbrainTask.TaskTypeCloudbrainOne {
@@ -141,10 +236,11 @@ func GetCloudbrainTask(ctx *context.APIContext) {
)

ID := ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)

job, err := cloudbrain.GetCloudBrainByIdOrJobId(ID)

if err != nil {
ctx.NotFound(err)
log.Error("GetCloudbrainByID failed:", err)
return
}
if job.JobType == string(models.JobTypeModelSafety) {
@@ -487,6 +583,12 @@ func ModelSafetyGetLog(ctx *context.APIContext) {
})
return
}
prefix := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, job.JobName, modelarts.LogPath, job.VersionName), "/") + "/job"
_, err = storage.GetObsLogFileName(prefix)
canLogDownload := isCanDownloadLog(ctx, job)
if err != nil {
canLogDownload = false
}
ctx.Data["log_file_name"] = resultLogFile.LogFileList[0]
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": job.JobID,
@@ -495,7 +597,7 @@ func ModelSafetyGetLog(ctx *context.APIContext) {
"EndLine": result.EndLine,
"Content": result.Content,
"Lines": result.Lines,
"CanLogDownload": isCanDownloadLog(ctx, job),
"CanLogDownload": canLogDownload,
"StartTime": job.StartTime,
})
}
@@ -566,7 +668,6 @@ func CloudbrainDownloadLogFile(ctx *context.Context) {
url, err := storage.Attachments.PresignedGetURL(prefix+"/"+fileName, fileName)
if err != nil {
log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("Get minio get SignedUrl failed", err)
return
}
log.Info("fileName=" + fileName)
@@ -596,12 +697,24 @@ func CloudbrainGetLog(ctx *context.APIContext) {
existStr = taskRes.TaskStatuses[0].ExitDiagnostics
}
ctx.Data["existStr"] = existStr
log.Info("existStr=" + existStr)
} else {
ModelSafetyGetLog(ctx)
return
}
}

if job.JobType == string(models.JobTypeTrain) || job.JobType == string(models.JobTypeInference) {
if job.Type == models.TypeCloudBrainOne {
result, err := cloudbrain.GetJob(job.JobID)
existStr := ""
if err == nil && result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
existStr = taskRes.TaskStatuses[0].ExitDiagnostics
}
ctx.Data["existStr"] = existStr
}
}

lines := ctx.QueryInt("lines")
@@ -638,7 +751,7 @@ func CloudbrainGetLog(ctx *context.APIContext) {
result = getLogFromModelDir(job.JobName, startLine, endLine, resultPath)
if result == nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
//ctx.ServerError(err.Error(), err)
return
}
}
@@ -646,9 +759,11 @@ func CloudbrainGetLog(ctx *context.APIContext) {
if result["Content"] != nil {
content = result["Content"].(string)
}

if ctx.Data["existStr"] != nil && result["Lines"].(int) < 50 {
content = content + ctx.Data["existStr"].(string)
}

logFileName := result["FileName"]

//Logs can only be downloaded if the file exists
@@ -851,7 +966,7 @@ func CloudBrainModelConvertList(ctx *context.APIContext) {
err = json.Unmarshal([]byte(dirs), &fileInfos)
if err != nil {
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("json.Unmarshal failed:", err)
//ctx.ServerError("json.Unmarshal failed:", err)
return
}

@@ -882,7 +997,7 @@ func CloudBrainModelConvertList(ctx *context.APIContext) {
models, err := storage.GetObsListObject(job.ID, "output/", parentDir, versionName)
if err != nil {
log.Info("get TrainJobListModel failed:", err)
ctx.ServerError("GetObsListObject:", err)
//ctx.ServerError("GetObsListObject:", err)
return
}

@@ -927,7 +1042,7 @@ func CloudBrainModelList(ctx *context.APIContext) {
err = json.Unmarshal([]byte(dirs), &fileInfos)
if err != nil {
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("json.Unmarshal failed:", err)
//ctx.ServerError("json.Unmarshal failed:", err)
return
}



+ 213
- 98
routers/api/v1/repo/cloudbrain_dashboard.go View File

@@ -11,7 +11,10 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/routers/repo"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
"code.gitea.io/gitea/services/cloudbrain/resource"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

@@ -56,42 +59,30 @@ func GetAllCloudbrainsOverview(ctx *context.Context) {
return
}
cloudbrainTypeCount, err := models.GetCloudbrainTypeCount()
log.Info("cloudbrainTypeCount:", cloudbrainTypeCount)
if err != nil {
log.Error("Can not query cloudbrainTypeCount.", err)
return
}

cloudbrainTpyeDurationSum, err := models.GetCloudbrainTpyeDurationSum()
log.Info("cloudbrainTpyeDurationSum:", cloudbrainTpyeDurationSum)
if err != nil {
log.Error("Can not query cloudbrainTpyeDurationSum.", err)
return
}

todayCloudbrainCount, err := models.GetTodayCloudbrainCount(beginTime, endTime)
log.Info("todayCloudbrainCount:", todayCloudbrainCount)
if err != nil {
log.Error("Can not query todayCloudbrainCount.", err)
return
}

todayRunningCount, err := models.GetTodayRunningCount(beginTime, endTime)
log.Info("todayRunningCount:", todayRunningCount)
if err != nil {
log.Error("Can not query todayRunningCount.", err)
return
}

todayWaitingCount, err := models.GetTodayWaitingCount(beginTime, endTime)
log.Info("todayWaittingCount:", todayWaitingCount)
if err != nil {
log.Error("Can not query todayWaitingCount.", err)
return
}

todayCompletedCount := todayCloudbrainCount - todayRunningCount - todayWaitingCount
log.Info("todayCompletedCount:", todayCompletedCount)

creatorCount, err := models.GetCreatorCount()
if err != nil {
@@ -121,8 +112,9 @@ func GetOverviewDuration(ctx *context.Context) {
recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
now := time.Now()
endTime := now
worker_server_num := 1
cardNum := 1
var workServerNumber int64
var cardNum int64

durationAllSum := int64(0)
cardDuSum := int64(0)

@@ -136,7 +128,7 @@ func GetOverviewDuration(ctx *context.Context) {
c2NetDuration := int64(0)
cDCenterDuration := int64(0)

cloudbrains, _, err := models.CloudbrainAllStatic(&models.CloudbrainsOptions{
cloudbrains, _, err := models.CloudbrainAllKanBan(&models.CloudbrainsOptions{
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
@@ -148,34 +140,36 @@ func GetOverviewDuration(ctx *context.Context) {
models.LoadSpecs4CloudbrainInfo(cloudbrains)

for _, cloudbrain := range cloudbrains {
if cloudbrain.Cloudbrain.WorkServerNumber >= 1 {
worker_server_num = cloudbrain.Cloudbrain.WorkServerNumber
cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
if cloudbrain.Cloudbrain.Spec != nil {
cardNum = int64(cloudbrain.Cloudbrain.Spec.AccCardsNum)
} else {
worker_server_num = 1
}
if cloudbrain.Cloudbrain.Spec == nil {
cardNum = 1
}
if cloudbrain.Cloudbrain.WorkServerNumber >= 1 {
workServerNumber = int64(cloudbrain.Cloudbrain.WorkServerNumber)
} else {
cardNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
workServerNumber = 1
}
duration := cloudbrain.Duration
durationSum := cloudbrain.Duration * int64(worker_server_num) * int64(cardNum)
duration := models.ConvertStrToDuration(cloudbrain.TrainJobDuration)
CardDuration := workServerNumber * int64(cardNum) * duration

if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
cloudBrainOneDuration += duration
cloudBrainOneCardDuSum += durationSum
cloudBrainOneCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
cloudBrainTwoDuration += duration
cloudBrainTwoCardDuSum += durationSum
cloudBrainTwoCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeC2Net {
c2NetDuration += duration
c2NetCardDuSum += durationSum
c2NetCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeCDCenter {
cDCenterDuration += duration
cDNetCardDuSum += durationSum
cDNetCardDuSum += CardDuration
}

durationAllSum += duration
cardDuSum += durationSum
cardDuSum += CardDuration
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"cloudBrainOneCardDuSum": cloudBrainOneCardDuSum,
@@ -192,6 +186,28 @@ func GetOverviewDuration(ctx *context.Context) {
})
}

func GetCloudbrainCardDuration(task models.Cloudbrain) string {
cardNum := int(0)
spec, err := resource.GetCloudbrainSpec(task.ID)
if err != nil {
log.Info("error:" + err.Error())
return ""
}
if spec != nil {
cardNum = spec.AccCardsNum
} else {
cardNum = 1
}
var workServerNumber int64
if task.WorkServerNumber >= 1 {
workServerNumber = int64(task.WorkServerNumber)
} else {
workServerNumber = 1
}
cardDuration := models.ConvertDurationToStr(workServerNumber * int64(cardNum) * task.Duration)
return cardDuration
}

func GetAllCloudbrainsTrend(ctx *context.Context) {

queryType := ctx.QueryTrim("type")
@@ -703,6 +719,30 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
aiCenter := ctx.Query("aiCenter")
needDeleteInfo := ctx.Query("needDeleteInfo")

if cloudBrainType == models.TypeCloudBrainOne && aiCenter == models.AICenterOfCloudBrainOne {
aiCenter = ""
}
if cloudBrainType == models.TypeCloudBrainTwo && aiCenter == models.AICenterOfCloudBrainTwo {
aiCenter = ""
}
if cloudBrainType == models.TypeCDCenter && aiCenter == models.AICenterOfChengdu {
aiCenter = ""
}
if cloudBrainType == models.TypeCloudBrainAll {
if aiCenter == models.AICenterOfCloudBrainOne {
cloudBrainType = models.TypeCloudBrainOne
aiCenter = ""
}
if aiCenter == models.AICenterOfCloudBrainTwo {
cloudBrainType = models.TypeCloudBrainTwo
aiCenter = ""
}
if aiCenter == models.AICenterOfChengdu {
cloudBrainType = models.TypeCDCenter
aiCenter = ""
}
}

page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pagesize")
if page <= 0 {
@@ -732,7 +772,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {

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

ciTasks, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ciTasks, count, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
@@ -747,8 +787,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
NeedRepoInfo: true,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
// AiCenter: aiCenter,
NeedDeleteInfo: needDeleteInfo,
AiCenter: aiCenter,
NeedDeleteInfo: needDeleteInfo,
})
if err != nil {
ctx.ServerError("Get job failed:", err)
@@ -758,45 +798,43 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
nilTime := time.Time{}
tasks := []models.TaskDetail{}
for i, task := range ciTasks {
if aiCenter == "" || aiCenter == task.Cloudbrain.Spec.AiCenterCode {
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
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.WorkServerNumber >= 1 {
taskDetail.WorkServerNum = int64(ciTasks[i].Cloudbrain.WorkServerNumber)
} else {
taskDetail.WorkServerNum = 1
}
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)
task = cloudbrainService.UpdateCloudbrainAiCenter(task)
var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
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
taskDetail.AiCenter = repo.GetAiCenterNameByCode(task.Cloudbrain.AiCenter, ctx.Language())
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.WorkServerNumber >= 1 {
taskDetail.WorkServerNum = int64(ciTasks[i].Cloudbrain.WorkServerNumber)
} else {
taskDetail.WorkServerNum = 1
}
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
}
taskDetail.Spec = ciTasks[i].Spec
tasks = append(tasks, taskDetail)
if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
}
taskDetail.Spec = ciTasks[i].Spec
tasks = append(tasks, taskDetail)
}
count := int64(len(tasks))
pager := context.NewPagination(int(count), pageSize, page, getTotalPage(count, pageSize))
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "listType", "ListType")
@@ -930,6 +968,8 @@ func GetWaittingTop(ctx *context.Context) {
taskDetail.RepoID = ciTasks[i].RepoID
if ciTasks[i].Repo != nil {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
} else {
taskDetail.RepoName = ""
}
WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
@@ -937,6 +977,13 @@ func GetWaittingTop(ctx *context.Context) {
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}

taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.ComputeResource = ciTasks[i].Cloudbrain.ComputeResource
taskDetail.JobType = ciTasks[i].Cloudbrain.JobType
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.Type = ciTasks[i].Cloudbrain.Type

tasks = append(tasks, taskDetail)
}
ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -963,6 +1010,12 @@ func GetRunningTop(ctx *context.Context) {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
}

taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.ComputeResource = ciTasks[i].Cloudbrain.ComputeResource
taskDetail.JobType = ciTasks[i].Cloudbrain.JobType
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.Type = ciTasks[i].Cloudbrain.Type

tasks = append(tasks, taskDetail)
}
ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -1176,6 +1229,12 @@ func getMonthCloudbrainInfo(beginTime time.Time, endTime time.Time) ([]DateCloud
}

func DownloadCloudBrainBoard(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
}

page := 1

@@ -1184,14 +1243,20 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
var cloudBrain = ctx.Tr("repo.cloudbrain")
fileName := getCloudbrainFileName(cloudBrain)

recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
now := time.Now()
endTime := now

_, total, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
},
Type: models.TypeCloudBrainAll,
NeedRepoInfo: false,
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
})
log.Info("totalcountisis:", total)

if err != nil {
log.Warn("Can not get cloud brain info", err)
@@ -1216,8 +1281,10 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
Page: page,
PageSize: pageSize,
},
Type: models.TypeCloudBrainAll,
NeedRepoInfo: true,
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
NeedRepoInfo: true,
})
if err != nil {
log.Warn("Can not get cloud brain info", err)
@@ -1225,7 +1292,8 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(pageRecords)
for _, record := range pageRecords {

record = cloudbrainService.UpdateCloudbrainAiCenter(record)
record.Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(record.Cloudbrain.AiCenter, ctx.Language())
for k, v := range allCloudbrainValues(row, record, ctx) {
f.SetCellValue(cloudBrain, k, v)
}
@@ -1264,7 +1332,7 @@ func allCloudbrainValues(row int, rs *models.CloudbrainInfo, ctx *context.Contex
getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): repo.GetCloudbrainCardDuration(rs.Cloudbrain),
getCellName("I", row): getBrainStartTime(rs),
getCellName("J", row): getBrainEndTime(rs), getCellName("K", row): rs.ComputeResource, getCellName("L", row): getCloudbrainCardType(rs),
getCellName("M", row): getWorkServerNum(rs), getCellName("N", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx),
getCellName("M", row): getWorkServerNum(rs), getCellName("N", row): rs.Cloudbrain.AiCenter,
getCellName("O", row): getCloudbrainFlavorName(rs), getCellName("P", row): rs.Name,
getCellName("Q", row): getBrainRepo(rs), getCellName("R", row): rs.JobName, getCellName("S", row): getBrainDeleteTime(rs),
}
@@ -1412,12 +1480,17 @@ func getCloudbrainTimePeroid(ctx *context.Context, recordBeginTime time.Time) (t
}

func GetCloudbrainResourceOverview(ctx *context.Context) {
var recordBeginTime timeutil.TimeStamp
recordCloudbrainDuration, err := models.GetDurationRecordBeginTime()
if err != nil {
log.Error("Can not get GetDurationRecordBeginTime", err)
return
}
recordBeginTime := recordCloudbrainDuration[0].CreatedUnix
if len(recordCloudbrainDuration) > 0 && err == nil {
recordBeginTime = recordCloudbrainDuration[0].DateTimeUnix
} else {
recordBeginTime = timeutil.TimeStamp(time.Now().Unix())
}
recordUpdateTime := time.Now().Unix()
resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
@@ -1428,11 +1501,12 @@ func GetCloudbrainResourceOverview(ctx *context.Context) {
C2NetResourceDetail := []models.ResourceDetail{}
for _, resourceQueue := range resourceQueues {
if resourceQueue.Cluster == models.OpenICluster {
aiCenterName := repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
var resourceDetail models.ResourceDetail
resourceDetail.QueueCode = resourceQueue.QueueCode
resourceDetail.Cluster = resourceQueue.Cluster
resourceDetail.AiCenterCode = resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterName + "/" + resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterCode + "/" + aiCenterName
resourceDetail.ComputeResource = resourceQueue.ComputeResource
resourceDetail.AccCardType = resourceQueue.AccCardType + "(" + resourceQueue.ComputeResource + ")"
resourceDetail.CardsTotalNum = resourceQueue.CardsTotalNum
@@ -1440,11 +1514,12 @@ func GetCloudbrainResourceOverview(ctx *context.Context) {
OpenIResourceDetail = append(OpenIResourceDetail, resourceDetail)
}
if resourceQueue.Cluster == models.C2NetCluster {
aiCenterName := repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
var resourceDetail models.ResourceDetail
resourceDetail.QueueCode = resourceQueue.QueueCode
resourceDetail.Cluster = resourceQueue.Cluster
resourceDetail.AiCenterCode = resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterName + "/" + resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterCode + "/" + aiCenterName
resourceDetail.ComputeResource = resourceQueue.ComputeResource
resourceDetail.AccCardType = resourceQueue.AccCardType + "(" + resourceQueue.ComputeResource + ")"
resourceDetail.CardsTotalNum = resourceQueue.CardsTotalNum
@@ -1542,6 +1617,7 @@ func getBeginAndEndTime(ctx *context.Context) (time.Time, time.Time) {
now := time.Now()
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var brainRecordBeginTime time.Time

var beginTime time.Time
var endTime time.Time
@@ -1554,7 +1630,12 @@ func getBeginAndEndTime(ctx *context.Context) (time.Time, time.Time) {
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return beginTime, endTime
}
brainRecordBeginTime := recordCloudbrainDuration[0].CreatedUnix.AsTime()
if len(recordCloudbrainDuration) > 0 && err == nil {
brainRecordBeginTime = recordCloudbrainDuration[0].DateTimeUnix.AsTime()
} else {
brainRecordBeginTime = now
}

beginTime = brainRecordBeginTime
endTime = now
} else if queryType == "today" {
@@ -1596,7 +1677,11 @@ func getBeginAndEndTime(ctx *context.Context) (time.Time, time.Time) {
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return beginTime, endTime
}
brainRecordBeginTime := recordCloudbrainDuration[0].CreatedUnix.AsTime()
if len(recordCloudbrainDuration) > 0 && err == nil {
brainRecordBeginTime = recordCloudbrainDuration[0].DateTimeUnix.AsTime()
} else {
brainRecordBeginTime = now
}
beginTime = brainRecordBeginTime
endTime = now
} else {
@@ -1627,7 +1712,7 @@ func getAiCenterUsageDuration(beginTime time.Time, endTime time.Time, cloudbrain
usageRate := float64(0)

for _, cloudbrainStatistic := range cloudbrainStatistics {
if int64(cloudbrainStatistic.CreatedUnix) >= beginTime.Unix() && int64(cloudbrainStatistic.CreatedUnix) < endTime.Unix() {
if int64(cloudbrainStatistic.DateTimeUnix) >= beginTime.Unix() && int64(cloudbrainStatistic.DateTimeUnix) < endTime.Unix() {
totalDuration += cloudbrainStatistic.CardsTotalDuration
usageDuration += cloudbrainStatistic.CardsUseDuration
}
@@ -1659,28 +1744,29 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
return OpenIDurationRate, C2NetDurationRate, 0
}
for _, cloudbrainStatistic := range cardDurationStatistics {
aiCenterName := cloudbrainStatistic.AiCenterCode + "/" + repo.GetAiCenterNameByCode(cloudbrainStatistic.AiCenterCode, "zh-CN")
if cloudbrainStatistic.Cluster == models.OpenICluster {
if _, ok := OpenITotalDuration[cloudbrainStatistic.AiCenterName]; !ok {
OpenITotalDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsTotalDuration
if _, ok := OpenITotalDuration[aiCenterName]; !ok {
OpenITotalDuration[aiCenterName] = cloudbrainStatistic.CardsTotalDuration
} else {
OpenITotalDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsTotalDuration
OpenITotalDuration[aiCenterName] += cloudbrainStatistic.CardsTotalDuration
}
if _, ok := OpenIUsageDuration[cloudbrainStatistic.AiCenterName]; !ok {
OpenIUsageDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsUseDuration
if _, ok := OpenIUsageDuration[aiCenterName]; !ok {
OpenIUsageDuration[aiCenterName] = cloudbrainStatistic.CardsUseDuration
} else {
OpenIUsageDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsUseDuration
OpenIUsageDuration[aiCenterName] += cloudbrainStatistic.CardsUseDuration
}
}
if cloudbrainStatistic.Cluster == models.C2NetCluster {
if _, ok := C2NetTotalDuration[cloudbrainStatistic.AiCenterName]; !ok {
C2NetTotalDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsTotalDuration
if _, ok := C2NetTotalDuration[aiCenterName]; !ok {
C2NetTotalDuration[aiCenterName] = cloudbrainStatistic.CardsTotalDuration
} else {
C2NetTotalDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsTotalDuration
C2NetTotalDuration[aiCenterName] += cloudbrainStatistic.CardsTotalDuration
}
if _, ok := C2NetUsageDuration[cloudbrainStatistic.AiCenterName]; !ok {
C2NetUsageDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsUseDuration
if _, ok := C2NetUsageDuration[aiCenterName]; !ok {
C2NetUsageDuration[aiCenterName] = cloudbrainStatistic.CardsUseDuration
} else {
C2NetUsageDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsUseDuration
C2NetUsageDuration[aiCenterName] += cloudbrainStatistic.CardsUseDuration
}
}
}
@@ -1690,16 +1776,17 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
return OpenIDurationRate, C2NetDurationRate, 0
}
for _, v := range ResourceAiCenterRes {
aiCenterName := v.AiCenterCode + "/" + repo.GetAiCenterNameByCode(v.AiCenterCode, "zh-CN")
if cutString(v.AiCenterCode, 4) == cutString(models.AICenterOfCloudBrainOne, 4) {
if _, ok := OpenIUsageDuration[v.AiCenterName]; !ok {
OpenIUsageDuration[v.AiCenterName] = 0
if _, ok := OpenIUsageDuration[aiCenterName]; !ok {
OpenIUsageDuration[aiCenterName] = 0
}
if _, ok := OpenITotalDuration[v.AiCenterName]; !ok {
OpenITotalDuration[v.AiCenterName] = 0
if _, ok := OpenITotalDuration[aiCenterName]; !ok {
OpenITotalDuration[aiCenterName] = 0
}
} else {
if _, ok := C2NetUsageDuration[v.AiCenterName]; !ok {
C2NetUsageDuration[v.AiCenterName] = 0
if _, ok := C2NetUsageDuration[aiCenterName]; !ok {
C2NetUsageDuration[aiCenterName] = 0
}
}
}
@@ -1716,7 +1803,7 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
for _, v := range OpenITotalDuration {
totalCanUse += float64(v)
}
for _, v := range OpenIUsageRate {
for _, v := range OpenIUsageDuration {
totalUse += float64(v)
}
if totalCanUse == 0 || totalUse == 0 {
@@ -1724,6 +1811,7 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
} else {
totalUsageRate = totalUse / totalCanUse
}
delete(C2NetUsageDuration, "/")

OpenIDurationRate.AiCenterTotalDurationStat = OpenITotalDuration
OpenIDurationRate.AiCenterUsageDurationStat = OpenIUsageDuration
@@ -1831,3 +1919,30 @@ func getHourCloudbrainDuration(beginTime time.Time, endTime time.Time, aiCenterC
hourTimeStatistic.HourTimeUsageRate = hourTimeUsageRate
return hourTimeStatistic, nil
}

func CloudbrainUpdateAiCenter(ctx *context.Context) {
repo.CloudbrainDurationStatisticHour()
ctx.JSON(http.StatusOK, map[string]interface{}{
"message": 0,
})
}

func GetResourceQueues(ctx *context.Context) {
resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
log.Error("GetCanUseCardInfo err: %v", err)
return
}
Resource := make([]*models.ResourceQueue, 0)
aiCenterCodeMap := make(map[string]string)
for _, resourceQueue := range resourceQueues {
if _, ok := aiCenterCodeMap[resourceQueue.AiCenterCode]; !ok {
resourceQueue.AiCenterName = repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
aiCenterCodeMap[resourceQueue.AiCenterCode] = resourceQueue.AiCenterCode
Resource = append(Resource, resourceQueue)
}
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"resourceQueues": Resource,
})
}

+ 14
- 0
routers/api/v1/repo/mlops.go View File

@@ -69,3 +69,17 @@ func GetRight(ctx *context.APIContext) {
})

}

func GetCloudBrainJobId(ctx *context.APIContext) {
cloudbrains, err := models.GetCloudbrainsByDisplayJobName(ctx.Repo.Repository.ID, ctx.Query("jobType"), ctx.Query("name"))
if err != nil {
log.Warn("get cloudbrain by display name failed", err)
ctx.JSON(http.StatusOK, map[string]string{"jobId": ""})
return
}
if len(cloudbrains) > 0 {
ctx.JSON(http.StatusOK, map[string]string{"jobId": cloudbrains[0].JobID})
return
}
ctx.JSON(http.StatusOK, map[string]string{"jobId": ""})
}

+ 5
- 2
routers/api/v1/repo/modelarts.go View File

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

import (
"code.gitea.io/gitea/modules/cloudbrain"
"encoding/json"
"net/http"
"path"
@@ -37,11 +38,14 @@ func GetModelArtsNotebook2(ctx *context.APIContext) {
)

ID := ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)

job,err := cloudbrain.GetCloudBrainByIdOrJobId(ID)

if err != nil {
ctx.NotFound(err)
return
}

err = modelarts.HandleNotebookInfo(job)
if err != nil {
ctx.NotFound(err)
@@ -146,7 +150,6 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
if len(result.JobInfo.Tasks) > 0 {
if len(result.JobInfo.Tasks[0].CenterID) > 0 && len(result.JobInfo.Tasks[0].CenterName) > 0 {
job.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
// aiCenterName = result.JobInfo.Tasks[0].CenterName[0]
aiCenterName = cloudbrainService.GetAiCenterShow(job.AiCenter, ctx.Context)
}
}


+ 20
- 0
routers/api/v1/repo/modelmanage.go View File

@@ -43,8 +43,14 @@ func QueryModelById(ctx *context.APIContext) {
routerRepo.QueryModelById(ctx.Context)
}

func QueryModelByName(ctx *context.APIContext) {
log.Info("QueryModelByName by api.")
routerRepo.ShowSingleModel(ctx.Context)
}

func QueryModelListForPredict(ctx *context.APIContext) {
log.Info("QueryModelListForPredict by api.")
ctx.Context.SetParams("isOnlyThisRepo", "true")
routerRepo.QueryModelListForPredict(ctx.Context)
}

@@ -88,6 +94,11 @@ func CreateModelConvert(ctx *context.APIContext) {
routerRepo.SaveModelConvert(ctx.Context)
}

func StopModelConvert(ctx *context.APIContext) {
log.Info("StopModelConvert by api.")
routerRepo.StopModelConvertApi(ctx.Context)
}

func ShowModelConvertPage(ctx *context.APIContext) {
log.Info("ShowModelConvertPage by api.")
modelResult, count, err := routerRepo.GetModelConvertPageData(ctx.Context)
@@ -113,3 +124,12 @@ func QueryModelConvertById(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, nil)
}
}

func QueryModelConvertByName(ctx *context.APIContext) {
modelResult, err := routerRepo.GetModelConvertByName(ctx.Context)
if err == nil {
ctx.JSON(http.StatusOK, modelResult)
} else {
ctx.JSON(http.StatusOK, nil)
}
}

+ 58
- 15
routers/home.go View File

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

import (
"bytes"
"encoding/json"
"net/http"
"strconv"
"strings"
@@ -672,7 +673,7 @@ func NotFound(ctx *context.Context) {
}

func getRecommendOrg() ([]map[string]interface{}, error) {
url := setting.RecommentRepoAddr + "organizations"
url := setting.RecommentRepoAddr + "home/organizations"
result, err := repository.RecommendFromPromote(url)

if err != nil {
@@ -745,7 +746,7 @@ func GetMapInfo(ctx *context.Context) {
}

func GetRankUser(index string) ([]map[string]interface{}, error) {
url := setting.RecommentRepoAddr + "user_rank_" + index
url := setting.RecommentRepoAddr + "user_rank/user_rank_" + index
result, err := repository.RecommendFromPromote(url)

if err != nil {
@@ -756,13 +757,25 @@ func GetRankUser(index string) ([]map[string]interface{}, error) {
tmpIndex := strings.Index(userRank, " ")
userName := userRank
score := 0
label := ""
if tmpIndex != -1 {
userName = userRank[0:tmpIndex]
tmpScore, err := strconv.Atoi(userRank[tmpIndex+1:])
if err != nil {
log.Info("convert to int error.")
left := userRank[tmpIndex+1:]
tmpIndex1 := strings.Index(left, " ")
if tmpIndex1 != -1 {
tmpScore, err := strconv.Atoi(left[0:tmpIndex1])
if err != nil {
log.Info("convert to int error.")
}
score = tmpScore
label = left[tmpIndex1+1:]
} else {
tmpScore, err := strconv.Atoi(left[tmpIndex+1:])
if err != nil {
log.Info("convert to int error.")
}
score = tmpScore
}
score = tmpScore
}
user, err := models.GetUserByName(userName)
if err == nil {
@@ -772,6 +785,7 @@ func GetRankUser(index string) ([]map[string]interface{}, error) {
userMap["FullName"] = user.FullName
userMap["HomeLink"] = user.HomeLink()
userMap["ID"] = user.ID
userMap["Label"] = label
userMap["Avatar"] = user.RelAvatarLink()
userMap["Score"] = score
resultOrg = append(resultOrg, userMap)
@@ -792,25 +806,54 @@ func GetUserRankFromPromote(ctx *context.Context) {
ctx.JSON(200, resultUserRank)
}

func getMapContent(fileName string) []map[string]string {
url := setting.RecommentRepoAddr + fileName
result, err := repository.RecommendContentFromPromote(url)
remap := make([]map[string]string, 0)
if err == nil {
json.Unmarshal([]byte(result), &remap)
}
return remap
}

func HomeNoticeTmpl(ctx *context.Context) {
ctx.Data["url_params"] = ""
ctx.HTML(200, "notice")
}

func RecommendHomeInfo(ctx *context.Context) {
resultOrg, err := getRecommendOrg()
if err != nil {
log.Info("error." + err.Error())
}
resultRepo, err := repository.GetRecommendRepoFromPromote("projects")
repoMap := getMapContent("home/projects")
resultRepo, err := repository.GetRecommendRepoFromPromote(repoMap)
if err != nil {
log.Info("error." + err.Error())
}
resultImage, err := getImageInfo("picture_info")
if err != nil {
log.Info("error." + err.Error())
}

resultActivityInfo := getMapContent("home/activity_info")
mapInterface := make(map[string]interface{})
mapInterface["org"] = resultOrg
mapInterface["repo"] = resultRepo
mapInterface["image"] = resultImage
//mapInterface["cloudbrain"] = resultCloudBrain
mapInterface["activity"] = resultActivityInfo

user_experience := getMapContent("home/user_experience")
for _, amap := range user_experience {
userId := amap["userid"]
userIntId, _ := strconv.Atoi(userId)
user, err := models.GetUserByID(int64(userIntId))
if err == nil {
amap["name"] = user.Name
amap["fullname"] = user.FullName
amap["detail"] = user.Description
amap["avatar"] = user.AvatarLink()
}
}
mapInterface["user_experience"] = user_experience
dataset, err := models.QueryDatasetGroupByTask()
if err == nil {
mapInterface["dataset"] = dataset
}
ctx.JSON(http.StatusOK, mapInterface)
}

@@ -824,4 +867,4 @@ func HomePrivacy(ctx *context.Context) {

func HomeResoruceDesc(ctx *context.Context) {
ctx.HTML(200, tplResoruceDesc)
}
}

+ 1
- 0
routers/private/internal.go View File

@@ -55,6 +55,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration)
m.Post("/task/history_handle/aicenter", repo.HandleTaskWithAiCenter)
m.Post("/resources/specification/handle_historical_task", admin.RefreshHistorySpec)
m.Post("/duration_statisctic/history_handle", repo.CloudbrainUpdateHistoryData)

}, CheckInternalToken)
}

+ 39
- 9
routers/repo/ai_model_convert.go View File

@@ -49,7 +49,7 @@ const (
//TensorFlowNpuBootFile = "convert_tensorflow.py"
//TensorFlowGpuBootFile = "convert_tensorflow_gpu.py"

//ConvertRepoPath = "https://git.openi.org.cn/zouap/npu_test"
//ConvertRepoPath = "https://openi.pcl.ac.cn/zouap/npu_test"

CONVERT_FORMAT_ONNX = 0
CONVERT_FORMAT_TRT = 1
@@ -573,13 +573,10 @@ func deleteCloudBrainTask(task *models.AiModelConvert) {
}
}

func StopModelConvert(ctx *context.Context) {
id := ctx.Params(":id")
log.Info("stop model convert start.id=" + id)
func stopModelConvert(id string) error {
job, err := models.QueryModelConvertById(id)
if err != nil {
ctx.ServerError("Not found task.", err)
return
return err
}
if job.IsGpuTrainTask() {
err = cloudbrain.StopJob(job.CloudBrainTaskId)
@@ -600,6 +597,35 @@ func StopModelConvert(ctx *context.Context) {
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateModelConvert failed:", err)
return err
}
return nil
}

func StopModelConvertApi(ctx *context.Context) {
id := ctx.Params(":id")
log.Info("stop model convert start.id=" + id)
err := stopModelConvert(id)
if err == nil {
ctx.JSON(200, map[string]string{
"code": "0",
"msg": "succeed",
})
} else {
ctx.JSON(200, map[string]string{
"code": "1",
"msg": err.Error(),
})
}
}

func StopModelConvert(ctx *context.Context) {
id := ctx.Params(":id")
log.Info("stop model convert start.id=" + id)
err := stopModelConvert(id)
if err != nil {
ctx.ServerError("Not found task.", err)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model")
}
@@ -620,7 +646,7 @@ func ShowModelConvertInfo(ctx *context.Context) {
return
}
ctx.Data["Name"] = job.Name
ctx.Data["canDownload"] = isOper(ctx, job.UserId)
ctx.Data["canDownload"] = isOperModifyOrDelete(ctx, job.UserId)
user, err := models.GetUserByID(job.UserId)
if err == nil {
job.UserName = user.Name
@@ -732,6 +758,11 @@ func GetModelConvertById(ctx *context.Context) (*models.AiModelConvert, error) {
return models.QueryModelConvertById(id)
}

func GetModelConvertByName(ctx *context.Context) ([]*models.AiModelConvert, error) {
name := ctx.Query("name")
return models.QueryModelConvertByName(name, ctx.Repo.Repository.ID)
}

func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, int64, error) {
page := ctx.QueryInt("page")
if page <= 0 {
@@ -755,7 +786,7 @@ func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, in
}
userIds := make([]int64, len(modelResult))
for i, model := range modelResult {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
userIds[i] = model.UserId
}
@@ -828,5 +859,4 @@ func ModelConvertDownloadModel(ctx *context.Context) {
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect)
}
}

}

+ 147
- 42
routers/repo/ai_model_manage.go View File

@@ -93,7 +93,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
log.Info("accuracyJson=" + string(accuracyJson))
aiTask.ContainerIp = ""
aiTaskJson, _ := json.Marshal(aiTask)
isPrivate := ctx.QueryBool("isPrivate")
model := &models.AiModelManage{
ID: id,
Version: version,
@@ -114,6 +114,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
TrainTaskInfo: string(aiTaskJson),
Accuracy: string(accuracyJson),
Status: STATUS_COPY_MODEL,
IsPrivate: isPrivate,
}

err = models.SaveModelToDb(model)
@@ -216,6 +217,7 @@ func SaveLocalModel(ctx *context.Context) {
description := ctx.Query("description")
engine := ctx.QueryInt("engine")
taskType := ctx.QueryInt("type")
isPrivate := ctx.QueryBool("isPrivate")
modelActualPath := ""
if taskType == models.TypeCloudBrainOne {
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/"
@@ -262,6 +264,7 @@ func SaveLocalModel(ctx *context.Context) {
TrainTaskInfo: "",
Accuracy: "",
Status: STATUS_FINISHED,
IsPrivate: isPrivate,
}

err := models.SaveModelToDb(model)
@@ -554,20 +557,6 @@ func deleteModelByID(ctx *context.Context, id string) error {
return err
}

func QueryModelByParameters(repoId int64, page int) ([]*models.AiModelManage, int64, error) {

return models.QueryModel(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repoId,
Type: -1,
New: MODEL_LATEST,
Status: -1,
})
}

func DownloadMultiModelFile(ctx *context.Context) {
log.Info("DownloadMultiModelFile start.")
id := ctx.Query("id")
@@ -578,7 +567,7 @@ func DownloadMultiModelFile(ctx *context.Context) {
ctx.ServerError("no such model:", err)
return
}
if !isOper(ctx, task.UserId) {
if !isCanDownload(ctx, task) {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
@@ -806,7 +795,7 @@ func DownloadSingleModelFile(ctx *context.Context) {
ctx.ServerError("no such model:", err)
return
}
if !isOper(ctx, task.UserId) {
if !isCanDownload(ctx, task) {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
@@ -874,8 +863,9 @@ func QueryModelById(ctx *context.Context) {
id := ctx.Query("id")
model, err := models.QueryModelById(id)
if err == nil {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
model.IsCanDownload = isCanDownload(ctx, model)
removeIpInfo(model)
ctx.JSON(http.StatusOK, model)
} else {
@@ -891,7 +881,8 @@ func ShowSingleModel(ctx *context.Context) {

userIds := make([]int64, len(models))
for i, model := range models {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDownload = isCanDownload(ctx, model)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
userIds[i] = model.UserId
}
@@ -941,7 +932,8 @@ func ShowOneVersionOtherModel(ctx *context.Context) {

userIds := make([]int64, len(aimodels))
for i, model := range aimodels {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDownload = isCanDownload(ctx, model)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
userIds[i] = model.UserId
}
@@ -964,6 +956,7 @@ func ShowOneVersionOtherModel(ctx *context.Context) {
}

func SetModelCount(ctx *context.Context) {
isQueryPrivate := isQueryPrivateModel(ctx)
repoId := ctx.Repo.Repository.ID
Type := -1
_, count, _ := models.QueryModel(&models.AiModelQueryOptions{
@@ -971,10 +964,12 @@ func SetModelCount(ctx *context.Context) {
Page: 1,
PageSize: 2,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
Status: -1,
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
IsOnlyThisRepo: true,
Status: -1,
IsQueryPrivate: isQueryPrivate,
})
ctx.Data["MODEL_COUNT"] = count
}
@@ -1001,27 +996,87 @@ func isQueryRight(ctx *context.Context) bool {
}
}

func isCanDownload(ctx *context.Context, task *models.AiModelManage) bool {
if ctx.User == nil {
return false
}
isCollaborator, err := ctx.Repo.Repository.IsCollaborator(ctx.User.ID)
if err != nil {
log.Info("query error.")
}
isTeamMember, err := ctx.Repo.Repository.IsInRepoTeam(ctx.User.ID)
if err != nil {
log.Info("query IsInRepoTeam error." + err.Error())
}
if ctx.User.IsAdmin || ctx.User.ID == task.UserId || isCollaborator || isTeamMember {
return true
}
if ctx.Repo.IsOwner() {
return true
}
if !task.IsPrivate {
return true
}
return false
}

func isQueryPrivateModel(ctx *context.Context) bool {
if ctx.User == nil {
return false
}
isCollaborator, err := ctx.Repo.Repository.IsCollaborator(ctx.User.ID)
if err != nil {
log.Info("query IsCollaborator error." + err.Error())
}
isTeamMember, err := ctx.Repo.Repository.IsInRepoTeam(ctx.User.ID)
if err != nil {
log.Info("query IsInRepoTeam error." + err.Error())
}
if ctx.User.IsAdmin || isCollaborator || isTeamMember {
return true
}
if ctx.Repo.IsOwner() {
return true
}
return false
}

func isCanDelete(ctx *context.Context, modelUserId int64) bool {
if ctx.User == nil {
return false
}
if ctx.User.IsAdmin || ctx.User.ID == modelUserId {
if ctx.User.ID == modelUserId {
return true
}
return isAdminRight(ctx)
}

func isAdminRight(ctx *context.Context) bool {
if ctx.User.IsAdmin {
return true
}
if ctx.Repo.IsOwner() {
return true
}
permission, err := models.GetUserRepoPermission(ctx.Repo.Repository, ctx.User)
if err != nil {
log.Error("GetUserRepoPermission failed:%v", err.Error())
return false
}
if permission.AccessMode >= models.AccessModeAdmin {
return true
}
return false
}

func isOper(ctx *context.Context, modelUserId int64) bool {
func isOperModifyOrDelete(ctx *context.Context, modelUserId int64) bool {
if ctx.User == nil {
return false
}
if ctx.User.IsAdmin || ctx.User.ID == modelUserId {
return true
}
return false
return isAdminRight(ctx)
}

func ShowModelPageInfo(ctx *context.Context) {
@@ -1038,6 +1093,7 @@ func ShowModelPageInfo(ctx *context.Context) {
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
isQueryPrivate := isQueryPrivateModel(ctx)
repoId := ctx.Repo.Repository.ID
Type := -1
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{
@@ -1045,10 +1101,12 @@ func ShowModelPageInfo(ctx *context.Context) {
Page: page,
PageSize: pageSize,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
Status: -1,
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
IsOnlyThisRepo: true,
Status: -1,
IsQueryPrivate: isQueryPrivate,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
@@ -1057,8 +1115,9 @@ func ShowModelPageInfo(ctx *context.Context) {

userIds := make([]int64, len(modelResult))
for i, model := range modelResult {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
model.IsCanDownload = isCanDownload(ctx, model)
userIds[i] = model.UserId
}

@@ -1089,6 +1148,37 @@ func ModifyModel(id string, description string) error {
return err
}

func ModifyModelPrivate(ctx *context.Context) {
id := ctx.Query("id")
isPrivate := ctx.QueryBool("isPrivate")
re := map[string]string{
"code": "-1",
}
task, err := models.QueryModelById(id)
if err != nil || task == nil {
re["msg"] = err.Error()
log.Error("no such model!", err.Error())
ctx.JSON(200, re)
return
}
if !isOperModifyOrDelete(ctx, task.UserId) {
re["msg"] = "No right to operation."
ctx.JSON(200, re)
return
}
err = models.ModifyModelPrivate(id, isPrivate)
if err == nil {
re["code"] = "0"
ctx.JSON(200, re)
log.Info("modify success.")
} else {
re["msg"] = err.Error()
ctx.JSON(200, re)
log.Info("Failed to modify.id=" + id + " isprivate=" + fmt.Sprint(isPrivate) + " error:" + err.Error())
}

}

func ModifyModelInfo(ctx *context.Context) {
log.Info("modify model start.")
id := ctx.Query("id")
@@ -1102,7 +1192,7 @@ func ModifyModelInfo(ctx *context.Context) {
ctx.JSON(200, re)
return
}
if !isOper(ctx, task.UserId) {
if !isOperModifyOrDelete(ctx, task.UserId) {
re["msg"] = "No right to operation."
ctx.JSON(200, re)
return
@@ -1112,6 +1202,7 @@ func ModifyModelInfo(ctx *context.Context) {
label := ctx.Query("label")
description := ctx.Query("description")
engine := ctx.QueryInt("engine")
isPrivate := ctx.QueryBool("isPrivate")
aimodels := models.QueryModelByName(name, task.RepoId)
if aimodels != nil && len(aimodels) > 0 {
if len(aimodels) == 1 {
@@ -1126,14 +1217,14 @@ func ModifyModelInfo(ctx *context.Context) {
return
}
}
err = models.ModifyLocalModel(id, name, label, description, engine)
err = models.ModifyLocalModel(id, name, label, description, engine, isPrivate)

} else {
label := ctx.Query("label")
description := ctx.Query("description")
engine := task.Engine
name := task.Name
err = models.ModifyLocalModel(id, name, label, description, int(engine))
err = models.ModifyLocalModel(id, name, label, description, int(engine), task.IsPrivate)
}

if err != nil {
@@ -1148,15 +1239,27 @@ func ModifyModelInfo(ctx *context.Context) {

func QueryModelListForPredict(ctx *context.Context) {
repoId := ctx.Repo.Repository.ID
page := ctx.QueryInt("page")
if page <= 0 {
page = -1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = -1
}
isQueryPrivate := isQueryPrivateModel(ctx)
//IsOnlyThisRepo := ctx.QueryBool("isOnlyThisRepo")
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: -1,
PageSize: -1,
Page: page,
PageSize: pageSize,
},
RepoID: repoId,
Type: ctx.QueryInt("type"),
New: -1,
Status: 0,
RepoID: repoId,
Type: ctx.QueryInt("type"),
New: -1,
Status: 0,
IsOnlyThisRepo: true,
IsQueryPrivate: isQueryPrivate,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
@@ -1168,7 +1271,9 @@ func QueryModelListForPredict(ctx *context.Context) {

nameMap := make(map[string][]*models.AiModelManage)
for _, model := range modelResult {
removeIpInfo(model)
model.TrainTaskInfo = ""
model.Accuracy = ""
//removeIpInfo(model)
if _, value := nameMap[model.Name]; !value {
models := make([]*models.AiModelManage, 0)
models = append(models, model)


+ 4
- 5
routers/repo/aisafety.go View File

@@ -11,7 +11,8 @@ import (
"os"
"strconv"
"strings"
"time"

cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/aisafety"
@@ -483,7 +484,6 @@ func isTaskNotFinished(status string) bool {
}

func AiSafetyCreateForGetGPU(ctx *context.Context) {
t := time.Now()
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["IsCreate"] = true
ctx.Data["type"] = models.TypeCloudBrainOne
@@ -497,7 +497,7 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) {
log.Info("GPUBaseDataSetUUID=" + setting.ModelSafetyTest.GPUBaseDataSetUUID)
log.Info("GPUCombatDataSetName=" + setting.ModelSafetyTest.GPUCombatDataSetName)
log.Info("GPUCombatDataSetUUID=" + setting.ModelSafetyTest.GPUCombatDataSetUUID)
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName
prepareCloudbrainOneSpecs(ctx)
queuesDetail, _ := cloudbrain.GetQueuesDetail()
@@ -514,12 +514,11 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) {
}

func AiSafetyCreateForGetNPU(ctx *context.Context) {
t := time.Now()
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["IsCreate"] = true
ctx.Data["type"] = models.TypeCloudBrainTwo
ctx.Data["compute_resource"] = models.NPUResource
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName
ctx.Data["datasetType"] = models.TypeCloudBrainTwo
ctx.Data["BaseDataSetName"] = setting.ModelSafetyTest.NPUBaseDataSetName


+ 24
- 53
routers/repo/cloudbrain.go View File

@@ -15,6 +15,8 @@ import (
"time"
"unicode/utf8"

cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/modules/urfs_client/urchin"

"code.gitea.io/gitea/modules/dataset"
@@ -92,28 +94,9 @@ func MustEnableCloudbrain(ctx *context.Context) {
}
}

func cutString(str string, lens int) string {
if len(str) < lens {
return str
}
return str[:lens]
}

func jobNamePrefixValid(s string) string {
lowStr := strings.ToLower(s)
re := regexp.MustCompile(`[^a-z0-9_\\-]+`)

removeSpecial := re.ReplaceAllString(lowStr, "")

re = regexp.MustCompile(`^[_\\-]+`)
return re.ReplaceAllString(removeSpecial, "")

}

func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error {
ctx.Data["PageIsCloudBrain"] = true
t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName

ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand()
@@ -687,6 +670,13 @@ func CloudBrainRestart(ctx *context.Context) {
break
}

if _, err := os.Stat(getOldJobPath(task)); err != nil {
log.Error("Can not find job minio path", err)
resultCode = "-1"
errorMsg = ctx.Tr("cloudbrain.result_cleared")
break
}

count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, string(models.JobTypeDebug))
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -696,7 +686,7 @@ func CloudBrainRestart(ctx *context.Context) {
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
resultCode = "2"
errorMsg = ctx.Tr("repo.cloudbrain.morethanonejob")
break
}
@@ -721,6 +711,11 @@ func CloudBrainRestart(ctx *context.Context) {
})
}


func getOldJobPath(task *models.Cloudbrain) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + task.JobName
}

func CloudBrainBenchMarkShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainBenchmarkShow, models.JobTypeBenchmark)
}
@@ -759,43 +754,13 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
return
}
if task.Status == string(models.JobWaiting) || task.Status == string(models.JobRunning) {
result, err := cloudbrain.GetJob(task.JobID)
task, err = cloudbrainTask.SyncCloudBrainOneStatus(task)
if err != nil {
log.Info("error:" + err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

if result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
ctx.Data["taskRes"] = taskRes
ctx.Data["ExitDiagnostics"] = taskRes.TaskStatuses[0].ExitDiagnostics
oldStatus := task.Status
task.Status = taskRes.TaskStatuses[0].State
task.ContainerIp = ""
task.ContainerID = taskRes.TaskStatuses[0].ContainerID
models.ParseAndSetDurationFromCloudBrainOne(jobRes, task)

if task.DeletedAt.IsZero() { //normal record
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
return
}
} else { //deleted record

}

ctx.Data["result"] = jobRes
} else {
log.Info("error:" + err.Error())
return
}
}

user, err := models.GetUserByID(task.UserID)
@@ -889,7 +854,13 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
func CloudBrainDebug(ctx *context.Context) {
task := ctx.Cloudbrain
debugUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName
ctx.Redirect(debugUrl)
if task.BootFile!=""{
ctx.Redirect(getFileUrl(debugUrl,task.BootFile))

}else{
ctx.Redirect(debugUrl)
}

}

func prepareSpec4Show(ctx *context.Context, task *models.Cloudbrain) {


+ 172
- 74
routers/repo/cloudbrain_statistic.go View File

@@ -1,118 +1,180 @@
package repo

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

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
)

func CloudbrainDurationStatisticHour() {
if setting.IsCloudbrainTimingEnabled {
var statisticTime time.Time
var count int64
recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime()
if err != nil {
log.Error("Can not get GetDurationRecordBeginTime", err)
}
now := time.Now()
currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
if err == nil && len(recordDurationUpdateTime) > 0 {
statisticTime = time.Unix(int64(recordDurationUpdateTime[0].DateTimeUnix), 0).Add(+1 * time.Hour)
} else {
statisticTime = currentTime
}

dateTime := time.Now().Format("2006-01-02 15:04:05")
dayTime := time.Now().Format("2006-01-02")
now := time.Now()
err = models.DeleteCloudbrainDurationStatistic(timeutil.TimeStamp(statisticTime.Add(-1*time.Hour).Unix()), timeutil.TimeStamp(currentTime.Unix()))
if err != nil {
log.Error("DeleteCloudbrainDurationStatistic failed", err)
}

currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
countEach := summaryDurationStat(statisticTime)
count += countEach
statisticTime = statisticTime.Add(+1 * time.Hour)
}
log.Info("summaryDurationStat count: %v", count)
}
}
func UpdateDurationStatisticHistoryData(beginTime time.Time, endTime time.Time) int64 {
var count int64
statisticTime := beginTime
currentTime := endTime
for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
countEach := summaryDurationStat(statisticTime)
count += countEach
statisticTime = statisticTime.Add(+1 * time.Hour)
}
return count
}

m, _ := time.ParseDuration("-1h")
beginTime := currentTime.Add(m).Unix()
endTime := currentTime.Unix()
hourTime := currentTime.Add(m).Hour()
//statisticTime是当前的时辰,比如当前是2019-01-01 12:01:01,那么statisticTime就是2019-01-01 12:00:00
func summaryDurationStat(statisticTime time.Time) int64 {
var count int64
dateTimeUnix := timeutil.TimeStamp(statisticTime.Add(-1 * time.Hour).Unix())
beginTime := statisticTime.Add(-1 * time.Hour).Unix()
dayTime := statisticTime.Add(-1 * time.Hour).Format("2006-01-02")
hourTime := statisticTime.Add(-1 * time.Hour).Hour()
endTime := statisticTime.Unix()

ciTasks, err := models.GetCloudbrainByTime(beginTime, endTime)
if err != nil {
log.Info("GetCloudbrainByTime err: %v", err)
return
return 0
}
specMap := make(map[string]*models.Specification)
models.LoadSpecs4CloudbrainInfo(ciTasks)
for _, cloudbrain := range ciTasks {
if _, ok := specMap[cloudbrain.Cloudbrain.Spec.AiCenterCode+"/"+cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if cloudbrain.Cloudbrain.Spec != nil {
specMap[cloudbrain.Cloudbrain.Spec.AiCenterCode+"/"+cloudbrain.Cloudbrain.Spec.AccCardType] = cloudbrain.Cloudbrain.Spec
}
}
}

cloudBrainCenterCodeAndCardTypeInfo := getcloudBrainCenterCodeAndCardTypeInfo(ciTasks, beginTime, endTime)
cloudBrainCenterCodeAndCardTypeInfo, cloudbrainMap := getcloudBrainCenterCodeAndCardTypeInfo(ciTasks, beginTime, endTime)

resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
log.Info("GetCanUseCardInfo err: %v", err)
return
return 0
}

cardsTotalDurationMap := make(map[string]int)
for _, resourceQueue := range resourceQueues {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterName+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType+"/"+resourceQueue.ComputeResource] = resourceQueue.CardsTotalNum * 1 * 60 * 60
if _, ok := cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType]; !ok {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] = resourceQueue.CardsTotalNum * 1 * 60 * 60
} else {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] += resourceQueue.CardsTotalNum * 1 * 60 * 60
}
}

for centerCode, CardTypeInfo := range cloudBrainCenterCodeAndCardTypeInfo {
for cardType, cardDuration := range CardTypeInfo {
spec := specMap[centerCode+"/"+cardType]
if spec != nil {
if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, centerCode, cardType); err != nil {
log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error())
return
}
if _, ok := cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource]; !ok {
cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource] = 0
for centerCode, CardTypes := range cloudBrainCenterCodeAndCardTypeInfo {
for cardType, cardDuration := range CardTypes {
cloudbrainTable := cloudbrainMap[centerCode+"/"+cardType]
if cloudbrainTable != nil {
if _, ok := cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType]; !ok {
cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType] = 0
}
cloudbrainDurationStat := models.CloudbrainDurationStatistic{
DateTime: dateTime,
DateTimeUnix: dateTimeUnix,
DayTime: dayTime,
HourTime: hourTime,
Cluster: spec.Cluster,
AiCenterName: spec.AiCenterName,
Cluster: cloudbrainTable.Cluster,
AiCenterName: GetAiCenterNameByCode(centerCode, "zh-CN"),
AiCenterCode: centerCode,
AccCardType: cardType,
ComputeResource: spec.ComputeResource,
CardsUseDuration: cardDuration,
CardsTotalDuration: cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource],
CardsTotalDuration: cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType],
CreatedUnix: timeutil.TimeStampNow(),
}
if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
}
delete(cardsTotalDurationMap, spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource)
count++
delete(cardsTotalDurationMap, cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType)
}
}
}

for key, cardsTotalDuration := range cardsTotalDurationMap {
if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, strings.Split(key, "/")[2], strings.Split(key, "/")[3]); err != nil {
log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error())
return
}
cloudbrainDurationStat := models.CloudbrainDurationStatistic{
DateTime: dateTime,
DateTimeUnix: dateTimeUnix,
DayTime: dayTime,
HourTime: hourTime,
Cluster: strings.Split(key, "/")[0],
AiCenterName: strings.Split(key, "/")[1],
AiCenterCode: strings.Split(key, "/")[2],
AccCardType: strings.Split(key, "/")[3],
ComputeResource: strings.Split(key, "/")[4],
AiCenterName: GetAiCenterNameByCode(strings.Split(key, "/")[1], "zh-CN"),
AiCenterCode: strings.Split(key, "/")[1],
AccCardType: strings.Split(key, "/")[2],
CardsUseDuration: 0,
CardsTotalDuration: cardsTotalDuration,
CardsTotalNum: cardsTotalDuration / 1 / 60 / 60,
CreatedUnix: timeutil.TimeStampNow(),
}
if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
}
count++
}

log.Info("finish summary cloudbrainDurationStat")
return count
}

func GetAiCenterNameByCode(centerCode string, language string) string {
var aiCenterName string
aiCenterInfo := cloudbrainService.GetAiCenterInfoByCenterCode(centerCode)
if aiCenterInfo != nil {
if language == "zh-CN" {
aiCenterName = aiCenterInfo.Content
} else {
aiCenterName = aiCenterInfo.ContentEN
}
} else {
aiCenterName = centerCode
}
return aiCenterName
}

func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, beginTime int64, endTime int64) map[string]map[string]int {
func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, beginTime int64, endTime int64) (map[string]map[string]int, map[string]*models.Cloudbrain) {
var WorkServerNumber int
var AccCardsNum int
cloudbrainMap := make(map[string]*models.Cloudbrain)
cloudBrainCenterCodeAndCardType := make(map[string]map[string]int)
for _, cloudbrain := range ciTasks {
if cloudbrain.Cloudbrain.StartTime == 0 {
cloudbrain.Cloudbrain.StartTime = cloudbrain.Cloudbrain.CreatedUnix
}
if cloudbrain.Cloudbrain.EndTime == 0 {
cloudbrain.Cloudbrain.EndTime = timeutil.TimeStamp(time.Now().Unix())
}
cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
if cloudbrain.Cloudbrain.Spec != nil {
if _, ok := cloudbrainMap[cloudbrain.Cloudbrain.AiCenter+"/"+cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if cloudbrain.Cloudbrain.Spec != nil {
cloudbrainMap[cloudbrain.Cloudbrain.AiCenter+"/"+cloudbrain.Cloudbrain.Spec.AccCardType] = &cloudbrain.Cloudbrain
}
}
}

cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
if cloudbrain.Cloudbrain.StartTime == 0 {
cloudbrain.Cloudbrain.StartTime = cloudbrain.Cloudbrain.CreatedUnix
}
@@ -129,41 +191,77 @@ func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, be
} else {
AccCardsNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
}
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode]; !ok {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode] = make(map[string]int)
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter]; !ok {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter] = make(map[string]int)
}

if cloudbrain.Cloudbrain.Status == string(models.ModelArtsRunning) {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
if cloudbrain.Cloudbrain.Spec != nil {
if cloudbrain.Cloudbrain.Status == string(models.ModelArtsRunning) && cloudbrain.Cloudbrain.DeletedAt.IsZero() {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) < endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) >= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = 0
}
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) < endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) >= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += 0
}
}
} else {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
}
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
}
}
}
} else {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
}
} else {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
}
}

}
}

return cloudBrainCenterCodeAndCardType
return cloudBrainCenterCodeAndCardType, cloudbrainMap
}

func CloudbrainUpdateHistoryData(ctx *context.Context) {
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var count int64
var err error
if beginTimeStr != "" && endTimeStr != "" {
beginTime, _ := time.ParseInLocation("2006-01-02 15:04:05", beginTimeStr, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
if time.Now().Before(endTime) {
endTime = time.Now()
}
beginTimeUnix := timeutil.TimeStamp(beginTime.Unix())
endTimeUnix := timeutil.TimeStamp(endTime.Unix())

err = models.DeleteCloudbrainDurationStatistic(beginTimeUnix, endTimeUnix)
count = UpdateDurationStatisticHistoryData(beginTime.Add(+1*time.Hour), endTime.Add(+1*time.Hour))
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"message": 0,
"count": count,
"err": err,
})
}

+ 2
- 4
routers/repo/grampus.go View File

@@ -10,7 +10,6 @@ import (
"path"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/urfs_client/urchin"
"code.gitea.io/gitea/routers/response"
@@ -77,8 +76,7 @@ func GrampusTrainJobNPUNew(ctx *context.Context) {
func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) error {
ctx.Data["PageIsCloudBrain"] = true

t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName

//get valid images
@@ -1144,7 +1142,7 @@ func HandleTaskWithAiCenter(ctx *context.Context) {
log.Error("GetJob failed:" + err.Error())
continue
}
if result != nil {
if len(result.JobInfo.Tasks) != 0 {
if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 {
task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
}


+ 47
- 20
routers/repo/modelarts.go View File

@@ -15,6 +15,8 @@ import (
"time"
"unicode/utf8"

cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask"

"code.gitea.io/gitea/modules/dataset"
@@ -128,8 +130,7 @@ func NotebookNew(ctx *context.Context) {

func notebookNewDataPrepare(ctx *context.Context) error {
ctx.Data["PageIsCloudBrain"] = true
t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
@@ -239,9 +240,9 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
}

if setting.ModelartsCD.Enabled {
err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec)
_, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec, "", modelarts.AutoStopDurationMs)
} else {
err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec)
_, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec, "", modelarts.AutoStopDurationMs)
}

if err != nil {
@@ -387,8 +388,31 @@ func NotebookDebug2(ctx *context.Context) {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
}
if task.BootFile != "" {
ctx.Redirect(getFileUrl(result.Url, task.BootFile) + "?token=" + result.Token)
} else {
ctx.Redirect(result.Url + "?token=" + result.Token)
}

ctx.Redirect(result.Url + "?token=" + result.Token)
}

func getFileUrl(url string, filename string) string {
middle := ""
if url[len(url)-3:] == "lab" || url[len(url)-4:] == "lab/" {
if url[len(url)-1] == '/' {
middle = "tree/"
} else {
middle = "/tree/"
}
} else {
if url[len(url)-1] == '/' {
middle = "lab/tree/"
} else {
middle = "/lab/tree/"
}
}

return url + middle + path.Base(filename)
}

func NotebookRestart(ctx *context.Context) {
@@ -420,7 +444,8 @@ func NotebookRestart(ctx *context.Context) {
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
errorMsg = "you have already a running or waiting task, can not create more"
resultCode = "2"
errorMsg = ctx.Tr("repo.cloudbrain.morethanonejob")
break
}
}
@@ -714,8 +739,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
// return
//}

t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -2313,7 +2337,7 @@ func InferenceJobIndex(ctx *context.Context) {
tasks[i].ComputeResource = models.NPUResource
}
}
isQueryPrivate := isQueryPrivateModel(ctx)
repoId := ctx.Repo.Repository.ID
Type := -1
_, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{
@@ -2321,10 +2345,12 @@ func InferenceJobIndex(ctx *context.Context) {
Page: 1,
PageSize: 2,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
Status: 0,
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
IsOnlyThisRepo: true,
Status: 0,
IsQueryPrivate: isQueryPrivate,
})
ctx.Data["MODEL_COUNT"] = model_count

@@ -2351,8 +2377,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error {
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["newInference"] = true

t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name)
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -2394,7 +2419,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error {
return err
}
ctx.Data["config_list"] = configList.ParaConfigs
isQueryPrivate := isQueryPrivateModel(ctx)
repoId := ctx.Repo.Repository.ID
Type := -1
_, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{
@@ -2402,10 +2427,12 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error {
Page: 1,
PageSize: 2,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
Status: 0,
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
IsOnlyThisRepo: true,
Status: 0,
IsQueryPrivate: isQueryPrivate,
})
ctx.Data["MODEL_COUNT"] = model_count
ctx.Data["datasetType"] = models.TypeCloudBrainTwo


+ 3
- 1
routers/repo/repo.go View File

@@ -414,7 +414,9 @@ func Action(ctx *context.Context) {
var err error
switch ctx.Params(":action") {
case "watch":
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.ReceiveAllNotification)
case "watch_but_reject":
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.RejectAllNotification)
case "unwatch":
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
case "star":


+ 6
- 0
routers/repo/user_data_analysis.go View File

@@ -907,3 +907,9 @@ func QueryUserLoginInfo(ctx *context.Context) {
log.Info("writer exel error." + err.Error())
}
}

func QueryUserAnnualReport(ctx *context.Context) {
log.Info("start to QueryUserAnnualReport ")
result := models.QueryUserAnnualReport(ctx.User.ID)
ctx.JSON(http.StatusOK, result)
}

+ 6
- 3
routers/repo/user_invitation.go View File

@@ -49,9 +49,10 @@ func getInvitationDetailExcelHeader(ctx *context.Context) map[string]string {
excelHeader := make([]string, 0)
excelHeader = append(excelHeader, ctx.Tr("user.static.id"))
excelHeader = append(excelHeader, ctx.Tr("user.static.name"))
excelHeader = append(excelHeader, ctx.Tr("user.static.srcUserId"))
excelHeader = append(excelHeader, ctx.Tr("user.static.email"))
excelHeader = append(excelHeader, ctx.Tr("user.static.phone"))
excelHeader = append(excelHeader, ctx.Tr("user.static.registdate"))
excelHeader = append(excelHeader, ctx.Tr("user.static.srcUserId"))

excelHeaderMap := make(map[string]string, 0)
var i byte
@@ -92,8 +93,7 @@ func writeInvitationDetailExcel(row int, xlsx *excelize.File, sheetName string,
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SrcUserID)
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Email)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone)
@@ -101,7 +101,9 @@ func writeInvitationDetailExcel(row int, xlsx *excelize.File, sheetName string,

formatTime := userRecord.CreatedUnix.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3])
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SrcUserID)
}

func DownloadInvitationDetail(ctx *context.Context) {
@@ -413,6 +415,7 @@ func queryData(ctx *context.Context, startTime time.Time, endTime time.Time) {
invi.Name = tmpUser.Name
invi.Phone = tmpUser.PhoneNumber
invi.CreatedUnix = tmpUser.CreatedUnix
invi.Email = tmpUser.Email
} else {
invi.Name = "已注销"
}


+ 5
- 2
routers/routes/routes.go View File

@@ -359,6 +359,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/all/dosearch/", routers.SearchApi)
m.Post("/user/login/kanban", user.SignInPostAPI)
m.Get("/home/term", routers.HomeTerm)
m.Get("/home/notice", routers.HomeNoticeTmpl)
m.Get("/home/privacy", routers.HomePrivacy)
m.Get("/extension/tuomin/upload", modelapp.ProcessImageUI)
m.Post("/extension/tuomin/upload", reqSignIn, modelapp.ProcessImage)
@@ -518,6 +519,7 @@ func RegisterRoutes(m *macaron.Macaron) {
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
m.Any("/activate", user.Activate, reqSignIn)
m.Any("/activate_email", user.ActivateEmail)
m.Post("/update_email", bindIgnErr(auth.UpdateEmailForm{}), user.UpdateEmailPost)
m.Get("/avatar/:username/:size", user.Avatar)
m.Get("/email2user", user.Email2User)
m.Get("/recover_account", user.ResetPasswd)
@@ -1249,6 +1251,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/delete_model_convert/:id", repo.DeleteModelConvert)
m.Post("/convert_stop/:id", repo.StopModelConvert)
m.Put("/modify_model", repo.ModifyModelInfo)
m.Put("/modify_model_status", repo.ModifyModelPrivate)
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate)
m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate)
m.Get("/show_model_info", repo.ShowModelInfo)
@@ -1272,8 +1275,8 @@ func RegisterRoutes(m *macaron.Macaron) {

m.Group("/modelsafety", func() {
m.Group("/:id", func() {
m.Get("/show", reqRepoCloudBrainWriter, repo.GetAiSafetyTaskTmpl)
m.Get("", reqRepoCloudBrainWriter, repo.GetAiSafetyTask)
m.Get("/show", reqRepoCloudBrainReader, repo.GetAiSafetyTaskTmpl)
m.Get("", reqRepoCloudBrainReader, repo.GetAiSafetyTask)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.StopAiSafetyTask)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.DelAiSafetyTask)
})


+ 2
- 1
routers/user/Invitation.go View File

@@ -63,7 +63,7 @@ func InviationTpl(ctx *context.Context) {
ctx.HTML(200, tplInvitation)
}

func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhoneNumber string) error {
func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhoneNumber string, email string) error {
user := parseInvitaionCode(invitationcode)
if user == nil {
return errors.New("The invitated user not existed.")
@@ -85,6 +85,7 @@ func RegisteUserByInvitaionCode(invitationcode string, newUserId int64, newPhone
SrcUserID: user.ID,
UserID: newUserId,
Phone: newPhoneNumber,
Email: email,
}

err := models.InsertInvitaion(invitation)


+ 29
- 1
routers/user/auth.go View File

@@ -1368,7 +1368,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo

log.Info("enter here, and form.InvitaionCode =" + invitationCode)
if invitationCode != "" {
RegisteUserByInvitaionCode(invitationCode, u.ID, u.PhoneNumber)
RegisteUserByInvitaionCode(invitationCode, u.ID, u.PhoneNumber, u.Email)
}

err := models.AddEmailAddress(&models.EmailAddress{
@@ -1413,6 +1413,34 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
handleSignInFull(ctx, u, false, true)
}

//update user emailAddress
func UpdateEmailPost(ctx *context.Context, form auth.UpdateEmailForm) {
newEmailAddress := ctx.Query("NewEmail")
if newEmailAddress == "" {
log.Error("please input the newEmail")
return
}
if used, _ := models.IsEmailUsed(newEmailAddress); used {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), TplActivate, &form)
return
}
user := ctx.User
email, err := models.GetEmailAddressByIDAndEmail(user.ID, user.Email)
if err != nil {
ctx.ServerError("GetEmailAddressByIDAndEmail failed", err)
return
}
err = email.UpdateEmailAddress(newEmailAddress)
if err != nil {
ctx.ServerError("UpdateEmailAddress failed", err)
return
}
ctx.Data["SignedUser.Email"] = newEmailAddress
ctx.User.Email = newEmailAddress
Activate(ctx)

}

// Activate render activate user page
func Activate(ctx *context.Context) {
code := ctx.Query("code")


+ 4
- 0
routers/user/home.go View File

@@ -23,6 +23,8 @@ import (
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/repo"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"

@@ -837,6 +839,8 @@ func Cloudbrains(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(ciTasks)
for i, _ := range ciTasks {
ciTasks[i] = cloudbrainService.UpdateCloudbrainAiCenter(ciTasks[i])
ciTasks[i].Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(ciTasks[i].Cloudbrain.AiCenter, ctx.Language())
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = ciTasks[i].ComputeResource


+ 151
- 0
services/cloudbrain/clear.go View File

@@ -0,0 +1,151 @@
package cloudbrain

import (
"io/ioutil"
"os"
"sort"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
)

func ClearCloudbrainResultSpace() {
log.Info("clear cloudbrain one result space begin.")
if !setting.ClearStrategy.Enabled{
return
}

tasks, err := models.GetCloudBrainOneStoppedNotDebugJobDaysAgo(setting.ClearStrategy.ResultSaveDays, setting.ClearStrategy.BatchSize)
if err != nil {
log.Warn("Failed to get cloudbrain, clear result failed.", err)
return
}
debugTasks, err := models.GetCloudBrainOneStoppedDebugJobDaysAgo(setting.ClearStrategy.ResultSaveDays, setting.ClearStrategy.DebugJobSize)
if err != nil {
log.Warn("Failed to get debug cloudbrain.", err)

}
tasks=append(tasks,debugTasks...)

if err != nil {
log.Warn("Failed to get cloudbrain, clear result failed.", err)
return
}
var ids []int64
for _, task := range tasks {
err := DeleteCloudbrainOneJobStorage(task.JobName)
if err == nil {
log.Info("clear job in cloudbrain table:"+task.JobName)
ids = append(ids, task.ID)
}
}

err = models.UpdateCloudBrainRecordsCleared(ids)
if err != nil {
log.Warn("Failed to set cloudbrain cleared status", err)
}
//如果云脑表处理完了,通过遍历minio对象处理历史垃圾数据,如果存在的话
if len(tasks) < setting.ClearStrategy.BatchSize+setting.ClearStrategy.DebugJobSize {
clearLocalHistoryTrashFile()
clearMinioHistoryTrashFile()

}
log.Info("clear cloudbrain one result space end.")

}

func clearMinioHistoryTrashFile() {
JobRealPrefix := setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix

miniofiles, err := ioutil.ReadDir(JobRealPrefix)

processCount := 0
if err != nil {
log.Warn("Can not browser minio job path.")
} else {
SortModTimeAscend(miniofiles)
for _, file := range miniofiles {

if file.Name()!="" && file.ModTime().Before(time.Now().AddDate(0, 0, -setting.ClearStrategy.TrashSaveDays)) {

has,err:=models.IsCloudbrainExistByJobName(file.Name())
if err==nil && !has {
dirPath := setting.CBCodePathPrefix + file.Name() + "/"
log.Info("clear job in minio trash:" + file.Name())
storage.Attachments.DeleteDir(dirPath)
processCount++
}
if processCount == setting.ClearStrategy.BatchSize {
break
}
} else {
break
}

}

}
}

func clearLocalHistoryTrashFile() {
files, err := ioutil.ReadDir(setting.JobPath)
processCount := 0
if err != nil {
log.Warn("Can not browser local job path.")
} else {
SortModTimeAscend(files)
for _, file := range files {
//清理n天前的历史垃圾数据,清理job目录
if file.Name()!="" && file.ModTime().Before(time.Now().AddDate(0, 0, -setting.ClearStrategy.TrashSaveDays)) {
has,err:=models.IsCloudbrainExistByJobName(file.Name())
if err==nil && !has{
os.RemoveAll(setting.JobPath + file.Name())
log.Info("clear job in local trash:"+file.Name())
processCount++
}
if processCount == setting.ClearStrategy.BatchSize {
break
}
} else {
break
}

}

}

}

func SortModTimeAscend(files []os.FileInfo) {
sort.Slice(files, func(i, j int) bool {
return files[i].ModTime().Before(files[j].ModTime())
})
}

func DeleteCloudbrainOneJobStorage(jobName string) error {

if jobName==""{
return nil
}
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

dirPath := setting.CBCodePathPrefix + jobName + "/"
err1 := storage.Attachments.DeleteDir(dirPath)

if err1 != nil {
log.Error("DeleteDir(%s) failed:%v", localJobPath, err)
}
if err == nil {
err = err1
}

return err
}

+ 362
- 0
services/cloudbrain/cloudbrainTask/notebook.go View File

@@ -0,0 +1,362 @@
package cloudbrainTask

import (
"fmt"
"net/http"
"path"

"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/modelarts_cd"

"code.gitea.io/gitea/modules/git"

"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/redis/redis_key"
"code.gitea.io/gitea/modules/redis/redis_lock"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/services/cloudbrain/resource"
"code.gitea.io/gitea/services/reward/point/account"

"code.gitea.io/gitea/modules/setting"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
repo_service "code.gitea.io/gitea/services/repository"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)

const NoteBookExtension = ".ipynb"

func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption) {

if ctx.Written() {
return
}

if path.Ext(option.File) != NoteBookExtension {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_select_wrong")))
return
}

isNotebookFileExist, _ := isNoteBookFileExist(ctx, option)
if !isNotebookFileExist {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist")))
return
}

sourceRepo, err := models.GetRepositoryByOwnerAndName(option.OwnerName, option.ProjectName)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist")))
return
}

permission, err := models.GetUserRepoPermission(sourceRepo, ctx.User)
if err != nil {
log.Error("Get permission failed", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_no_right")))
return
}

if !permission.CanRead(models.UnitTypeCode) {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_no_right")))
return
}

//create repo if not exist
repo, err := models.GetRepositoryByName(ctx.User.ID, setting.FileNoteBook.ProjectName)
if repo == nil {
repo, err = repo_service.CreateRepository(ctx.User, ctx.User, models.CreateRepoOptions{
Name: setting.FileNoteBook.ProjectName,
Alias: "",
Description: "",
IssueLabels: "",
Gitignores: "",
License: "",
Readme: "Default",
IsPrivate: false,
AutoInit: true,
DefaultBranch: "master",
})
}
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.failed_to_create_notebook_repo",setting.FileNoteBook.ProjectName)))
return
}
if option.Type <= 1 {
cloudBrainFileNoteBookCreate(ctx, option, repo, sourceRepo)
} else {
modelartsFileNoteBookCreate(ctx, option, repo, sourceRepo)
}

}

func cloudBrainFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository, sourceRepo *models.Repository) {

displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name)
jobName := util.ConvertDisplayJobNameToJobName(displayJobName)
jobType := string(models.JobTypeDebug)

lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName))
defer lock.UnLock()
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err")))
return
}

tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName)
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err")))
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error."))
return
}
}

count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error."))
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
ctx.JSON(http.StatusOK,models.BaseMessageApi{
Code: 2,
Message: ctx.Tr("repo.cloudbrain.morethanonejob"),
})
return
}
}

errStr := uploadCodeFile(sourceRepo, getCodePath(jobName), option.BranchName, option.File, jobName)
if errStr != "" {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist")))
return
}
command := cloudbrain.GetCloudbrainDebugCommand()
specId := setting.FileNoteBook.SpecIdGPU
if option.Type == 0 {
specId = setting.FileNoteBook.SpecIdCPU
}
spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{
JobType: models.JobType(jobType),
ComputeResource: models.GPU,
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainOne})
if err != nil || spec == nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification")))
return
}

if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance")))
return
}
ctx.Repo = &context.Repository{
Repository: repo,
}

req := cloudbrain.GenerateCloudBrainTaskReq{
Ctx: ctx,
DisplayJobName: displayJobName,
JobName: jobName,
Image: setting.FileNoteBook.ImageGPU,
Command: command,
Uuids: "",
DatasetNames: "",
DatasetInfos: nil,
CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"),
Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"),
JobType: jobType,
Description: getDescription(option),
BranchName: option.BranchName,
BootFile: option.File,
Params: "{\"parameter\":[]}",
CommitID: "",
BenchmarkTypeID: 0,
BenchmarkChildTypeID: 0,
ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"),
Spec: spec,
}

jobId, err := cloudbrain.GenerateTask(req)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error()))
return
}
ctx.JSON(http.StatusOK, models.BaseMessageApi{
Code: 0,
Message: jobId,
})

}

func getCodePath(jobName string) string {
return setting.JobPath + jobName + cloudbrain.CodeMountPath
}

func getDescription(option api.CreateFileNotebookJobOption) string {
return option.OwnerName + "/" + option.ProjectName + "/" + option.File
}

func modelartsFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository, sourceRepo *models.Repository) {
displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name)
jobName := util.ConvertDisplayJobNameToJobName(displayJobName)

lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeDebug), displayJobName))
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err")))
return
}
defer lock.UnLock()

count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug))

if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])

ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error."))
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
ctx.JSON(http.StatusOK,models.BaseMessageApi{
Code: 2,
Message: ctx.Tr("repo.cloudbrain.morethanonejob"),
})
return
}
}

tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeDebug), displayJobName)
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err")))
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error."))
return
}
}

err = downloadCode(sourceRepo, getCodePath(jobName), option.BranchName)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.load_code_failed")))
return
}

var aiCenterCode = models.AICenterOfCloudBrainTwo
var specId = setting.FileNoteBook.SpecIdNPU
if setting.ModelartsCD.Enabled {
aiCenterCode = models.AICenterOfChengdu
specId = setting.FileNoteBook.SpecIdNPUCD
}
spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{
JobType: models.JobTypeDebug,
ComputeResource: models.NPU,
Cluster: models.OpenICluster,
AiCenterCode: aiCenterCode})
if err != nil || spec == nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification")))
return
}
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d ", ctx.User.ID, spec.ID)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance")))
return
}
ctx.Repo = &context.Repository{
Repository: repo,
}

var jobId string
if setting.ModelartsCD.Enabled {
jobId, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPUCD, spec, option.File,modelarts.AutoStopDurationMs/4)
} else {
jobId, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPU, spec, option.File,modelarts.AutoStopDurationMs/4)
}

if err != nil {
log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"])

ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error()))

return
}

ctx.JSON(http.StatusOK, models.BaseMessageApi{
Code: 0,
Message: jobId,
})

}

func isNoteBookFileExist(ctx *context.Context, option api.CreateFileNotebookJobOption) (bool, error) {
repoPathOfNoteBook := models.RepoPath(option.OwnerName, option.ProjectName)

gitRepoOfNoteBook, err := git.OpenRepository(repoPathOfNoteBook)
if err != nil {
log.Error("RepoRef Invalid repo "+repoPathOfNoteBook, err.Error())
return false, err
}
// We opened it, we should close it
defer func() {
// If it's been set to nil then assume someone else has closed it.
if gitRepoOfNoteBook != nil {
gitRepoOfNoteBook.Close()
}
}()
fileExist, err := fileExists(gitRepoOfNoteBook, option.File, option.BranchName)
if err != nil || !fileExist {
log.Error("Get file error:", err, ctx.Data["MsgID"])

return false, err
}
return true, nil
}

func uploadCodeFile(repo *models.Repository, codePath string, branchName string, filePath string, jobName string) string {
err := downloadCode(repo, codePath, branchName)
if err != nil {
return "cloudbrain.load_code_failed"
}

err = uploadOneFileToMinio(codePath, filePath, jobName, cloudbrain.CodeMountPath+"/")
if err != nil {
return "cloudbrain.load_code_failed"
}
return ""
}

func fileExists(gitRepo *git.Repository, path string, branch string) (bool, error) {

commit, err := gitRepo.GetBranchCommit(branch)
if err != nil {
return false, err
}
if _, err := commit.GetTreeEntryByPath(path); err != nil {
return false, err
}
return true, nil
}

+ 16
- 7
services/cloudbrain/cloudbrainTask/sync_status.go View File

@@ -1,20 +1,21 @@
package cloudbrainTask

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"net/http"
"strconv"
)

var noteBookOKMap = make(map[int64]int, 20)
var noteBookFailMap = make(map[int64]int, 20)

//if a task notebook url can get two times, the notebook can browser.
//if a task notebook url can get successfulCount times, the notebook can browser.
const successfulCount = 3
const maxSuccessfulCount=10

func SyncCloudBrainOneStatus(task *models.Cloudbrain) (*models.Cloudbrain, error) {
jobResult, err := cloudbrain.GetJob(task.JobID)
@@ -62,21 +63,29 @@ func isNoteBookReady(task *models.Cloudbrain) bool {
return true
}
noteBookUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName
r := httplib.Get(noteBookUrl)
res, err := r.Response()
res,err := http.Get(noteBookUrl)
if err != nil {
return false
}
log.Info("notebook success count:"+strconv.Itoa(noteBookOKMap[task.ID])+",fail count:"+strconv.Itoa(noteBookFailMap[task.ID]))
if res.StatusCode == http.StatusOK {
count := noteBookOKMap[task.ID]
if count < successfulCount-1 {
if count==0{ //如果是第一次成功,把失败数重置为0
noteBookFailMap[task.ID]=0
}

if count < successfulCount-1 || (noteBookFailMap[task.ID]==0 && count < maxSuccessfulCount-1) {
noteBookOKMap[task.ID] = count + 1
return false
} else {
log.Info("notebook success count:"+strconv.Itoa(count)+",fail count:"+strconv.Itoa(noteBookFailMap[task.ID]))
delete(noteBookOKMap, task.ID)
delete(noteBookFailMap, task.ID)
return true
}

}else{
noteBookFailMap[task.ID]+=1
}
return false



+ 12
- 0
services/cloudbrain/cloudbrainTask/train.go View File

@@ -810,6 +810,18 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error {
return nil
}

func uploadOneFileToMinio(codePath, filePath, jobName, parentDir string) error {
destObject := setting.CBCodePathPrefix + jobName + parentDir + path.Base(filePath)
sourceFile := codePath + "/" + filePath
err := storage.Attachments.UploadObject(destObject, sourceFile)
if err != nil {
log.Error("UploadObject(%s) failed: %s", filePath, err.Error())
return err
}
return nil

}

func readDir(dirname string) ([]os.FileInfo, error) {
f, err := os.Open(dirname)
if err != nil {


+ 2
- 46
services/cloudbrain/resource/resource_specification.go View File

@@ -246,10 +246,10 @@ func FindAvailableSpecs(userId int64, opts models.FindSpecsOptions) ([]*models.S
return nil, err
}
//filter exclusive specs
specs := filterExclusiveSpecs(r, userId)
specs := models.FilterExclusiveSpecs(r, userId)

//distinct by sourceSpecId
specs = distinctSpecs(specs)
specs = models.DistinctSpecs(specs)
return specs, err
}

@@ -265,50 +265,6 @@ func FindAvailableSpecs4Show(userId int64, opts models.FindSpecsOptions) ([]*api
return result, nil
}

func filterExclusiveSpecs(r []*models.Specification, userId int64) []*models.Specification {
specs := make([]*models.Specification, 0, len(r))
specMap := make(map[int64]string, 0)
for i := 0; i < len(r); i++ {
spec := r[i]
if _, has := specMap[spec.ID]; has {
continue
}
if !spec.IsExclusive {
specs = append(specs, spec)
specMap[spec.ID] = ""
continue
}
orgs := strings.Split(spec.ExclusiveOrg, ";")
for _, org := range orgs {
isMember, _ := models.IsOrganizationMemberByOrgName(org, userId)
if isMember {
specs = append(specs, spec)
specMap[spec.ID] = ""
break
}
}
}
return specs
}

func distinctSpecs(r []*models.Specification) []*models.Specification {
specs := make([]*models.Specification, 0, len(r))
sourceSpecIdMap := make(map[string]string, 0)
for i := 0; i < len(r); i++ {
spec := r[i]
if spec.SourceSpecId == "" {
specs = append(specs, spec)
continue
}
if _, has := sourceSpecIdMap[spec.SourceSpecId]; has {
continue
}
specs = append(specs, spec)
sourceSpecIdMap[spec.SourceSpecId] = ""
}
return specs
}

func GetAndCheckSpec(userId int64, specId int64, opts models.FindSpecsOptions) (*models.Specification, error) {
if specId == 0 {
return nil, nil


+ 72
- 7
services/cloudbrain/util.go View File

@@ -1,27 +1,33 @@
package cloudbrain

import (
"regexp"
"strconv"
"strings"
"time"


"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"strings"
)

func GetAiCenterShow(aiCenter string,ctx *context.Context) string{
func GetAiCenterShow(aiCenter string, ctx *context.Context) string {
aiCenterInfo := strings.Split(aiCenter, "+")

if len(aiCenterInfo) == 2{
if setting.C2NetMapInfo!=nil {
if info,ok:=setting.C2NetMapInfo[aiCenterInfo[0]];ok {
if len(aiCenterInfo) == 2 {
if setting.C2NetMapInfo != nil {
if info, ok := setting.C2NetMapInfo[aiCenterInfo[0]]; ok {
if ctx.Language() == "zh-CN" {
return info.Content
} else {
return info.ContentEN
}
}else{
} else {
return aiCenterInfo[1]
}

}else{
} else {
return aiCenterInfo[1]
}

@@ -29,5 +35,64 @@ func GetAiCenterShow(aiCenter string,ctx *context.Context) string{

return ""

}

func GetDisplayJobName(username string) string {
t := time.Now()
return jobNamePrefixValid(cutString(username, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
}

func cutString(str string, lens int) string {
if len(str) < lens {
return str
}
return str[:lens]
}

func jobNamePrefixValid(s string) string {
lowStr := strings.ToLower(s)
re := regexp.MustCompile(`[^a-z0-9_\\-]+`)

removeSpecial := re.ReplaceAllString(lowStr, "")

re = regexp.MustCompile(`^[_\\-]+`)
return re.ReplaceAllString(removeSpecial, "")
}

func GetAiCenterInfoByCenterCode(aiCenterCode string) *setting.C2NetSequenceInfo {
if setting.AiCenterCodeAndNameMapInfo != nil {
if info, ok := setting.AiCenterCodeAndNameMapInfo[aiCenterCode]; ok {
return info
} else {
return nil
}
} else {
return nil
}
}

func getAiCenterCode(aiCenter string) string {
aiCenterInfo := strings.Split(aiCenter, "+")
return aiCenterInfo[0]
}

func UpdateCloudbrainAiCenter(cloudbrain *models.CloudbrainInfo) *models.CloudbrainInfo {
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfCloudBrainOne
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfCloudBrainTwo
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeCDCenter {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfChengdu
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeC2Net {
cloudbrain.Cloudbrain.AiCenter = getAiCenterCode(cloudbrain.Cloudbrain.AiCenter)
cloudbrain.Cloudbrain.Cluster = models.C2NetCluster
}

return cloudbrain
}

+ 6
- 10
services/repository/repository.go View File

@@ -107,18 +107,13 @@ func GetRecommendCourseKeyWords() ([]string, error) {

}

func GetRecommendRepoFromPromote(filename string) ([]map[string]interface{}, error) {
func GetRecommendRepoFromPromote(repoMap []map[string]string) ([]map[string]interface{}, error) {
resultRepo := make([]map[string]interface{}, 0)
url := setting.RecommentRepoAddr + filename
result, err := RecommendFromPromote(url)

if err != nil {

return resultRepo, err
}

//resultRepo := make([]*models.Repository, 0)
for _, repoName := range result {
for _, record := range repoMap {
repoName := record["project_url"]
//log.Info("repoName=" + repoName + " tmpIndex1=" + fmt.Sprint(tmpIndex1) + " len(repoName)=" + fmt.Sprint(len(repoName)))
tmpIndex := strings.Index(repoName, "/")
if tmpIndex == -1 {
log.Info("error repo name format.")
@@ -131,7 +126,8 @@ func GetRecommendRepoFromPromote(filename string) ([]map[string]interface{}, err
repoMap["ID"] = fmt.Sprint(repo.ID)
repoMap["Name"] = repo.Name
repoMap["Alias"] = repo.Alias

repoMap["Label"] = record["class"]
repoMap["Label_en"] = record["class_en"]
repoMap["OwnerName"] = repo.OwnerName
repoMap["NumStars"] = repo.NumStars
repoMap["NumForks"] = repo.NumForks


+ 8
- 6
templates/admin/cloudbrain/list.tmpl View File

@@ -170,7 +170,7 @@
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}" title="{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
@@ -184,16 +184,16 @@
spanEl.setAttribute('title', cardType);
spanEl.innerText = cardType;
var cluster = spec.Cluster || '--';
var cluster = {{.Cluster}} || '--';
var clusterName = document.querySelector('.cloudbrain_debug').dataset['cluster' + cluster[0] + cluster.toLocaleLowerCase().slice(1)] || '--';
spanEl = document.querySelector('.cluster_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', cluster);
spanEl.innerText = clusterName;

var aiCenter = spec.AiCenterName || '--';
spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', aiCenter);
spanEl.innerText = aiCenter;
// var aiCenter = spec.AiCenterName || '--';
// spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
// spanEl.setAttribute('title', aiCenter);
// spanEl.innerText = aiCenter;
})();
</script>
<!-- 创建者 -->
@@ -238,6 +238,7 @@
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
{{if not .BootFile}}
<a id="ai-debug-{{$JobID}}"
class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button'
data-jobid="{{$JobID}}"
@@ -245,6 +246,7 @@
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{end}}
</form>
</div>
{{end}}


+ 4
- 6
templates/admin/cloudbrain/search.tmpl View File

@@ -71,22 +71,20 @@
document.addEventListener('DOMContentLoaded', function() {
$.ajax({
type: "GET",
url: "/api/v1/cloudbrain/get_center_info",
url: "/api/v1/cloudbrainboard/cloudbrain/resource_queues",
dataType: "json",
data: {},
success: function (res) {
var data = res || [];
var data = res.resourceQueues || [];
var aiCenterSelEl = $('#aiCenter-sel');
var itemEl = aiCenterSelEl.find('.menu .item').eq(0);
var selectAiCenterCode = aiCenterSelEl.find('.default').attr('aicenter');
var selectAiCenterName = '';
var lang = document.querySelector('html').getAttribute('lang') || 'en-US';
var except = ['', 'more'];
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.name;
if (except.indexOf(aiCenterCode) >= 0) continue;
var aiCenterName = lang === 'en-US' ? dataI.content_en : dataI.content;
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 4
- 6
templates/admin/cloudbrain/search_dashboard.tmpl View File

@@ -85,22 +85,20 @@
document.addEventListener('DOMContentLoaded', function() {
$.ajax({
type: "GET",
url: "/api/v1/cloudbrain/get_center_info",
url: "/api/v1/cloudbrainboard/cloudbrain/resource_queues",
dataType: "json",
data: {},
success: function (res) {
var data = res || [];
var data = res.resourceQueues || [];
var aiCenterSelEl = $('#aiCenter-sel');
var itemEl = aiCenterSelEl.find('.menu .item').eq(0);
var selectAiCenterCode = aiCenterSelEl.find('.default').attr('aicenter');
var selectAiCenterName = '';
var lang = document.querySelector('html').getAttribute('lang') || 'en-US';
var except = ['', 'more'];
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.name;
if (except.indexOf(aiCenterCode) >= 0) continue;
var aiCenterName = lang === 'en-US' ? dataI.content_en : dataI.content;
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 47
- 7
templates/base/footer_content.tmpl View File

@@ -1,15 +1,17 @@
<footer>
<footer style="border-top:none;">
<div class="ui container">
<div class="ui grid">
<div class="sixteen wide mobile eight wide tablet eight wide computer column">
<div class="sixteen wide mobile wide tablet three wide computer column mobile-text-align-center">
<img style="width:166px;height:66px;margin-top:24px;" src="/img/logo-footer.svg" />
</div>
<div class="sixteen wide mobile wide tablet seven wide computer column" style="padding-left:20px;">
<div class="ui three column grid">
<div class="column ui vertical text menu">
<div class="header item">{{.i18n.Tr "custom.head.community"}}</div>
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">{{.i18n.Tr "custom.foot.council"}}</a>
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">{{.i18n.Tr "custom.foot.technical_committee"}}</a>
<a href="https://openi.org.cn/html/Club/2019/0228/17.html" class="item">{{.i18n.Tr "custom.foot.join"}}</a>
<a href="{{AppSubUrl}}/home/term/" class="item">{{.i18n.Tr "custom.foot.agreement"}}</a>
<a href="{{AppSubUrl}}/home/term/" class="item">{{.i18n.Tr "custom.foot.agreement"}}</a>
</div>
<div class="column ui vertical text menu">
<div class="header item">{{.i18n.Tr "custom.foot.news"}}</div>
@@ -48,10 +50,10 @@
});
})();
</script>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon" ></i> {{.i18n.Tr "custom.Platform_Tutorial"}}</a>
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon" ></i> {{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon"></i> API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}
@@ -61,7 +63,40 @@
</div>
</div>
</div>
<div class="sixteen wide mobile eight wide tablet eight wide computer column" style=" margin:2.0rem 0">
<style>
.contacts-qr-code-c {
margin:2.0rem 0;
display:flex !important;
justify-content:flex-end;
}
</style>
<div class="sixteen wide mobile wide tablet six wide computer column contacts-qr-code-c mobile-justify-content-center">
<div style="text-align:center;">
<div style="width:80px;height:80px;display:inline-block;
background-image: url('https://openi.pcl.ac.cn/zeizei/OpenI_Learning/raw/branch/master/img/official_account_mini.png');
background-repeat: no-repeat;
background-attachment: scroll;
background-position: -2px -2px;
background-size: 84px 84px;
background-color: transparent;"
></div>
<p style="margin-top:4px;color:rgb(16, 16, 16);">{{.i18n.Tr "custom.foot.openi_subscription_number"}}</p>
</div>
<div style="text-align:center;margin-left:40px;">
<div style="width:80px;height:80px;display:inline-block;
background-image: url('https://openi.pcl.ac.cn/zeizei/OpenI_Learning/raw/branch/master/img/wechatgroup.jpg');
background-repeat: no-repeat;
background-attachment: scroll;
background-position: -7px -25px;
background-size: 94px 117px;
background-color: transparent;"
></div>
<p style="margin-top:4px;color:rgb(16, 16, 16);">{{.i18n.Tr "custom.foot.user_communication_group"}}</p>
</div>
</div>
</div>
<div class="ui grid" style="margin-top:2rem;margin-bottom:2rem;border-top:1px solid #d6d6d6;">
<div class="sixteen wide mobile sixteen wide tablet wide computer column" style=" margin:1.0rem 0;text-align:center;">
{{.i18n.Tr "custom.foot.copyright"}} <a href="http://beian.miit.gov.cn/" target="_blank">京ICP备18004880号</a>
<br>
{{.i18n.Tr "home.powerdby"}}<a href="https://www.trustie.net/" target="_blank">Trustie确实</a>{{.i18n.Tr "、Gitea"}}
@@ -69,4 +104,9 @@
</div>
</div>
</div>
<div class="__go-top" style="display:none;z-index:100;width:44px;height:44px;bottom:50px;right:50px;background:rgba(16, 16, 16, 0.1);position:fixed;cursor:pointer;border-radius:5px;">
<div style="display:flex;align-items:center;justify-content:center;height:100%;">
<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 mHEdk svg-icon-path-icon fill" viewBox="0 0 32 32" width="30" height="30"><defs data-reactroot=""></defs><g><path fill="rgba(16, 16, 16, 0.6)" d="M17.333 10.437v16.229h-2.667v-16.229l-7.152 7.152-1.885-1.885 10.371-10.371 10.371 10.371-1.885 1.885-7.152-7.152z"></path></g></svg>
</div>
</div>
</footer>

+ 2
- 2
templates/base/footer_content_fluid.tmpl View File

@@ -46,10 +46,10 @@
});
})();
</script>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon"></i> {{.i18n.Tr "custom.Platform_Tutorial"}} </a>
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon"></i> {{.i18n.Tr "custom.Platform_Tutorial"}} </a>
{{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon" ></i> API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}


+ 1
- 0
templates/base/head.tmpl View File

@@ -240,6 +240,7 @@ var _hmt = _hmt || [];
}
}
if (isShowNoticeTag){
if (!document.getElementById("notic_content")) return;
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{


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

@@ -247,6 +247,7 @@ var _hmt = _hmt || [];
}
}
if (isShowNoticeTag){
if (!document.getElementById("notic_content")) return;
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{


+ 42
- 21
templates/base/head_navbar.tmpl View File

@@ -1,5 +1,5 @@
<div class="ui container" id="navbar">
<div class="item brand" style="justify-content: space-between;">
<div class="item brand" style="justify-content: space-between;height:62px;">
<a href="https://openi.org.cn/">
<img class="ui mini image" src="{{StaticUrlPrefix}}/img/logo-w.svg">
</a>
@@ -7,15 +7,18 @@
<i class="sidebar icon"></i>
</div>
</div>
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div>
<div class="item brand" style="margin-left: 0.9rem;">
<div class="item brand" style="padding-right:1.9rem">
<a href="/">
<img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg">
<!-- <img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg"> -->
<div>
<div style="display:flex">
<div style="line-height:24px;font-weight:700;font-size:24px;color:rgba(91,185,115,1);margin-right:2px;">AI</div>
<div style="line-height:24px;font-weight:700;font-size:21px;color:rgba(91,185,115,1);">协作平台</div>
</div>
<div style="font-weight:300;font-size:12px;color: rgba(254,221,89,1);font-style:normal;letter-spacing: 0.1px;line-height:17px;">Powered by C²NET</div>
</div>
</a>
</div>


{{if .IsSigned}}
<div class=" item edge">
<div class="dropdown-menu">
@@ -116,14 +119,14 @@
{{if .IsSigned}}
<div class="right stackable menu">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<div class="ui fluid action input" style="background:transparent ;border-radius: 5px;width: 200px;height:30px;border:rgb(233,233,233) solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:white;background:transparent;color:white;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="hot">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->
<button style="border:none;background-color:transparent;outline:none;border-radius:5px;cursor:pointer;">
<img type="submit" style="width:21px;height:21px;margin:auto;vertical-align:bottom;" src="/img/search.svg" >
</button>
</div>
</form>
<a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted">
@@ -160,7 +163,7 @@
</div><!-- end dropdown menu create new -->

<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">
<span class="text" style="display:flex;align-items:center;">
<img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}">
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span>
<span class="mobile-only">{{.SignedUser.Name}}</span>
@@ -188,7 +191,7 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<a class="item" href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
@@ -216,6 +219,13 @@
</a>
</div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu -->
<div class="ui simple item poping up" data-content="{{.i18n.Tr "help"}}" data-variation="tiny inverted">
<a target="_blank" href="{{AppSubUrl}}/docs/index.html">
<div style="display:flex;justify-content:center;align-items:center;font-size:10px;cursor:pointer;width:26px;height:26px;border-radius:100%;text-align:center;background: url(&quot;data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%221%22%20cx%3D%220%22%20cy%3D%220%22%20r%3D%221%22%20gradientTransform%3D%22matrix(0.7%2C%20-0.5250000000000001%2C%200.5250000000000001%2C%200.7%2C%200.283%2C%200.767)%22%3E%3Cstop%20stop-color%3D%22%2361d8dc%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23498af9%22%20stop-opacity%3D%221%22%20offset%3D%220.63%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23e840f7%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E&quot;);">
<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 fPsHiw svg-icon-path-icon fill" viewBox="0 0 384 512" width="16" height="16"><defs data-reactroot=""></defs><g><path fill="rgb(255,255,255)" d="M202.021 0C122.202 0 70.503 32.703 29.914 91.026c-7.363 10.58-5.093 25.086 5.178 32.874l43.138 32.709c10.373 7.865 25.132 6.026 33.253-4.148 25.049-31.381 43.63-49.449 82.757-49.449 30.764 0 68.816 19.799 68.816 49.631 0 22.552-18.617 34.134-48.993 51.164-35.423 19.86-82.299 44.576-82.299 106.405V320c0 13.255 10.745 24 24 24h72.471c13.255 0 24-10.745 24-24v-5.773c0-42.86 125.268-44.645 125.268-160.627C377.504 66.256 286.902 0 202.021 0zM192 373.459c-38.196 0-69.271 31.075-69.271 69.271 0 38.195 31.075 69.27 69.271 69.27s69.271-31.075 69.271-69.271-31.075-69.27-69.271-69.27z"></path></g></svg>
</div>
</a>
</div>
</div><!-- end signed user right menu -->

{{else}}
@@ -224,19 +234,19 @@
<div class="right stackable menu">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<div class="ui fluid action input" style="background:transparent ;border-radius: 5px;width: 200px;height:30px;border:rgb(233,233,233) solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:white;background:transparent;color:white;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="hot">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->
<button style="border:none;background-color:transparent;outline:none;border-radius:5px;cursor:pointer;">
<img type="submit" style="width:21px;height:21px;margin:auto;vertical-align:bottom;" src="/img/search.svg" >
</button>
</div>
</form>
{{if .ShowRegistrationButton}}
{{if .IsCourse}}
<a class="item{{if .PageIsSignUp}} active{{end}}" href="https://git.openi.org.cn/user/sign_up" target="_blank">
<a class="item{{if .PageIsSignUp}} active{{end}}" href="https://openi.pcl.ac.cn/user/sign_up" target="_blank">
{{svg "octicon-person" 16}} {{.i18n.Tr "register"}}
</a>
{{else}}
@@ -246,7 +256,7 @@
{{end}}
{{end}}
{{if .IsCourse}}
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="https://git.openi.org.cn/user/login?course=true" target="_blank">
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="https://openi.pcl.ac.cn/user/login?course=true" target="_blank">
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}}
</a>
{{else}}
@@ -254,9 +264,20 @@
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}}
</a>
{{end}}

<div class="ui simple item poping up" data-content="{{.i18n.Tr "help"}}" data-variation="tiny inverted">
<a target="_blank" href="{{AppSubUrl}}/docs/index.html">
<div style="display:flex;justify-content:center;align-items:center;font-size:10px;cursor:pointer;width:26px;height:26px;border-radius:100%;text-align:center;background: url(&quot;data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%221%22%20cx%3D%220%22%20cy%3D%220%22%20r%3D%221%22%20gradientTransform%3D%22matrix(0.7%2C%20-0.5250000000000001%2C%200.5250000000000001%2C%200.7%2C%200.283%2C%200.767)%22%3E%3Cstop%20stop-color%3D%22%2361d8dc%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23498af9%22%20stop-opacity%3D%221%22%20offset%3D%220.63%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23e840f7%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E&quot;);">
<svg xmlns="http://www.w3.org/2000/svg" class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 fPsHiw svg-icon-path-icon fill" viewBox="0 0 384 512" width="16" height="16"><defs data-reactroot=""></defs><g><path fill="rgb(255,255,255)" d="M202.021 0C122.202 0 70.503 32.703 29.914 91.026c-7.363 10.58-5.093 25.086 5.178 32.874l43.138 32.709c10.373 7.865 25.132 6.026 33.253-4.148 25.049-31.381 43.63-49.449 82.757-49.449 30.764 0 68.816 19.799 68.816 49.631 0 22.552-18.617 34.134-48.993 51.164-35.423 19.86-82.299 44.576-82.299 106.405V320c0 13.255 10.745 24 24 24h72.471c13.255 0 24-10.745 24-24v-5.773c0-42.86 125.268-44.645 125.268-160.627C377.504 66.256 286.902 0 202.021 0zM192 373.459c-38.196 0-69.271 31.075-69.271 69.271 0 38.195 31.075 69.27 69.271 69.27s69.271-31.075 69.271-69.271-31.075-69.27-69.271-69.27z"></path></g></svg>
</div>
</a>
</div>

</div><!-- end anonymous right menu -->

{{end}}



</div>


+ 1
- 1
templates/base/head_navbar_fluid.tmpl View File

@@ -186,7 +186,7 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<a class="item" href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>


+ 1
- 1
templates/base/head_navbar_home.tmpl View File

@@ -168,7 +168,7 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<a class="item" href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>


+ 1
- 1
templates/base/head_navbar_pro.tmpl View File

@@ -189,7 +189,7 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<a class="item" href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>


+ 1
- 1
templates/base/head_notice.tmpl View File

@@ -1,5 +1,5 @@
{{if not .IsCourse}}
{{ if .notices}}
{{ if (and .notices (not .PageIsHome)) }}
<div class="notic_content" id ="notic_content" style="display: block; position: relative">
<div class="ui container">
<marquee behavior="scroll" direction="left">


+ 36
- 0
templates/custom/home/home_activity.tmpl View File

@@ -0,0 +1,36 @@
<style>
.homeactivity {
padding-top: 5rem;
padding-bottom: 6rem;
overflow: hidden;
}
.homeactivity .card {
width: 360px !important;
height: 160px !important;
}
.homeactivity img {
width: 100% !important;
height: 100% !important;
}
.homeactivity .image-name {
font-size: 14px;
color: rgb(16, 16, 16);
text-align: center;
margin-top: 0.8em;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 20px;
box-sizing: border-box;
white-space: nowrap;
}
</style>
<div class="ui container homeactivity _hm-container">
<div class="ui center homepro-tit am-mb-20">
<h2>{{.page_recommend_activity}}</h2>
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p>
</div>
<div class="event-list">
<div class="swiper-wrapper" id="recommendactivity"></div>
<div class="swiper-pagination"></div>
</div>
</div>

+ 85
- 0
templates/custom/home/home_dataset.tmpl View File

@@ -0,0 +1,85 @@
<style>
.homedataset {
padding-top: 4em;
padding-bottom: 4em;
}
.home-dataset-list {
position: relative;
z-index: 9;
padding: 0em 1em 3em;
overflow: hidden;
}
.home-dataset-list .swiper-slide {
padding-top: 5px;
}
.home-dataset-list .dataset-card {
height: 130px;
width: 130px;
border: 1px solid rgba(157, 197, 226, 0.4);
box-shadow: rgb(157 197 226 / 20%) 0px 5px 10px 0px;
color: rgb(16, 16, 16);
border-radius: 6px;
display:flex;
justify-content: center;
align-items: center;
flex-direction: column;
transition: all 0.1s;
}
.home-dataset-list .dataset-card:hover {
transform: translateY(-3px);
}
.home-dataset-list .dataset-card>div {
width:100%;
display: flex;
justify-content: center;
}
.home-dataset-list .dataset-card .content {
width:100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
padding: 0 10px;
}
.home-dataset-list .dataset-card .icon-c {
font-size: 14px;
color: #101010;
display:flex;
justify-content: center;
align-items: center;
margin-bottom: 8px;
}
.home-dataset-list .dataset-card .label {
font-size: 14px;
color: #101010;
margin-bottom: 8px;
}
.home-dataset-list .dataset-card .svg.fill:not([stroke]) {
fill: url(#ila93em9ydx6bi61,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs);
}
.home-dataset-list .dataset-card .svg.fill:not([fill]) {
fill: url(#ila93em9ydx6bi61,1,rs,1,f000f000,f0rsf000,f000,00e6msqtrs,dw4hjuqlrs,ri00exmcrs);
}
.home-dataset-list .dataset-card .count {
font-size:12px;
color:rgb(136,136,136);
}
.home-dataset-list .swiper-pagination-bullet-active {
width: 40px;
border-radius: 4px;
}
</style>
<div class="ui container homedataset _hm-container">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column mobile-text-align-center">
<h2>{{.i18n.Tr "home.search_dataset"}}</h2>
<p><span class="ui text grey">{{.i18n.Tr "home.datasets_descr"}}&nbsp;</span><a href="/explore/datasets">{{.i18n.Tr "home.search_dataset"}}</a></p>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="home-dataset-list">
<div class="swiper-wrapper" id="home_dataset"></div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
</div>

+ 20
- 0
templates/custom/home/home_org.tmpl View File

@@ -0,0 +1,20 @@
<style>

</style>
<div class="ui container homeorg _hm-container" style="max-width:1200px;">
<div class="ui stackable grid">
<div class="sixteen wide tablet sixteen wide computer column mobile-text-align-center" style="text-align:center;">
<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>
{{.i18n.Tr "home.org_see"}}
<a href="{{AppSubUrl}}/explore/organizations" class="">{{.page_recommend_org_more}}</a>
</p>
</div>
<div class="sixteen wide tablet sixteen wide computer column">
<div class="homeorg-list">
<div class="swiper-wrapper" id="recommendorg"></div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
</div>

+ 21
- 0
templates/custom/home/home_repo.tmpl View File

@@ -0,0 +1,21 @@
<style>
.homepro-bg {
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(0.013999999999999973%2C%201.0040000000000002%2C%20-0.1807553452932099%2C%200.013999999999999973%2C%200.374%2C%20-0.007)%22%3E%3Cstop%20stop-color%3D%22%23eee9da%22%20stop-opacity%3D%220.2%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23f3e7f7%22%20stop-opacity%3D%220.26%22%20offset%3D%220.29%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23d0e7ff%22%20stop-opacity%3D%220.3%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E");
}
</style>
<div class="homepro-bg">
<div class="ui container homepro _hm-container" style="padding-top:4rem;padding-bottom:3rem;">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column mobile-text-align-center">
<h2>{{.page_recommend_repo}}</h2>
<p><span class="ui text grey">{{.page_recommend_repo_desc}}&nbsp;</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>&nbsp;<span class="ui text grey">{{.page_recommend_repo_go}}</span>&nbsp;<a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="homepro-list">
<div class="swiper-wrapper" id="recommendrepo"></div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
</div>
</div>

+ 2079
- 0
templates/custom/home/home_top.tmpl
File diff suppressed because it is too large
View File


+ 134
- 0
templates/custom/home/home_user_experience.tmpl View File

@@ -0,0 +1,134 @@
<style>
.homeuserexp-bg {
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(0.04900000000000009%2C%201.104%2C%20-0.06118479166666667%2C%200.04900000000000009%2C%200.339%2C%20-0.107)%22%3E%3Cstop%20stop-color%3D%22%23ffffff%22%20stop-opacity%3D%220.33%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23e5e7eb%22%20stop-opacity%3D%220.3%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E");
}
.homeuserexp {
padding-top: 5em;
padding-bottom: 2em;
}

.homeuserexp .swiper-prev {
position: absolute;
top: 104px;
left: 14px;
z-index: 10;
}

.homeuserexp .swiper-next {
position: absolute;
top: 104px;
right: 14px;
z-index: 10;
}
.homeuserexp .prev-next-i {
font-size: 22px;
border: 1px solid rgb(0, 122, 255);
border-radius: 100%;
color: rgb(0, 122, 255);
cursor: pointer;
}
.homeuserexp .swiper-prev.swiper-button-disabled .prev-next-i, .homeuserexp .swiper-next.swiper-button-disabled .prev-next-i {
opacity: 0.35;
cursor: default;
}

.home-user-exp-list {
position: relative;
z-index: 9;
padding: 0em 1.2em 3em 1.2em;
overflow: hidden;
}

.home-user-exp-list .user-card {
width: 240px;
height: 180px;
color: rgb(16, 16, 16);
border-radius: 6px;
display:flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.home-user-exp-list .swiper-slide {
display: flex;
justify-content: center;
}

.home-user-exp-list .user-card>div {
width:100%;
display: flex;
justify-content: center;
}

.home-user-exp-list .user-card .content {
width:100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
padding: 0 10px;
}

.home-user-exp-list .user-card .img-c {
font-size: 14px;
color: #101010;
display:flex;
justify-content: center;
align-items: center;
height: 74px;
margin-bottom: 8px;
}

.home-user-exp-list .user-card .img {
border: 3px solid rgb(243, 240, 164);
border-radius: 100%;
box-shadow: rgb(255 220 144) 0px 0px 0px 2px;
height: 60px;
width: 60px;
display: block;
background-size:cover;
}

.home-user-exp-list .user-card .label {
font-size: 14px;
color: #101010;
margin-bottom: 8px;
font-weight: 550;
}

.home-user-exp-list .user-card .descr {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
font-size:12px;
color:rgb(136,136,136);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
max-height: 50px;
height: 40px;
white-space: break-spaces;
}
</style>
<div class="homeuserexp-bg">
<div class="ui container homeuserexp _hm-container">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column mobile-text-align-center">
<h2>{{.i18n.Tr "home.experience_officer"}}</h2>
<p><a href="https://openi.org.cn/index.php?m=content&c=index&a=lists&catid=220">{{.i18n.Tr "home.openi_experience_officer_plan"}}</a><span class="ui text grey">{{.i18n.Tr "home.more_benefits"}}</span></p>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="home-user-exp-list">
<div class="swiper-wrapper" id="home_user-exp"></div>
<div style="display:none;" class="swiper-button-prev"></div>
<div style="display:none;" class="swiper-button-next"></div>
</div>
<div class="swiper-prev"><i class="ri-arrow-left-line prev-next-i"></i></div>
<div class="swiper-next"><i class="ri-arrow-right-line prev-next-i"></i></div>
</div>
</div>
</div>
</div>

+ 7
- 7
templates/explore/repo_orgtop.tmpl View File

@@ -46,49 +46,49 @@
{{end}}-->
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/OpenI">
<a class="image" href="https://openi.pcl.ac.cn/OpenI">
<img src="/img/org-openi@2x-80.jpg" alt="OpenI 启智社区" title="OpenI 启智社区">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/JDOpenISCT">
<a class="image" href="https://openi.pcl.ac.cn/JDOpenISCT">
<img src="/img/org-jd@2x-80.jpg" alt="京东智能供应链开源工具" title="京东智能供应链开源工具">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/OpenI/TensorLayerX">
<a class="image" href="https://openi.pcl.ac.cn/OpenI/TensorLayerX">
<img src="/img/org-tensorlayer@2x-80.jpg" alt="TensorLayer" title="TensorLayer">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/PCL-Platform.Intelligence">
<a class="image" href="https://openi.pcl.ac.cn/PCL-Platform.Intelligence">
<img src="/img/org-platform@2x-80.jpg" alt="PCL-Platform.Intelligence" title="PCL-Platform.Intelligence">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/BAAI">
<a class="image" href="https://openi.pcl.ac.cn/BAAI">
<img src="/img/org-baai@2x-80.jpg" alt="BAAI" title="BAAI">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/OpenModelZoo">
<a class="image" href="https://openi.pcl.ac.cn/OpenModelZoo">
<img src="/img/org-modelzoo@2x-80.jpg" alt="OpenModelZoo" title="OpenModelZoo">
</a>
</div>
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/PCL_EngineClub">
<a class="image" href="https://openi.pcl.ac.cn/PCL_EngineClub">
<img src="/img/org-engineclub@2x-80.jpg" alt="PCL_EngineClub" title="PCL_EngineClub">
</a>
</div>


+ 5
- 5
templates/explore/repo_right.tmpl View File

@@ -9,31 +9,31 @@
<div class="item">
<i class="sticky note outline icon"></i>
<div class="content">
<div ><a href="https://git.openi.org.cn/OpenI/aiforge/wiki">启智AI开发协同平台使用说明</a></div>
<div ><a href="https://openi.pcl.ac.cn/OpenI/aiforge/wiki">启智AI开发协同平台使用说明</a></div>
</div>
</div>
<div class="item">
<i class="sticky note outline icon"></i>
<div class="content">
<div ><a href="https://git.openi.org.cn/OpenI/Paddle/wiki">启智飞桨 Paddle 2.0 项目手册</a></div>
<div ><a href="https://openi.pcl.ac.cn/OpenI/Paddle/wiki">启智飞桨 Paddle 2.0 项目手册</a></div>
</div>
</div>
<div class="item">
<i class="sticky note outline icon"></i>
<div class="content">
<div ><a href="https://git.openi.org.cn/OpenI/aiforge/wiki/cloudbrain">启智社区使用云脑计算资源进行调试说明</a></div>
<div ><a href="https://openi.pcl.ac.cn/OpenI/aiforge/wiki/cloudbrain">启智社区使用云脑计算资源进行调试说明</a></div>
</div>
</div>
<div class="item">
<i class="sticky note outline icon"></i>
<div class="content">
<div ><a href="https://git.openi.org.cn/PCL-Federated.Learning.Middleware/HiStar/wiki">海星HiStar:联邦深度学习中间件帮助文档</a></div>
<div ><a href="https://openi.pcl.ac.cn/PCL-Federated.Learning.Middleware/HiStar/wiki">海星HiStar:联邦深度学习中间件帮助文档</a></div>
</div>
</div>
<div class="item">
<i class="sticky note outline icon"></i>
<div class="content">
<div ><a href="https://git.openi.org.cn/OpenI/octopus/wiki/启智章鱼">启智章鱼开源项目文档</a></div>
<div ><a href="https://openi.pcl.ac.cn/OpenI/octopus/wiki/启智章鱼">启智章鱼开源项目文档</a></div>
</div>
</div>
</div>

+ 1
- 3
templates/explore/repos.tmpl View File

@@ -1,9 +1,7 @@
{{template "base/head_pro" .}}
{{template "base/head_home" .}}
<div class="explore repositories">

{{template "explore/repo_search" .}}
{{template "explore/repo_orgtop" .}}
<div class="ui container">
<div class="ui grid">
{{template "explore/repo_left" .}}


+ 27
- 89
templates/home.tmpl View File

@@ -1,99 +1,32 @@
{{template "base/head_home" .}}
<div class="ui vertical masthead secondary hometop segment">
<div class="ui container" style="position: relative;">
<div class="ui center homebanner">
<h1 class="ui huge header">
{{.page_title}}
<div class="sub header">
{{.page_small_title}}
</div>
</h1>
<p class="ui am-lh-18">{{.page_description}}</p>
{{if .IsSigned}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/dashboard">{{.page_use}} <i class="right arrow icon"></i></a>
{{else}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/user/login">{{.page_use}} <i class="right arrow icon"></i></a>
{{end}}
</div>
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
<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">
<div class="newslist">
<div class="ui mini aligned list swiper-wrapper" id="newmessage">
</div>
</div>
</div>
</div>
</div><!-- end homenews -->
</div>
</div><!-- end segment -->
<div class="ui vertical masthead secondary hometop segment" style="background:transparent;margin-bottom:0">
{{template "custom/home/home_top" .}}
</div>

<!--组织-->
<div class="ui container homeorg">
<div class="ui stackable grid">
<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>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="homeorg-list">
<div class="swiper-wrapper" id="recommendorg">
</div>
<div class="swiper-pagination"></div>
</div>
</div>
{{template "custom/home/home_org" .}}

<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>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="event-list">
<div class="swiper-wrapper" id="recommendactivity">
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
<div class="leftline01"></div>
</div>
<!--项目-->
<div class="ui container homepro">
<div class="leftline02"></div>
<div class="leftline02-2"></div>
<div class="ui center homepro-tit am-mb-20">
<h2>{{.page_recommend_repo}}</h2>
<p><span class="ui text grey">{{.page_recommend_repo_desc}}&nbsp;</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>{{.page_recommend_repo_go}}&nbsp;<a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p>
</div>
<!-- 项目 -->
{{template "custom/home/home_repo" .}}

<div class="homepro-list">
<div class="swiper-wrapper" id="recommendrepo">
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<!-- 数据集 -->
{{template "custom/home/home_dataset" .}}

<!-- 体验官 -->
{{template "custom/home/home_user_experience" .}}

<!-- 社区活动 -->
{{template "custom/home/home_activity" .}}

<!-- 中国算力网(C²NET) -->
<div class="ui vertical masthead secondary c2net segment">
<div class="ui container">
<div class="ui center am-pt-30 am-pb-30">
<h2>{{.i18n.Tr "home.c2net_title"}}</h2>
<p><span class="ui text grey">{{.i18n.Tr "home.c2net_desc"}}</p>
</div>

<div id="app" v-cloak>
<div id="app" class="_hm-computing-net-container" v-cloak>
<!--底座-->
<div class="rotation3D-baseMap"></div>
<!--旋转3D-->
@@ -135,12 +68,13 @@
</div>
</div>
</div><!--rotation3D end-->
<div class="_hm-computing-net-mobile-container" style="display:none;"></div>
</div>
</div>
</div>

<!-- 协同开发环境 -->
<a name="fourth"></a>
<div class="ui container i-env">
<div class="ui container i-env _hm-container" style="padding-bottom:0rem;padding-top:4rem;">
<div class="ui center am-pb-30">
<h2>{{.page_dev_env}}</h2>
<p><span class="ui text grey">{{.page_dev_env_desc}}</p>
@@ -193,8 +127,10 @@
</div>
</div>

<!-- 启智AI协作平台 介绍 -->
<!--
<a name="fifth"></a>
<div class="ui container">
<div class="ui container _hm-container">
<div class="ui very padded inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
@@ -221,7 +157,9 @@
</div>
</div>
</div>
<div class="am-mt-30"></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>



+ 81
- 0
templates/notice.tmpl View File

@@ -0,0 +1,81 @@

{{template "base/head_home" .}}
<style>
.notice-container {
}
.notice-row {
display: flex;
justify-content: space-between;
align-items: center;
height: 52px;
border-bottom: 1px solid rgba(157, 197, 226, 0.2);
padding: 0 16px;
}
.notice-title {
flex: 1;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.notice-title a {
font-size: 16px;
color: rgb(16, 16, 16);
}
.notice-title a:hover {
opacity: 0.8;
}
.notice-time {
width: 150px;
text-align: right;
font-size: 14px;
color: rgba(16, 16, 16, 0.6);
}
</style>
<div class="ui container">
<h3 class="ui center am-pt-30 am-pb-20">{{.i18n.Tr "notice_announcement"}}</h3>
<div class="notice-container">
</div>
</div>
{{template "base/footer" .}}
<script>
;(function() {
var isZh = document.documentElement.getAttribute('lang') == 'zh-CN';
function getNotice() {
$.ajax({
type:"GET",
url:"/dashboard/invitation",
dataType:"json",
data: {
filename: 'notice/notice.json',
},
success:function(data){
if (!data) return;
try {
var noticeList = JSON.parse(data).Notices || [];
var noticeEl = $('.notice-container');
for (var i = 0, iLen = noticeList.length; i < iLen; i++) {
var noticeObj = noticeList[i];
noticeEl.append(`<div class="notice-row">
<div class="notice-title">
<a class="_hm-notice" href="${noticeObj.Link}">
<i class="ri-arrow-right-s-line" style="vertical-align:-2px;"></i>
<span>${isZh ? noticeObj.Title : (noticeObj.Title_en || noticeObj.Title)}</span>
</a>
</div>
<div class="notice-time">${noticeObj.Date || ''}</div>
</div>`);
}
} catch (e) {
console.info(e);
}
},
error:function(err) {
console.info(err);
}
});
}
getNotice();
})();
</script>

+ 2
- 2
templates/org/home_courses.tmpl View File

@@ -116,7 +116,7 @@
<div class="ui sixteen wide mobile six wide tablet four wide computer column">
<div class=" ui bottom attached segment text center noborder text center" >
<a style="width: 80%;" class="ui green button bpadding" href="https://git.openi.org.cn/course/create" target="_blank"><i class="ri-folder-add-line" style="vertical-align: middle;"></i> &nbsp;{{.i18n.Tr "org.release_course"}} </a>
<a style="width: 80%;" class="ui green button bpadding" href="https://openi.pcl.ac.cn/course/create" target="_blank"><i class="ri-folder-add-line" style="vertical-align: middle;"></i> &nbsp;{{.i18n.Tr "org.release_course"}} </a>
</div>
</div>
</div>
@@ -185,7 +185,7 @@
{{if .IsSigned}}
<a class="ui blue basic button" onclick="jion_course_team()" style="width: 80%;"> <i class="ri-user-add-line"></i> {{.i18n.Tr "org.teams.join_teams"}}</a>
{{else}}
<a class="ui blue basic button" href="https://git.openi.org.cn/user/login?course=true" style="width: 80%;" target="_blank"> <i class="ri-user-add-line"></i> {{.i18n.Tr "org.teams.join_teams"}}</a>
<a class="ui blue basic button" href="https://openi.pcl.ac.cn/user/login?course=true" style="width: 80%;" target="_blank"> <i class="ri-user-add-line"></i> {{.i18n.Tr "org.teams.join_teams"}}</a>
{{end}}
</div>
</div>


+ 10
- 10
templates/repo/cloudbrain/benchmark/new.tmpl View File

@@ -113,7 +113,7 @@
data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}}
data-position="right center" data-variation="mini"></i>
</span>
<a id="benchmark_model_example" href="https://git.openi.org.cn/BDIP/snn4imagenet"
<a id="benchmark_model_example" href="https://openi.pcl.ac.cn/BDIP/snn4imagenet"
target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>

@@ -270,7 +270,7 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}}</label>
<input disabled="disabled" style="width: 33.5%;" name="train_file" id="train_file"
value="train.py" tabindex="3" autofocus required maxlength="254">
<a id="train_href_id" href="https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark"
<a id="train_href_id" href="https://openi.pcl.ac.cn/CV_benchmark/CV_reID_benchmark"
target="_blank">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}}</a>
</div>

@@ -278,7 +278,7 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}}</label>
<input disabled="disabled" style="width: 33.5%;" name="test_file" id="test_file" value="test.py"
tabindex="3" autofocus required maxlength="254">
<a id="test_href_id" href="https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark"
<a id="test_href_id" href="https://openi.pcl.ac.cn/CV_benchmark/CV_reID_benchmark"
target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>

@@ -349,7 +349,7 @@
<label class="label-fix-width" style="font-weight: normal;">推理程序</label>
<input disabled="disabled" style="width: 33.5%;" name="test_file" id="test_file" value="test.py"
tabindex="3" autofocus required maxlength="254">
<a id="test_href_id" href="https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark"
<a id="test_href_id" href="https://openi.pcl.ac.cn/CV_benchmark/CV_reID_benchmark"
target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>

@@ -390,10 +390,10 @@
onChange: function (value, text, $selectedItem) {
if (value === "BRAINSCORE") {
$('#brainscore_child_type').css('display', 'block')
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/BDIP/similarity2brain_ann')
$('#benchmark_model_example').attr('href', 'https://openi.pcl.ac.cn/BDIP/similarity2brain_ann')
} else {
$('#brainscore_child_type').css('display', 'none')
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/BDIP/snn4imagenet')
$('#benchmark_model_example').attr('href', 'https://openi.pcl.ac.cn/BDIP/snn4imagenet')
}
}
})
@@ -401,11 +401,11 @@
function setChildType() {
let type_id = $('#benchmark_types_id').val();
if (type_id == 3) {
$('#train_href_id').attr('href', 'https://git.openi.org.cn/CV_benchmark/CV_MOT_benchmark');
$('#test_href_id').attr('href', 'https://git.openi.org.cn/CV_benchmark/CV_MOT_benchmark');
$('#train_href_id').attr('href', 'https://openi.pcl.ac.cn/CV_benchmark/CV_MOT_benchmark');
$('#test_href_id').attr('href', 'https://openi.pcl.ac.cn/CV_benchmark/CV_MOT_benchmark');
} else {
$('#train_href_id').attr('href', 'https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark');
$('#test_href_id').attr('href', 'https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark');
$('#train_href_id').attr('href', 'https://openi.pcl.ac.cn/CV_benchmark/CV_reID_benchmark');
$('#test_href_id').attr('href', 'https://openi.pcl.ac.cn/CV_benchmark/CV_reID_benchmark');
}
let child_selected_id = $('#benchmark_child_types_id_hidden').val();
$.get(`${repolink}/cloudbrain/benchmark/get_child_types?benchmark_type_id=${type_id}`, (data) => {


+ 1
- 1
templates/repo/cloudbrain/inference/new.tmpl View File

@@ -211,7 +211,7 @@
<span >
<i class="question circle icon" data-content={{.i18n.Tr "repo.modelarts.infer_job.boot_file_helper"}} data-position="top center" data-variation="inverted mini"></i>
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU/src/branch/master/inference.py" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
<a href="https://openi.pcl.ac.cn/OpenIOSSG/MNIST_PytorchExample_GPU/src/branch/master/inference.py" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>

<!-- 运行参数 -->


+ 2
- 72
templates/repo/cloudbrain/inference/show.tmpl View File

@@ -262,8 +262,6 @@
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item"
data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second"
onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
<a class="item log_bottom" data-tab="third"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item load-model-file" data-tab="four"
@@ -364,7 +362,7 @@
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
创建人
{{$.i18n.Tr "repo.cloudbrain_creator"}}
</td>

<td class="ti-text-form-content">
@@ -446,6 +444,7 @@
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.BranchName}}
<span style="margin-left:1rem" class="ui label">{{SubStr .CommitID 0 10}}</span>
</div>
</td>
</tr>
@@ -515,25 +514,6 @@

</div>
</div>

<div class="ui tab" data-tab="second">
<div>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached"
style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
<span id="info_display" class="info_text">

</span>
</div>

</div>

</div>

<div class="ui tab" data-tab="third">
<div class="file-info">
<a id="{{.VersionName}}-log-down"
@@ -616,56 +596,6 @@
$(document).ready(function () {
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobID
let downlaodFlag = {{ $.canDownload }}
let taskID = {{ $.task.ID }}
let realJobName = {{ $.task.JobName }}
function parseInfo() {
let jsonValue = document.getElementById("json_value").value;
let jsonObj = JSON.parse(jsonValue);
let podRoleName = jsonObj["podRoleName"];
let html = "";
if (podRoleName != null) {
let task0 = podRoleName["task1-0"];
let podEvents = jsonObj["podEvents"];
let podEventArray = podEvents[task0];
if (podEventArray != null) {
for (var i = 0; i < podEventArray.length; i++) {
if (podEventArray[i]["reason"] != "") {
html += "<p><b>[" + podEventArray[i]["reason"] + "]</b></p>";
html += "<p>" + podEventArray[i]["message"] + "</p>";
html += "<p>" + podEventArray[i]["action"] + "</p>";
}
}
}
let extras = jsonObj["extras"];
if (extras != null) {
for (var i = 0; i < extras.length; i++) {
if (extras[i]["reason"] != "") {
html += "<p><b>[" + extras[i]["reason"] + "]</b></p>";
html += "<p>" + extras[i]["message"] + "</p>";
html += "<p>" + extras[i]["action"] + "</p>";
}
}
}
}

let string = document.getElementById("ExitDiagnostics").value;
string = string.replace(/\r\n/g, "<br>")
string = string.replace(/\n/g, "<br>");
string = string.replace(/(\r\n)|(\n)/g, '<br>');

if (string != "") {
html += "<p><b>[ExitDiagnostics]</b></p>";
html += "<p>" + string + "</p>";
}

document.getElementById("info_display").innerHTML = html;
}

;(function() {
var SPEC = {{ .Spec }};
var showPoint = false;


+ 1
- 0
templates/repo/cloudbrain/show.tmpl View File

@@ -337,6 +337,7 @@
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-code">
{{.BranchName}}
<span style="margin-left:1rem" class="ui label">{{SubStr .CommitID 0 10}}</span>
</div>
</td>
</tr>


+ 1
- 1
templates/repo/cloudbrain/trainjob/new.tmpl View File

@@ -196,7 +196,7 @@
data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}}
data-position="right center" data-variation="mini"></i>
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
<a href="https://openi.pcl.ac.cn/OpenIOSSG/MNIST_PytorchExample_GPU" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>
<div id="select-multi-dataset">



Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save