#4028 V20230410

Merged
ychao_1983 merged 310 commits from V20230410 into develop 1 year ago
  1. +5
    -1
      .gitignore
  2. +0
    -688
      index.html
  3. +265
    -42
      models/ai_model_manage.go
  4. +27
    -3
      models/cloudbrain.go
  5. +2
    -0
      models/models.go
  6. +22
    -1
      models/repo.go
  7. +16
    -0
      models/repo_list.go
  8. +3
    -1
      modules/auth/cloudbrain.go
  9. +2
    -0
      modules/auth/grampus.go
  10. +4
    -1
      modules/auth/modelarts.go
  11. +11
    -12
      modules/cloudbrain/cloudbrain.go
  12. +4
    -4
      modules/convert/cloudbrain.go
  13. +19
    -10
      modules/grampus/grampus.go
  14. +45
    -4
      modules/markup/markdown/goldmark.go
  15. +28
    -10
      modules/markup/markdown/toc.go
  16. +1
    -1
      modules/markup/sanitizer.go
  17. +6
    -0
      modules/modelarts/modelarts.go
  18. +30
    -7
      modules/modelarts/resty.go
  19. +1
    -0
      modules/modelarts_cd/modelarts.go
  20. +15
    -8
      modules/modelarts_cd/resty.go
  21. +8
    -4
      modules/setting/setting.go
  22. +4
    -0
      modules/storage/local.go
  23. +4
    -0
      modules/storage/minio.go
  24. +33
    -1
      modules/storage/obs.go
  25. +4
    -2
      modules/storage/storage.go
  26. +4
    -0
      modules/structs/cloudbrain.go
  27. +1
    -1
      modules/templates/helper.go
  28. +8
    -3
      options/locale/locale_en-US.ini
  29. +8
    -3
      options/locale/locale_zh-CN.ini
  30. +89
    -0
      package-lock.json
  31. +1
    -0
      package.json
  32. +3
    -3
      public/home/home.js
  33. +57
    -0
      public/img/empty-box.svg
  34. +1
    -0
      public/img/holder.svg
  35. BIN
      public/img/ros-hmci/05ba445b9835d86f81dd3d2d2fb0085b.png
  36. BIN
      public/img/ros-hmci/07101d729ec50d8bf8c0329224585f14.png
  37. BIN
      public/img/ros-hmci/07efd9450ffe064783352fc7f834c818.png
  38. BIN
      public/img/ros-hmci/0ad3ccc7a16937626852494fe161f920.png
  39. BIN
      public/img/ros-hmci/0b51c576036515c0b151c2b73c848d5a.png
  40. BIN
      public/img/ros-hmci/0bcaad921656ccd036d59b5001290107.png
  41. BIN
      public/img/ros-hmci/0e3b98bffa39d78df6519384523216d4.png
  42. BIN
      public/img/ros-hmci/0f386ae5fc2a0ff6c19600002d0e5321.png
  43. BIN
      public/img/ros-hmci/1266ef6d15c9a75a4e74980373438d12.png
  44. BIN
      public/img/ros-hmci/12a58f09aa65651a4e8457a87d0c47c9.png
  45. BIN
      public/img/ros-hmci/1483edffca1c70a08974d6b7de6a3fdb.png
  46. BIN
      public/img/ros-hmci/15d30eeae7c75d1c55c672cee086d023.png
  47. BIN
      public/img/ros-hmci/15e78788894611bd018de8f762e13b1d.png
  48. BIN
      public/img/ros-hmci/18bc9f0fd8ffe1059aa8e57019ba88e8.png
  49. BIN
      public/img/ros-hmci/191a154003e8bbbd8b2faa94df79c381.png
  50. BIN
      public/img/ros-hmci/1a356bb5a7ce93c23243062386ea60e9.png
  51. BIN
      public/img/ros-hmci/1d7748ff8d2c3b099e0d8c2db16a0a0a.png
  52. BIN
      public/img/ros-hmci/1ea818c19c5613897903f3f07e4aabea.png
  53. BIN
      public/img/ros-hmci/202c82cca2cccbe1919fcee768356fa1.png
  54. BIN
      public/img/ros-hmci/227958a1d5796fb19d379cf8df9c873f.png
  55. BIN
      public/img/ros-hmci/23ea1b095bd7856806cbffaeaf3160bb.png
  56. BIN
      public/img/ros-hmci/2742681bb0685ab3ec198a5239289f24.png
  57. BIN
      public/img/ros-hmci/27d598cdd229958d8d8b3e1259e287b6.png
  58. BIN
      public/img/ros-hmci/2b245f6e8732299f6c5d29d45c09f4ab.png
  59. BIN
      public/img/ros-hmci/2b91f419b0c3fbd48469905da58b368a.png
  60. BIN
      public/img/ros-hmci/2d4d93f3962be672964d8e494dae69a9.png
  61. BIN
      public/img/ros-hmci/2dc305b08d2bff74de723e660cf54f51.png
  62. BIN
      public/img/ros-hmci/2df728971445f735584502351e69f404.png
  63. BIN
      public/img/ros-hmci/2dfd8be62195aea32d3721e9c44a7b65.png
  64. BIN
      public/img/ros-hmci/2fb2e97a136836d83ca1b1970d5ebc05.png
  65. BIN
      public/img/ros-hmci/307193d9e46833b97c8e5afae89a3b84.png
  66. BIN
      public/img/ros-hmci/328f39c65f2fad357fd239d70f9853d3.png
  67. BIN
      public/img/ros-hmci/32f93a9ac08c57dfb50d38eef5828a13.png
  68. BIN
      public/img/ros-hmci/36d96691d2b74c84ca57e270907a9596.png
  69. BIN
      public/img/ros-hmci/372a8bfa767dfa44c42afe1be7a3341b.png
  70. BIN
      public/img/ros-hmci/375deb080d12485d7c5b020a91cac3f5.png
  71. BIN
      public/img/ros-hmci/38b556121ea08c3a34ebd7947ff818ef.png
  72. BIN
      public/img/ros-hmci/39ea174f887d877ea76ba31228a6315d.png
  73. BIN
      public/img/ros-hmci/3a6453ce7a73331de8dc8d46ac792980.png
  74. BIN
      public/img/ros-hmci/3bbd57a73399bf2077275457666e5e37.png
  75. BIN
      public/img/ros-hmci/3cc371058d1857c44ab96a2ddd28159b.png
  76. BIN
      public/img/ros-hmci/3d0cdf6c59b3734bdcaa492f430697ae.png
  77. BIN
      public/img/ros-hmci/3e56d7dc07ba43c2fc3777593c616ba9.png
  78. BIN
      public/img/ros-hmci/41526c6a56ab35fbfd75efe611e6a269.png
  79. BIN
      public/img/ros-hmci/43e3b14c6e2a924e143faab617e1b449.png
  80. BIN
      public/img/ros-hmci/449b407d5174de110f663f1b72471720.png
  81. BIN
      public/img/ros-hmci/45351da17710517dfb616133de40bc17.png
  82. BIN
      public/img/ros-hmci/4949f8f2b7bae0d43a4aa67699c10335.png
  83. BIN
      public/img/ros-hmci/4b4c4662629e074227c63d23f46271ac.png
  84. BIN
      public/img/ros-hmci/4dcdce6ea20fc6126991a3a9ce999064.png
  85. BIN
      public/img/ros-hmci/5520ba673bc80210912d830a304adddd.png
  86. BIN
      public/img/ros-hmci/556e5bde0bcecb4a5313962a5cf935fe.png
  87. BIN
      public/img/ros-hmci/55e24ed247765c26ba9ebdc7178aa587.png
  88. BIN
      public/img/ros-hmci/573ef7ee84a6b4884195d6d20d48d192.png
  89. BIN
      public/img/ros-hmci/58287c3a4b1f6c90d86a18c1ce3fe9a0.png
  90. BIN
      public/img/ros-hmci/58c00cc05cb3a7614393125e1a0bd7ba.png
  91. BIN
      public/img/ros-hmci/5b08f8e6adcee3691cc86af6a880afb6.png
  92. BIN
      public/img/ros-hmci/5fda1de7e984f5c1ec553662ab771407.png
  93. BIN
      public/img/ros-hmci/624b71c49ce138ae6ce2dff0de4f81cc.png
  94. BIN
      public/img/ros-hmci/62b53dd597736adecf97d25b2889c5e2.png
  95. BIN
      public/img/ros-hmci/649898031748a5867af33a892716a817.png
  96. BIN
      public/img/ros-hmci/64a805a2c15419c356ca28f95ee943b6.png
  97. BIN
      public/img/ros-hmci/64feeeb56b3e341ea6bb89649896adf6.png
  98. BIN
      public/img/ros-hmci/66fa35144bcca1d59efbd809308d8978.png
  99. BIN
      public/img/ros-hmci/68acd342613a54742d5e94bb85df2128.png
  100. BIN
      public/img/ros-hmci/6ae4d710aaf64c9fb32198a417e7deda.png

+ 5
- 1
.gitignore View File

@@ -85,6 +85,7 @@ coverage.all
/public/img/svg
/VERSION


# Snapcraft
snap/.snapcraft/
parts/
@@ -99,4 +100,7 @@ prime/
/.make_evidence

/templates/home_bak.tmpl
/==bak
/==bak

#ROS-hmci-frontend-link
web_src/vuepages/pages/ros-hmci/views/links.js

+ 0
- 688
index.html View File

@@ -1,688 +0,0 @@
<!DOCTYPE html>
<html lang="en-US">
<head data-suburl="">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title> OpenI</title>
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
console.info('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
console.info('ServiceWorker registration failed: ', err);
});
}
</script>
<meta name="theme-color" content="#6cc644">
<meta name="author" content="OpenI - open i project management" />
<meta name="description" content="Efficient code management center, you can host and review code" />
<meta name="keywords" content="OpenI,git">
<meta name="referrer" content="no-referrer" />
<meta name="_csrf" content="R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ" />

<script>
/*
@licstart The following is the entire license notice for the
JavaScript code in this page.

Copyright (c) 2016 The Gitea Authors
Copyright (c) 2015 The Gogs Authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
Licensing information for additional javascript libraries can be found at:
{{StaticUrlPrefix}}/vendor/librejs.html

@licend The above is the entire license notice
for the JavaScript code in this page.
*/
</script>
<script>
window.config = {
AppSubUrl: '',
StaticUrlPrefix: '',
csrf: 'R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ',
HighlightJS: false,
Minicolors: false,
SimpleMDE: false,
Tribute: false,
U2F: false,
Heatmap: false,
heatmapUser: null,
NotificationSettings: {
MinTimeout: 10000 ,
TimeoutStep: 10000 ,
MaxTimeout: 60000 ,
EventSourceUpdateTime: 10000 ,
},
};
</script>
<link rel="shortcut icon" href="/img/favicon.png">
<link rel="mask-icon" href="/img/openi-safari.svg" color="#609926">
<link rel="fluid-icon" href="/img/gitea-lg.png" title="OpenI">
<link rel="stylesheet" href="/vendor/assets/font-awesome/css/font-awesome.min.css">
<link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous">
<link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="/css/git.openi.css">



<link rel="stylesheet" href="/fomantic/semantic.min.css?v=eef985e4d4b587d055fc7c3eff3f18e9">
<link rel="stylesheet" href="/css/index.css?v=eef985e4d4b587d055fc7c3eff3f18e9">
<noscript>
<style>
.dropdown:hover > .menu { display: block; }
.ui.secondary.menu .dropdown.item > .menu { margin-top: 0; }
</style>
</noscript>

<style class="list-search-style"></style>

<meta property="og:title" content="OpenI">
<meta property="og:type" content="website" />
<meta property="og:image" content="/img/gitea-lg.png" />
<meta property="og:url" content="https://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" />



<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="/self/func.js" type="text/javascript"></script>

<link rel="stylesheet" href="/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css">

<link rel="stylesheet" href="/swiper/swiper-bundle.min.css">
<script src="/swiper/swiper-bundle.min.js"></script>

<link rel="stylesheet" href="/rotation3D/rotation3D.css">
</head>
<body>

<div class="full height">
<noscript>This website works better with JavaScript.</noscript>


<div class="ui top secondary stackable main menu following bar dark">
<div class="ui container" id="navbar">
<div class="item brand" style="justify-content: space-between;">
<a href="https://openi.org.cn/">
<img class="ui mini image" src="/img/logo-w.svg">
</a>
<div class="ui basic icon button mobile-only" id="navbar-expand-toggle">
<i class="sidebar icon"></i>
</div>
</div>
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div>
<div class="item brand" style="margin-left: 0.9rem;">
<a href="/">
<img class="ui mini image" style="height: 1.3rem;" src="/img/git-logo.svg">
</a>
</div>


<div class="item edge">
<div class="dropdown-menu">
<a class=" item lfpd" href="/user/login">
Home <i class="dropdown icon mglf"></i>
</a>
<div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;">
<a style="border: none;color: #000;" class=" item" href="/user/login">Issues</a>
<a style="border: none;color: #000; white-space: nowrap;" class=" item" href="/user/login">Pull Requests</a>
<a style="border: none;color: #000;" class=" item" href="/user/login">Milestones</a>
<a style="border: none;color: #000;" class=" item" href="/cloudbrains">Cloudbrain Task</a>
</div>
</div>
</div>

<a class="item" href="/explore/repos">Repositories</a>
<a class="item" href="/explore/datasets">Datasets</a>
<div class="ui simple dropdown item" id='dropdown_PageHome'>
Explore
<i class="dropdown icon"></i>
<div class="menu" >
<a class="item" href="/explore/users">Users</a>
<a class="item" href="/explore/organizations">Organizations</a>
<a class="item" href="/explore/images">Cloudbrain Mirror</a>
<a class="item" href="/OpenI">OpenI Projects</a>
</div>
</div>




<div class="right stackable menu">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="" placeholder="Search..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="">
<input type="hidden" name="sort" value="hot">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button>
</div>
</form>
<a class="item" href="/user/sign_up">
<svg class="svg octicon-person" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-person" /></svg> Register
</a>
<a class="item" rel="nofollow" href="/user/login">
<svg class="svg octicon-sign-in" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-sign-in" /></svg> Sign In
</a>
</div>


</div>


</div>
<div class="notic_content" id ="notic_content" style="display: block; position: relative">
<div class="ui container">
<marquee behavior="scroll" direction="left">
<a href=https://openi.org.cn/html/2022/notices_0701/636.html class="a_width" style = 'margin-left: 0px !important;' target="_blank">
<i class="ri-arrow-right-s-line"></i>
“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认&gt;&gt;&gt;
</a>
<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>
<a href=https://openi.org.cn/html/2022/dongtai_0628/634.html class="a_width" target="_blank">
<i class="ri-arrow-right-s-line"></i>
智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~&gt;&gt;&gt;
</a>
<a href=https://wj.qq.com/s2/10362208/5c0c class="a_width" target="_blank">
<i class="ri-arrow-right-s-line"></i>
启智AI协作平台问卷调查,邀请您参加&gt;&gt;&gt;
</a>
</marquee>
<div class="item right" style="position:absolute;right: 1px;top:0px;">
<i class="ri-close-fill x_icon" onclick="closeNoice()"></i>
</div>
</div>
</div>



<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notices")

if (current_notice != "f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de"){
localStorage.setItem('notices',"f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
let isShowNoticeTag = false;
let notices= [{"Title":"“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/notices_0701/636.html","Visible":1},{"Title":"7月中下旬登录启智AI协作平台,需登记手机号码啦\u003e\u003e\u003e","Link":"https://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){
isShowNoticeTag =true;
break;
}
}
}
if (isShowNoticeTag){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
if (document.getElementById("notic_content") != null){
document.getElementById("notic_content").style.display='none'
}
}
}
if(!("" == true || "" =='true')) {
isShowNotice();
}
</script>
<div class="ui vertical masthead secondary hometop segment">
<div class="ui container" style="position: relative;">
<div class="ui center homebanner">
<h1 class="ui huge header">
Explore Better AI
<div class="sub header">
OpenI AI Development Cooperation Platform
</div>
</h1>
<p class="ui am-lh-18">The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation</p>
<a class="circular huge ui secondary button" href="/user/login">Use Now <i class="right arrow icon"></i></a>
</div>
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
<div id="homenews">
<p>* Only show the dynamics of open source projects</p>
<div class="ui grid">
<div class="sixteen wide mobile twelve wide tablet ten wide computer column homenews">
<div class="newslist">
<div class="ui mini aligned list swiper-wrapper" id="newmessage">
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<div class="ui container homeorg">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column homeorg-tit">
<h2>Recommended Organizations</h2>
<p><span class="ui text grey">These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here,&nbsp;</span><a href="/OpenIOSSG/promote/">Click here to submit.</a></p>
<a href="/explore/organizations" class="circular ui primary basic button">More Organizations <i class="arrow circle right icon"></i></a>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="homeorg-list">
<div class="swiper-wrapper" id="recommendorg">
</div>
<div class="swiper-pagination"></div>
</div>
</div>

<div class="sixteen wide tablet four wide computer column homeorg-tit">
<h2>Community Activities</h2>
<p><span class="ui text grey">The community has prepared a wealth of activities, waiting for you to participate!</p>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="event-list">
<div class="swiper-wrapper" id="recommendactivity">
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</div>
<div class="leftline01"></div>
</div>
<div class="ui container homepro">
<div class="leftline02"></div>
<div class="leftline02-2"></div>
<div class="ui center homepro-tit am-mb-20">
<h2>Recommended Projects</h2>
<p><span class="ui text grey">Excellent AI projects recommendation. To show your project here,&nbsp;</span><a href="/OpenIOSSG/promote/">Click here to submit.</a>Click here to&nbsp;<a href="/explore/">explore more projects.</a></p>
</div>

<div class="homepro-list">
<div class="swiper-wrapper" id="recommendrepo">
</div>
<div class="swiper-pagination"></div>
</div>
</div>

<div class="ui vertical masthead secondary c2net segment">
<div class="ui container">
<div class="ui center am-pt-30 am-pb-30">
<h2>智算网络</h2>
<p><span class="ui text grey">人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P</p>
</div>

<div id="app" v-cloak>
<div class="rotation3D-baseMap"></div>
<div id="rotation3D" class="rotation3D">
<button class="center">中心</button>
<div class="itemList">
<div class="rotation3D__item" :class="item.type" v-for="item in itemList">
<div class="scale">
<div class="baseImg"></div>
<div class="cont">
<i class="iconfont" :class="item.icon"></i>
<p></p>
</div>
</div>
</div>
</div>
<div class="lineList">
<div class="rotation3D__line" v-for="item in itemList" :class="item.type">
<div v-if="item.type=='blue'" class="pos">
<svg width="50" height="400">
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/>
</svg>
<div class="dot dot1 ri-arrow-left-s-line"><span></span></div>
</div>
<div v-if="item.type=='yellow'" class="pos">
<svg width="10" height="400">
<path id="path2" d="M0 400, 0 0" stroke-dasharray="5,10"/>
</svg>
<div class="dot dot2"><i class="el-icon-close"></i></div>
</div>
<div v-if="item.type=='green'" class="pos">
<svg width="50" height="400">
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/>
</svg>
<div class="dot dot1 ri-arrow-left-s-line"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<a name="fourth"></a>
<div class="ui container i-env">
<div class="ui center am-pb-30">
<h2>Collaborative Development Environment</h2>
<p><span class="ui text grey">Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms.</p>
</div>
<div class="ui four doubling cards">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">Unified Management of Development Elements</h3>
<div class="description ui text grey">
The platform provides four elements of AI development: unified management of model code, data set, model and execution environment.
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-02.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">Data Collaboration and Sharing</h3>
<div class="description ui text grey">
By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset.
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-03.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">Model Management and Sharing</h3>
<div class="description ui text grey">
Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback.
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.jpg">
</div>
<div class="content">
<h3 class="ui centered small header">Once Configuration, Multiple Reuse</h3>
<div class="description ui text grey">
Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments.
</div>
</div>
</div>
</div>
</div>

<a name="fifth"></a>
<div class="ui container">
<div class="ui very padded inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<h2 class="ui grey inverted header">PengCheng Cloudbrain Open Source Collaboration</h2>
<p class="am-lh-18 ui text grey">
The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks.<br>
Pengcheng Cloudbrain&#39;s existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors.<br>
Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments.<br>
If your model requires more computing resources, you can also apply for it separately.<br>
</p>
<a class="ui blue basic button am-mt-20" href="/user/login">Use Now</a>
<a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">Apply Separately</a>
</div>
</div>
</div>
</div>
<div class="am-mt-30"></div>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>
<script src="/home/home.js?v=eef985e4d4b587d055fc7c3eff3f18e9" type="text/javascript"></script>





</div>


<footer>
<div class="ui container">
<div class="ui grid">
<div class="sixteen wide mobile eight wide tablet eight wide computer column">
<div class="ui three column grid">
<div class="column ui vertical text menu">
<div class="header item">Community</div>
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Council</a>
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Technical Committee</a>
<a href="https://openi.org.cn/html/Club/2019/0228/17.html" class="item">Join OpenI</a>
<a href="/home/term/" class="item">Use agreement</a>
</div>
<div class="column ui vertical text menu">
<div class="header item">News</div>
<a href="https://openi.org.cn/html/news/dongtai/" class="item">Community News</a>
<a href="https://openi.org.cn/html/news/huodong/" class="item">Member news</a>
<a href="https://openi.org.cn/html/news/zixun/" class="item">Industry Advisory</a>
</div>
<div class="column ui vertical text menu">
<div class="header item">help</div>
<div class="ui language bottom floating slide up dropdown link item">
<i class="world icon"></i>
<div class="text">English</div>
<div class="menu">
<a lang="en-US" class="item active selected" href="#">English</a>
<a lang="zh-CN" class="item " href="?lang=zh-CN">简体中文</a>
</div>
</div>

<a href="https://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>

</div>
</div>
</div>
<div class="sixteen wide mobile eight wide tablet eight wide computer column" style=" margin:2.0rem 0">
Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI) <a href="http://beian.miit.gov.cn/" target="_blank">京ICP备18004880号</a>
<br>
Powered_by 鹏城实验室云脑、<a href="https://www.trustie.net/" target="_blank">Trustie确实</a>、gitea
<br>
</div>
</div>
</div>
</footer>


<script src="/js/jquery.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script>










<script rel="stylesheet" src="/vendor/plugins/jquery.particleground/jquery.particleground.min.js"></script>

<script src="/fomantic/semantic.min.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script>
<script src="/js/index.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script>


<script src="/rotation3D/vue-2.6.10.min.js"></script>
<script src="/rotation3D/rotation3D.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script>
<script>
var app = new Vue({
el: "#app",
data: {
itemList: [
{ name:'鹏城云脑一号', type:'blue', icon:'', },
{ name:'鹏城云脑二号', type:'blue', icon:'', },
{ name:'北大人工智能集群系统', type:'green', icon:'', },
{ name:'合肥类脑智能开放平台', type:'green', icon:'', },
{ name:'武汉人工智能计算中心', type:'green', icon:'', },
{ name:'西安未来人工智能计算中心', type:'green', icon:'', },
{ name:'……', type:'yellow', icon:'', },
{ name:'中原人工智能计算中心', type:'green', icon:'', },
{ name:'成都人工智能计算中心', type:'green', icon:'', },
{ name:'横琴先进智能计算中心', type:'green', icon:'', },
{ name:'国家超级计算济南中心', type:'green', icon:'', },
],
},
mounted: function () {
new Rotation3D({
id: '#rotation3D',
farScale: 0.6,
xRadius: 0,
yRadius: 130,
})
},
methods: {},
});
</script>


</body>
</html>


+ 265
- 42
models/ai_model_manage.go View File

@@ -6,6 +6,7 @@ import (

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
"xorm.io/xorm"
@@ -25,6 +26,7 @@ type AiModelManage struct {
Path string `xorm:"varchar(400) NOT NULL" json:"path"`
DownloadCount int `xorm:"NOT NULL DEFAULT 0" json:"downloadCount"`
Engine int64 `xorm:"NOT NULL DEFAULT 0" json:"engine"`
ComputeResource string `json:"computeResource"`
Status int `xorm:"NOT NULL DEFAULT 0" json:"status"`
StatusDesc string `xorm:"varchar(500)" json:"statusDesc"`
Accuracy string `xorm:"varchar(1000)" json:"accuracy"`
@@ -32,16 +34,42 @@ type AiModelManage struct {
RepoId int64 `xorm:"INDEX NULL" json:"repoId"`
CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"`
CodeCommitID string `xorm:"NULL" json:"codeCommitID"`
Recommend int `xorm:"NOT NULL DEFAULT 0" json:"recommend"`
UserId int64 `xorm:"NOT NULL" json:"userId"`
IsPrivate bool `xorm:"DEFAULT true" json:"isPrivate"`
UserName string `json:"userName"`
UserRelAvatarLink string `json:"userRelAvatarLink"`
UserName string `xorm:"-" json:"userName"`
UserRelAvatarLink string `xorm:"-" json:"userRelAvatarLink"`
TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"`
CreatedUnix timeutil.TimeStamp `xorm:"created" json:"createdUnix"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"`
IsCanOper bool `json:"isCanOper"`
IsCanDelete bool `json:"isCanDelete"`
IsCanDownload bool `json:"isCanDownload"`
IsCanOper bool `xorm:"-" json:"isCanOper"`
IsCanDelete bool `xorm:"-" json:"isCanDelete"`
IsCanDownload bool `xorm:"-" json:"isCanDownload"`
IsCollected bool `xorm:"-" json:"isCollected"`
RepoName string `xorm:"-" json:"repoName"`
RepoDisplayName string `xorm:"-" json:"repoDisplayName"`
RepoOwnerName string `xorm:"-" json:"repoOwnerName"`
ReferenceCount int `xorm:"NOT NULL DEFAULT 0" json:"referenceCount"`
CollectedCount int `xorm:"NOT NULL DEFAULT 0" json:"collectedCount"`
ModelFileList []storage.FileInfo `xorm:"-" json:"modelFileList"`
}

type AiModelFile struct {
ID int64 `xorm:"pk autoincr"`
ModelID string `xorm:"UNIQUE(s)"`
Name string `xorm:"varchar(400) UNIQUE(s)"`
Path string `xorm:"varchar(400) NULL"`
Description string `xorm:"varchar(400) NULL"`
DownloadCount int64 `xorm:"DEFAULT 0"`
Size int64 `xorm:"DEFAULT 0"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}

type AiModelCollect struct {
ID int64 `xorm:"pk autoincr"`
ModelID string `xorm:"UNIQUE(s)"`
UserId int64 `xorm:"UNIQUE(s)"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}

type AiModelConvert struct {
@@ -72,10 +100,10 @@ type AiModelConvert struct {
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"`
StartTime timeutil.TimeStamp `json:"startTime"`
EndTime timeutil.TimeStamp `json:"endTime"`
UserName string `json:"userName"`
UserRelAvatarLink string `json:"userRelAvatarLink"`
IsCanOper bool `json:"isCanOper"`
IsCanDelete bool `json:"isCanDelete"`
UserName string `xorm:"-" json:"userName"`
UserRelAvatarLink string `xorm:"-" json:"userRelAvatarLink"`
IsCanOper bool `xorm:"-" json:"isCanOper"`
IsCanDelete bool `xorm:"-" json:"isCanDelete"`
}

type AiModelQueryOptions struct {
@@ -86,10 +114,18 @@ type AiModelQueryOptions struct {
SortType string
New int
// JobStatus CloudbrainStatus
Type int
Status int
IsOnlyThisRepo bool
IsQueryPrivate bool
Type int
Status int
IsOnlyThisRepo bool
IsQueryPrivate bool
IsRecommend bool
IsCollected bool
CollectedUserId int64
Namelike string
LabelFilter string
FrameFilter int
ComputeResourceFilter string
NotNeedEmpty bool
}

func (a *AiModelConvert) IsGpuTrainTask() bool {
@@ -310,6 +346,34 @@ func ModifyModelPrivate(id string, isPrivate bool) error {
return nil
}

func ModifyModelRecommend(id string, recommend int) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("recommend").Update(&AiModelManage{
Recommend: recommend,
})
if err != nil {
return err
}
log.Info("success to update recommend from db.re=" + fmt.Sprint((re)))
return nil
}

func ModifyModelCollectedNum(id string, collectedNum int) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("collected_count").Update(&AiModelManage{
CollectedCount: collectedNum,
})
if err != nil {
return err
}
log.Info("success to update collectedNum 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)
@@ -394,6 +458,29 @@ func QueryModelByName(name string, repoId int64) []*AiModelManage {
return aiModelManageList
}

func QueryModelByRepoId(repoId int64) []*AiModelManage {
sess := x.NewSession()
defer sess.Close()
sess.Select("*").Table("ai_model_manage").
Where("repo_id=?", repoId)
aiModelManageList := make([]*AiModelManage, 0)
sess.Find(&aiModelManageList)
return aiModelManageList
}

func DeleteModelByRepoId(repoId int64) error {
sess := x.NewSession()
defer sess.Close()
re, err := sess.Delete(&AiModelManage{
RepoId: repoId,
})
if err != nil {
return err
}
log.Info("success to delete DeleteModelByRepoId from db.re=" + fmt.Sprint((re)))
return nil
}

func QueryModelByPath(path string) (*AiModelManage, error) {
modelManage := new(AiModelManage)
has, err := x.Where("path=?", path).Get(modelManage)
@@ -409,51 +496,74 @@ func QueryModelByPath(path string) (*AiModelManage, error) {
func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
var where string
where += " ai_model_manage.user_id > 0 "
if opts.RepoID > 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.repo_id": opts.RepoID},
)
where += " and ai_model_manage.repo_id= " + fmt.Sprint(opts.RepoID)
}

if opts.UserID > 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.user_id": opts.UserID},
)
where += " and ai_model_manage.user_id=" + fmt.Sprint(opts.UserID)
}

if opts.New >= 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.new": opts.New},
)
where += " and ai_model_manage.new=" + fmt.Sprint(opts.New)
}

if len(opts.ModelID) > 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.id": opts.ModelID},
)
where += " and ai_model_manage.id='" + fmt.Sprint(opts.ModelID) + "'"
}

if (opts.Type) >= 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.type": opts.Type},
)
where += " and ai_model_manage.type=" + fmt.Sprint(opts.Type)
}

if (opts.Status) >= 0 {
cond = cond.And(
builder.Eq{"ai_model_manage.status": opts.Status},
)
where += " and ai_model_manage.status=" + fmt.Sprint(opts.Status)
}
if !opts.IsQueryPrivate {
cond = cond.And(
builder.Eq{"ai_model_manage.is_private": false},
)
where += " and 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)
if opts.IsRecommend {
where += " and ai_model_manage.recommend=1"
}
if opts.FrameFilter >= 0 {
if opts.FrameFilter == 2 {
where += " and ai_model_manage.engine in (2,121,122)"
} else {
where += " and ai_model_manage.engine=" + fmt.Sprint(opts.FrameFilter)
}
}
if opts.LabelFilter != "" {
where += " and ai_model_manage.label ILIKE '%" + opts.LabelFilter + "%'"
}
if opts.ComputeResourceFilter != "" {
where += " and ai_model_manage.compute_resource ILIKE '%" + opts.ComputeResourceFilter + "%'"
}
if opts.Namelike != "" {
where += " and ( ai_model_manage.name ILIKE '%" + opts.Namelike + "%'"
where += " or ai_model_manage.description ILIKE '%" + opts.Namelike + "%'"
where += " or ai_model_manage.label ILIKE '%" + opts.Namelike + "%')"
}
if opts.NotNeedEmpty {
where += " and ai_model_manage.size > 0 "
}
var count int64
var err error
if opts.IsCollected {
where += " and ai_model_collect.user_id=" + fmt.Sprint(opts.CollectedUserId)

count, err = sess.Join("INNER", "ai_model_collect", "ai_model_manage.id = ai_model_collect.model_id").Where(where).Count(new(AiModelManage))
if err != nil {
log.Info("error=" + err.Error())
return nil, 0, fmt.Errorf("Count: %v", err)
}
} else {
count, err = sess.Where(where).Count(new(AiModelManage))
if err != nil {
log.Info("error=" + err.Error())
return nil, 0, fmt.Errorf("Count: %v", err)
}
}

if opts.Page >= 0 && opts.PageSize > 0 {
@@ -465,11 +575,18 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) {
}
sess.Limit(opts.PageSize, start)
}

sess.OrderBy("ai_model_manage.created_unix DESC")
if opts.IsCollected {
sess.Join("INNER", "ai_model_collect", "ai_model_manage.id = ai_model_collect.model_id")
}
orderby := "ai_model_manage.created_unix desc"
if opts.SortType != "" {
orderby = opts.SortType
}
sess.OrderBy(orderby)
aiModelManages := make([]*AiModelManage, 0, setting.UI.IssuePagingNum)
if err := sess.Table("ai_model_manage").Where(cond).
if err := sess.Table("ai_model_manage").Where(where).
Find(&aiModelManages); err != nil {
log.Info("error=" + err.Error())
return nil, 0, fmt.Errorf("Find: %v", err)
}

@@ -551,3 +668,109 @@ func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelConvert, int64, err

return aiModelManageConvert, count, nil
}

func SaveModelCollect(modelCollect *AiModelCollect) error {
sess := x.NewSession()
defer sess.Close()
re, err := sess.Insert(modelCollect)
if err != nil {
log.Info("insert AiModelCollect error." + err.Error())
return err
}
log.Info("success to save AiModelCollect db.re=" + fmt.Sprint((re)))
return nil
}

func DeleteModelCollect(modelCollect *AiModelCollect) error {
sess := x.NewSession()
defer sess.Close()
re, err := sess.Delete(modelCollect)
if err != nil {
log.Info("delete AiModelCollect error." + err.Error())
return err
}
log.Info("success to delete AiModelCollect db.re=" + fmt.Sprint((re)))
return nil
}

func QueryModelCollectNum(modelId string) int {
sess := x.NewSession()
defer sess.Close()
modelCollects := make([]*AiModelCollect, 0)
err := sess.Table(new(AiModelCollect)).Where("model_id=?", modelId).Find(&modelCollects)
if err == nil {
return len(modelCollects)
}
return 0
}
func QueryModelCollectByUserId(modelId string, userId int64) []*AiModelCollect {
sess := x.NewSession()
defer sess.Close()
modelCollects := make([]*AiModelCollect, 0)
err := sess.Table(new(AiModelCollect)).Where("model_id=? and user_id=?", modelId, userId).Find(&modelCollects)
if err == nil {
return modelCollects
}
return nil
}

func QueryModelCollectedStatus(modelIds []string, userId int64) map[string]*AiModelCollect {
sess := x.NewSession()
defer sess.Close()
modelCollects := make([]*AiModelCollect, 0)
var cond = builder.NewCond()
cond = cond.And(
builder.In("model_id", modelIds),
)
cond = cond.And(
builder.Eq{"user_id": userId},
)
result := make(map[string]*AiModelCollect, 0)
err := sess.Table(new(AiModelCollect)).Where(cond).Find(&modelCollects)
if err == nil {
for _, v := range modelCollects {
result[v.ModelID] = v
}
}
return result
}

func SaveModelFile(modelFile *AiModelFile) error {
sess := x.NewSession()
defer sess.Close()
re, err := sess.Insert(modelFile)
if err != nil {
log.Info("insert modelFile error." + err.Error())
return err
}
log.Info("success to save modelFile db.re=" + fmt.Sprint((re)))
return nil
}

func DeleteModelFile(modelFile *AiModelFile) error {
sess := x.NewSession()
defer sess.Close()
re, err := sess.Delete(modelFile)
if err != nil {
log.Info("delete modelFile error." + err.Error())
return err
}
log.Info("success to delete modelFile db.re=" + fmt.Sprint((re)))
return nil
}

func QueryModelFileByModelId(modelId string) []*AiModelFile {
sess := x.NewSession()
defer sess.Close()
modelFileList := make([]*AiModelFile, 0)
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"model_id": modelId},
)
result := make([]*AiModelFile, 0)
err := sess.Table(new(AiModelFile)).Where(cond).Find(&modelFileList)
if err != nil {
log.Info("query AiModelFile failed, err=" + err.Error())
}
return result
}

+ 27
- 3
models/cloudbrain.go View File

@@ -205,6 +205,9 @@ type Cloudbrain struct {
ModelName string //模型名称
ModelVersion string //模型版本
CkptName string //权重文件名称
ModelId string //模型ID
ModelRepoName string `xorm:"-"`
ModelRepoOwnerName string `xorm:"-"`
PreTrainModelUrl string //预训练模型地址
ResultUrl string //推理结果的obs路径
ResultJson string `xorm:"varchar(4000)"`
@@ -2071,12 +2074,22 @@ func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) {
}
}
session.Commit()
increaseModelReference(session, cloudbrain.ModelId)
go IncreaseDatasetUseCount(cloudbrain.Uuid)
go OperateRepoAITaskNum(cloudbrain.RepoID, 1)
//go IncreaseModelRefernceCount(cloudbrain)
return nil
}

func increaseModelReference(session *xorm.Session, modelId string) {
if modelId != "" {
log.Info("increase model count.")
if _, err := session.Exec("UPDATE `ai_model_manage` SET reference_count = reference_count + 1 WHERE id = ?", modelId); err != nil {
log.Info("err=" + err.Error())
}
}
}

func getRepoCloudBrain(cb *Cloudbrain) (*Cloudbrain, error) {
has, err := x.Get(cb)
if err != nil {
@@ -2490,7 +2503,7 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
if err = sess.Commit(); err != nil {
return err
}
increaseModelReference(sess, new.ModelId)
go IncreaseDatasetUseCount(new.Uuid)
return nil
}
@@ -2628,7 +2641,6 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
Join("left", "`user`", condition).
Join("left", "cloudbrain_spec", "cloudbrain.id = cloudbrain_spec.cloudbrain_id").
Count(new(CloudbrainInfo))

}

if err != nil {
@@ -2982,3 +2994,15 @@ func LoadSpecs4CloudbrainInfo(tasks []*CloudbrainInfo) error {
}
return nil
}

func GetCloudBrainByModelId(modelId string) ([]*Cloudbrain, error) {
cloudBrains := make([]*Cloudbrain, 0)
err := x.AllCols().Where("model_id=?", modelId).OrderBy("created_unix asc").Find(&cloudBrains)
return cloudBrains, err
}

func GetCloudBrainByRepoIdAndModelName(repoId int64, modelName string) ([]*Cloudbrain, error) {
cloudBrains := make([]*Cloudbrain, 0)
err := x.AllCols().Where("model_name=? and repo_id=?", modelName, repoId).OrderBy("created_unix asc").Find(&cloudBrains)
return cloudBrains, err
}

+ 2
- 0
models/models.go View File

@@ -170,6 +170,8 @@ func init() {
new(TechConvergeBaseInfo),
new(RepoConvergeInfo),
new(UserRole),
new(AiModelCollect),
new(AiModelFile),
new(ModelMigrateRecord),
)



+ 22
- 1
models/repo.go View File

@@ -1706,7 +1706,9 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
if err != nil {
return err
}

_, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&AiModelManage{
IsPrivate: true,
})
} else {
//If repo has become public, we need set dataset to public
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{
@@ -1870,6 +1872,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {

// Delete dataset attachment record and remove related files
deleteDatasetAttachmentByRepoId(sess, repoID)

deleteModelByRepoId(repoID)

if err = deleteBeans(sess,
&Access{RepoID: repo.ID},
&Action{RepoID: repo.ID},
@@ -2055,6 +2060,22 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
return nil
}

func deleteModelByRepoId(repoId int64) {
models := QueryModelByRepoId(repoId)
if models != nil {
for _, model := range models {
log.Info("bucket=" + setting.Bucket + " path=" + model.Path)
if len(model.Path) > (len(setting.Bucket) + 1) {
err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:])
if err != nil {
log.Info("Failed to delete model. id=" + model.ID)
}
}
}
}
DeleteModelByRepoId(repoId)
}

func deleteDatasetAttachmentByRepoId(sess *xorm.Session, repoId int64) error {
attachments := make([]*Attachment, 0)
if err := sess.Join("INNER", "dataset", "dataset.id = attachment.dataset_id").


+ 16
- 0
models/repo_list.go View File

@@ -181,6 +181,10 @@ type SearchRepoOptions struct {
TopicOnly bool
//search by Specific TopicName
TopicName string
//Multi topic names.available just when topicName is empty
MultiTopicNames []string
//available just when MultiTopicNames is not empty,true for intersect,false for union
IsTopicIntersect bool
// include description in keyword search
IncludeDescription bool
// None -> include has milestones AND has no milestone
@@ -407,6 +411,18 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
var topicNameCond = builder.In("id", subQuery)
cond = cond.And(topicNameCond)

} else if opts.MultiTopicNames != nil && len(opts.MultiTopicNames) > 0 {
var subQueryCond = builder.NewCond()
subQueryCond = subQueryCond.And(builder.In("topic.name", opts.MultiTopicNames))
subQuery := builder.Select("repo_topic.repo_id").From("repo_topic").
Join("INNER", "topic", "topic.id = repo_topic.topic_id").
Where(subQueryCond).
GroupBy("repo_topic.repo_id")
if opts.IsTopicIntersect {
subQuery = subQuery.Having(fmt.Sprintf("count(repo_topic.repo_id) >= %d", len(opts.MultiTopicNames)))
}
var topicNameCond = builder.In("id", subQuery)
cond = cond.And(topicNameCond)
}

if opts.Fork != util.OptionalBoolNone {


+ 3
- 1
modules/auth/cloudbrain.go View File

@@ -26,6 +26,7 @@ type CreateCloudBrainForm struct {
ModelName string `form:"model_name"`
ModelVersion string `form:"model_version"`
CkptName string `form:"ckpt_name"`
ModelId string `form:"model_id"`
LabelName string `form:"label_names"`
PreTrainModelUrl string `form:"pre_train_model_url"`
DatasetName string `form:"dataset_name"`
@@ -68,7 +69,7 @@ type CreateCloudBrainInferencForm struct {
JobType string `form:"job_type" binding:"Required"`
BenchmarkCategory string `form:"get_benchmark_category"`
GpuType string `form:"gpu_type"`
TrainUrl string `form:"train_url"`
PreTrainModelUrl string `form:"pre_train_model_url"`
TestUrl string `form:"test_url"`
Description string `form:"description"`
ResourceSpecId int `form:"resource_spec_id" binding:"Required"`
@@ -79,6 +80,7 @@ type CreateCloudBrainInferencForm struct {
ModelVersion string `form:"model_version" binding:"Required"`
CkptName string `form:"ckpt_name" binding:"Required"`
LabelName string `form:"label_names" binding:"Required"`
ModelId string `form:"model_id" binding:"Required"`
DatasetName string `form:"dataset_name"`
SpecId int64 `form:"spec_id"`
}


+ 2
- 0
modules/auth/grampus.go View File

@@ -21,6 +21,7 @@ type CreateGrampusTrainJobForm struct {
ModelName string `form:"model_name"`
ModelVersion string `form:"model_version"`
CkptName string `form:"ckpt_name"`
ModelId string `form:"model_id"`
LabelName string `form:"label_names"`
PreTrainModelUrl string `form:"pre_train_model_url"`
SpecId int64 `form:"spec_id"`
@@ -44,6 +45,7 @@ type CreateGrampusNotebookForm struct {
ModelName string `form:"model_name"`
ModelVersion string `form:"model_version"`
CkptName string `form:"ckpt_name"`
ModelId string `form:"model_id"`
LabelName string `form:"label_names"`
PreTrainModelUrl string `form:"pre_train_model_url"`
SpecId int64 `form:"spec_id" binding:"Required"`


+ 4
- 1
modules/auth/modelarts.go View File

@@ -25,6 +25,7 @@ type CreateModelArtsNotebookForm struct {
ModelName string `form:"model_name"`
ModelVersion string `form:"model_version"`
CkptName string `form:"ckpt_name"`
ModelId string `form:"model_id"`
LabelName string `form:"label_names"`
PreTrainModelUrl string `form:"pre_train_model_url"`
SpecId int64 `form:"spec_id" binding:"Required"`
@@ -56,6 +57,7 @@ type CreateModelArtsTrainJobForm struct {
EngineName string `form:"engine_names" binding:"Required"`
SpecId int64 `form:"spec_id" binding:"Required"`
ModelName string `form:"model_name"`
ModelId string `form:"model_id"`
ModelVersion string `form:"model_version"`
CkptName string `form:"ckpt_name"`
LabelName string `form:"label_names"`
@@ -79,10 +81,11 @@ type CreateModelArtsInferenceJobForm struct {
FlavorName string `form:"flaver_names" binding:"Required"`
EngineName string `form:"engine_names" binding:"Required"`
LabelName string `form:"label_names" binding:"Required"`
TrainUrl string `form:"train_url" binding:"Required"`
PreTrainModelUrl string `form:"pre_train_model_url" binding:"Required"`
ModelName string `form:"model_name" binding:"Required"`
ModelVersion string `form:"model_version" binding:"Required"`
CkptName string `form:"ckpt_name" binding:"Required"`
ModelId string `form:"model_id"`
SpecId int64 `form:"spec_id" binding:"Required"`
}



+ 11
- 12
modules/cloudbrain/cloudbrain.go View File

@@ -79,6 +79,7 @@ type GenerateCloudBrainTaskReq struct {
ModelName string
ModelVersion string
CkptName string
ModelId string
LabelName string
PreTrainModelPath string
PreTrainModelUrl string
@@ -358,6 +359,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) (string, error) {
ModelName: req.ModelName,
ModelVersion: req.ModelVersion,
CkptName: req.CkptName,
ModelId: req.ModelId,
ResultUrl: req.ResultPath,
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
@@ -475,18 +477,13 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
}

if task.PreTrainModelUrl != "" { //预训练
_, err := models.QueryModelByPath(task.PreTrainModelUrl)
if err != nil {
log.Warn("The model may be deleted", err)
} else {
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
Path: setting.Attachment.Minio.RealPath + task.PreTrainModelUrl,
MountPath: PretrainModelMountPath,
ReadOnly: true,
},
})
}
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
Path: setting.Attachment.Minio.RealPath + task.PreTrainModelUrl,
MountPath: PretrainModelMountPath,
ReadOnly: true,
},
})
}

createTime := timeutil.TimeStampNow()
@@ -549,6 +546,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
LabelName: task.LabelName,
PreTrainModelUrl: task.PreTrainModelUrl,
CkptName: task.CkptName,
ModelId: task.ModelId,
}

err = models.RestartCloudbrain(task, newTask)
@@ -698,6 +696,7 @@ type GenerateModelArtsNotebookReq struct {
ModelName string
LabelName string
CkptName string
ModelId string
ModelVersion string
PreTrainModelUrl string
}

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

@@ -31,10 +31,10 @@ func ToCloudBrain(task *models.Cloudbrain) *api.Cloudbrain {
VersionName: task.VersionName,
ModelVersion: task.ModelVersion,
CkptName: task.CkptName,
StartTime: int64(task.StartTime),
EndTime: int64(task.EndTime),
Spec: ToSpecification(task.Spec),
ModelId: task.ModelId,
StartTime: int64(task.StartTime),
EndTime: int64(task.EndTime),
Spec: ToSpecification(task.Spec),
}
}
func ToAttachment(attachment *models.Attachment) *api.AttachmentShow {


+ 19
- 10
modules/grampus/grampus.go View File

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

import (
"encoding/json"
"fmt"
"strconv"
"strings"
@@ -78,6 +79,7 @@ type GenerateTrainJobReq struct {
ModelName string
LabelName string
CkptName string
ModelId string
ModelVersion string
PreTrainModelPath string
PreTrainModelUrl string
@@ -103,6 +105,7 @@ type GenerateNotebookJobReq struct {
ModelName string
LabelName string
CkptName string
ModelId string
ModelVersion string
PreTrainModelPath string
PreTrainModelUrl string
@@ -227,7 +230,7 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job
EndPoint: getEndPoint(),
ReadOnly: true,
ObjectKey: req.PreTrainModelPath,
ContainerPath: cloudbrain.PretrainModelMountPath,
ContainerPath: cloudbrain.PretrainModelMountPath + "/" + req.CkptName,
})
}

@@ -248,7 +251,8 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job
log.Info("debug command:" + req.Command)

}

datasetGrampusJson, _ := json.Marshal(datasetGrampus)
log.Info("datasetGrampusJson=" + string(datasetGrampusJson))
jobResult, err := createNotebookJob(models.CreateGrampusNotebookRequest{
Name: req.JobName,
Tasks: []models.GrampusNotebookTask{
@@ -299,6 +303,7 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
})

if err != nil {
@@ -355,13 +360,13 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
} else if ProcessorTypeGPU == req.ProcessType {
datasetGrampus = getDatasetGPUGrampus(req.DatasetInfos, "/tmp/dataset")
if len(req.ModelName) != 0 {
modelGrampus = []models.GrampusDataset{
modelGrampus = []models.GrampusDataset{ //model save as obs
{
Name: req.ModelName,
Bucket: setting.Attachment.Minio.Bucket,
EndPoint: setting.Attachment.Minio.Endpoint,
ObjectKey: req.PreTrainModelPath,
Bucket: setting.Bucket,
EndPoint: getEndPoint(),
ReadOnly: true,
ObjectKey: req.PreTrainModelPath,
ContainerPath: "/tmp/pretrainmodel/" + req.CkptName,
},
}
@@ -382,13 +387,13 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
} else if ProcessorTypeGCU == req.ProcessType {
datasetGrampus = getDatasetGCUGrampus(req.DatasetInfos, "/tmp/dataset")
if len(req.ModelName) != 0 {
modelGrampus = []models.GrampusDataset{
modelGrampus = []models.GrampusDataset{ //model save as obs
{
Name: req.ModelName,
Bucket: setting.Attachment.Minio.Bucket,
EndPoint: setting.Attachment.Minio.Endpoint,
ObjectKey: req.PreTrainModelPath,
Bucket: setting.Bucket,
EndPoint: getEndPoint(),
ReadOnly: true,
ObjectKey: req.PreTrainModelPath,
ContainerPath: "/tmp/pretrainmodel/" + req.CkptName,
},
}
@@ -407,6 +412,9 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
}
}

modelGrampusJson, _ := json.Marshal(modelGrampus)
log.Info("train job modelGrampus=" + string(modelGrampusJson))

jobResult, err := createJob(models.CreateGrampusJobRequest{
Name: req.JobName,
Tasks: []models.GrampusTasks{
@@ -465,6 +473,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
})

if err != nil {


+ 45
- 4
modules/markup/markdown/goldmark.go View File

@@ -41,10 +41,11 @@ type ASTTransformer struct{}
func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
metaData := meta.GetItems(pc)
firstChild := node.FirstChild()
createTOC := false

createTOC := setting.Markdown.EnableToc
var toc = []Header{}
rc := &RenderConfig{
Meta: "table",
Meta: "",
Icon: "table",
Lang: "",
}
@@ -154,6 +155,25 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
}
return ast.WalkContinue, nil
})
if node.HasChildren() {
children := make([]ast.Node, 0, node.ChildCount())
child := node.FirstChild()
for child != nil {
children = append(children, child)
child = child.NextSibling()
}
node.RemoveChildren(node)
contentNode := ast.NewDocument()
contentNode.SetAttributeString("class", []byte("markdown-content"))
for _, child := range children {

contentNode.AppendChild(contentNode, child)

}

node.AppendChild(node, contentNode)

}

if createTOC && len(toc) > 0 {
lang := rc.Lang
@@ -161,6 +181,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
lang = setting.Langs[0]
}
tocNode := createTOCNode(toc, lang)
firstChild = node.FirstChild()
if tocNode != nil {
node.InsertBefore(node, firstChild, tocNode)
}
@@ -248,7 +269,27 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Document)

if val, has := n.AttributeString("lang"); has {
var err error
if entering {
_, err = w.WriteString("<div")
if err == nil {
if n.Attributes() != nil {
html.RenderAttributes(w, n, html.GlobalAttributeFilter)
}

}
if err == nil {
_, err = w.WriteRune('>')
}
} else {
_, err = w.WriteString("</div>")
}

if err != nil {
return ast.WalkStop, err
}

/**if val, has := n.AttributeString("lang"); has {
var err error
if entering {
_, err = w.WriteString("<div")
@@ -265,7 +306,7 @@ func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.
if err != nil {
return ast.WalkStop, err
}
}
}*/

return ast.WalkContinue, nil
}


+ 28
- 10
modules/markup/markdown/toc.go View File

@@ -8,18 +8,24 @@ import (
"fmt"
"net/url"

"github.com/unknwon/i18n"
"github.com/yuin/goldmark/ast"
)

func createTOCNode(toc []Header, lang string) ast.Node {
details := NewDetails()
summary := NewSummary()

summary.AppendChild(summary, ast.NewString([]byte(i18n.Tr(lang, "toc"))))
details.AppendChild(details, summary)
sidebar := ast.NewDocument()
sidebar.SetAttributeString("class", []byte("markdown_catalog"))
scrollContainer := ast.NewDocument()
scrollContainer.SetAttributeString("class", []byte("scroll-container"))
toggleContainer := ast.NewDocument()
toggleContainer.SetAttributeString("class", []byte("toggle-container"))
toggleIcon := ast.NewDocument()
toggleIcon.SetAttributeString("class", []byte("icon ri-arrow-drop-left-line"))
container := ast.NewDocument()
container.SetAttributeString("class", []byte("container"))
ul := ast.NewList('-')
details.AppendChild(details, ul)
ul.SetAttributeString("class", []byte("markdown_toc"))
topul:=ul

currentLevel := 6
for _, header := range toc {
if header.Level < currentLevel {
@@ -28,22 +34,34 @@ func createTOCNode(toc []Header, lang string) ast.Node {
}
for _, header := range toc {
for currentLevel > header.Level {
ul = ul.Parent().(*ast.List)
ul = ul.Parent().Parent().(*ast.List)
currentLevel--
}
for currentLevel < header.Level {
newLi := ast.NewListItem(currentLevel * 2)
newLi.SetAttributeString("class", []byte("no-catalog-li"))
newL := ast.NewList('-')
ul.AppendChild(ul, newL)
newL.SetAttributeString("class", []byte("markdown_toc"))
newLi.AppendChild(newLi, newL)
ul.AppendChild(ul, newLi)
currentLevel++
ul = newL
}
li := ast.NewListItem(currentLevel * 2)
li.SetAttributeString("class", []byte("catalog-li"))
a := ast.NewLink()
a.Destination = []byte(fmt.Sprintf("#%s", url.PathEscape(header.ID)))
a.AppendChild(a, ast.NewString([]byte(header.Text)))
a.SetAttributeString("title", []byte(header.Text))
li.AppendChild(li, a)
ul.AppendChild(ul, li)
}
container.AppendChild(container,topul)
scrollContainer.AppendChild(scrollContainer,container)
toggleContainer.AppendChild(toggleContainer,toggleIcon)
sidebar.AppendChild(sidebar, toggleContainer)
sidebar.AppendChild(sidebar, scrollContainer)

return details
//return details
return sidebar
}

+ 1
- 1
modules/markup/sanitizer.go View File

@@ -69,7 +69,7 @@ func ReplaceSanitizer() {
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(ui checkbox)|(ui checked checkbox)|(emoji))$`)).OnElements("span")

// Allow generally safe attributes
generalSafeAttrs := []string{"abbr", "accept", "accept-charset",
generalSafeAttrs := []string{"abbr", "accept", "accept-charset", "class",
"accesskey", "action", "align", "alt",
"aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
"axis", "border", "cellpadding", "cellspacing", "char",


+ 6
- 0
modules/modelarts/modelarts.go View File

@@ -91,6 +91,7 @@ type GenerateTrainJobReq struct {
ModelName string
LabelName string
CkptName string
ModelId string
ModelVersion string
PreTrainModelUrl string
}
@@ -122,6 +123,7 @@ type GenerateInferenceJobReq struct {
ModelName string
ModelVersion string
CkptName string
ModelId string
ResultUrl string
Spec *models.Specification
DatasetName string
@@ -244,6 +246,7 @@ func GenerateNotebook2(ctx *context.Context, req cloudbrain.GenerateModelArtsNot
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
}

err = models.CreateCloudbrain(task)
@@ -366,6 +369,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
})

if createErr != nil {
@@ -526,6 +530,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
})
if createErr != nil {
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error())
@@ -706,6 +711,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (j
ModelName: req.ModelName,
ModelVersion: req.ModelVersion,
CkptName: req.CkptName,
ModelId: req.ModelId,
ResultUrl: req.ResultUrl,
CreatedUnix: createTime,
UpdatedUnix: createTime,


+ 30
- 7
modules/modelarts/resty.go View File

@@ -39,7 +39,9 @@ const (
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"

ModelArtsJobNotExists = "ModelArts.0102"
ModelArtsJobInTargetState = "ModelArts.6357"
ModelArtsJobNotExists = "ModelArts.0102"
ModelArtsJobInternalError = "ModelArts.0010"
)

func getRestyClient() *resty.Client {
@@ -395,8 +397,12 @@ sendjob:
_ = getToken()
goto sendjob
}
if response.ErrorCode == ModelArtsJobNotExists {
//任务不存在,此时认为删除成功
if response.ErrorCode == ModelArtsJobNotExists || response.ErrorCode == ModelArtsJobInTargetState {
//任务不存在或者已经处于被删除的状态,此时认为删除成功
return &models.NotebookDelResult{}, nil
}
if result.ErrorCode == ModelArtsJobInternalError {
log.Error("ModelArt internal error when del job,jobId=%s", jobID)
return &models.NotebookDelResult{}, nil
}
return &result, fmt.Errorf("DelNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg)
@@ -1052,8 +1058,12 @@ sendjob:
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("DelTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if temp.ErrorCode == ModelArtsJobNotExists {
//任务不存在,此时认为删除成功
if temp.ErrorCode == ModelArtsJobNotExists || temp.ErrorCode == ModelArtsJobInTargetState {
//任务不存在或者已经处于被删除的状态,此时认为删除成功
return &models.TrainJobResult{IsSuccess: true}, nil
}
if result.ErrorCode == ModelArtsJobInternalError {
log.Error("ModelArt internal error when del job,jobId=%s", jobID)
return &models.TrainJobResult{IsSuccess: true}, nil
}
return &result, fmt.Errorf("删除训练作业失败(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
@@ -1061,8 +1071,12 @@ sendjob:

if !result.IsSuccess {
log.Error("DelTrainJob(%s) failed", jobID)
if result.ErrorCode == ModelArtsJobNotExists {
//任务不存在,此时认为删除成功
if result.ErrorCode == ModelArtsJobNotExists || result.ErrorCode == ModelArtsJobInTargetState {
//任务不存在或者已经处于被删除的状态,此时认为删除成功
return &models.TrainJobResult{IsSuccess: true}, nil
}
if result.ErrorCode == ModelArtsJobInternalError {
log.Error("ModelArt internal error when del job,jobId=%s", jobID)
return &models.TrainJobResult{IsSuccess: true}, nil
}
return &result, fmt.Errorf("删除训练作业失败:%s", result.ErrorMsg)
@@ -1141,6 +1155,15 @@ sendjob:
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}

if temp.ErrorCode == ModelArtsJobNotExists || temp.ErrorCode == ModelArtsJobInTargetState {
//任务不存在或者已经处于被删除的状态,此时认为删除成功
return &models.TrainJobResult{IsSuccess: true}, nil
}
if result.ErrorCode == ModelArtsJobInternalError {
log.Error("ModelArt internal error when del job,jobId=%s", jobID)
return &models.TrainJobResult{IsSuccess: true}, nil
}
log.Error("DelTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("删除训练作业版本失败(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}


+ 1
- 0
modules/modelarts_cd/modelarts.go View File

@@ -154,6 +154,7 @@ func GenerateNotebook(ctx *context.Context, req cloudbrain.GenerateModelArtsNote
LabelName: req.LabelName,
PreTrainModelUrl: req.PreTrainModelUrl,
CkptName: req.CkptName,
ModelId: req.ModelId,
}

err = models.CreateCloudbrain(task)


+ 15
- 8
modules/modelarts_cd/resty.go View File

@@ -29,12 +29,14 @@ const (
urlNotebook2 = "/notebooks"

//error code
modelartsIllegalToken = "ModelArts.6401"
NotebookNotFound = "ModelArts.6404"
NotebookNoPermission = "ModelArts.6407"
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"
ModelArtsJobNotExists = "ModelArts.0102"
modelartsIllegalToken = "ModelArts.6401"
NotebookNotFound = "ModelArts.6404"
NotebookNoPermission = "ModelArts.6407"
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"
ModelArtsJobNotExists = "ModelArts.0102"
ModelArtsJobInTargetState = "ModelArts.6357"
ModelArtsJobInternalError = "ModelArts.0010"
)

func getHttpClient() *http.Client {
@@ -168,8 +170,13 @@ func DelNotebook(jobID string) (*models.NotebookDelResult, error) {

if len(result.ErrorCode) != 0 {
log.Error("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
if result.ErrorCode == ModelArtsJobNotExists {
//任务不存在,此时认为删除成功
if result.ErrorCode == ModelArtsJobNotExists || result.ErrorCode == ModelArtsJobInTargetState {
//任务不存在或者已经处于被删除的状态,此时认为删除成功
return &models.NotebookDelResult{}, nil
}

if result.ErrorCode == ModelArtsJobInternalError {
log.Error("ModelArt internal error when del job,jobId=%s", jobID)
return &models.NotebookDelResult{}, nil
}
return &result, fmt.Errorf("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)


+ 8
- 4
modules/setting/setting.go View File

@@ -114,6 +114,7 @@ var (
AppName string
MLOPS bool
MlopsHost string
MlopsToken string
AppURL string
AppSubURL string
AppSubURLDepth int // Number of slashes
@@ -311,9 +312,11 @@ var (
EnableHardLineBreak bool
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
FileExtensions []string
EnableToc bool
}{
EnableHardLineBreak: true,
FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","),
EnableToc: true,
}

// Admin settings
@@ -1080,7 +1083,8 @@ func NewContext() {
AppSubURLDepth = strings.Count(AppSubURL, "/")

MLOPS = Cfg.Section("").Key("MLOPS").MustBool(false)
MlopsHost = Cfg.Section("").Key("MLOPS_HOST").MustString(AppSubURL)
MlopsHost = Cfg.Section("").Key("MLOPS_HOST").MustString("")
MlopsToken = Cfg.Section("").Key("MLOPS_TOKEN").MustString("")
// Check if Domain differs from AppURL domain than update it to AppURL's domain
// TODO: Can be replaced with url.Hostname() when minimal GoLang version is 1.8
urlHostname := strings.SplitN(appURL.Host, ":", 2)[0]
@@ -1753,7 +1757,7 @@ func getModelConvertConfig() {
ModelConvert.GPU_PYTORCH_IMAGE = sec.Key("GPU_PYTORCH_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap")
ModelConvert.GpuQueue = sec.Key("GpuQueue").MustString("openidgx")
ModelConvert.GPU_TENSORFLOW_IMAGE = sec.Key("GPU_TENSORFLOW_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx")
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend")
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.8.1_train_openi_new:v1")
ModelConvert.PytorchOnnxBootFile = sec.Key("PytorchOnnxBootFile").MustString("convert_pytorch.py")
ModelConvert.PytorchTrTBootFile = sec.Key("PytorchTrTBootFile").MustString("convert_pytorch_tensorrt.py")
ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py")
@@ -1763,8 +1767,8 @@ func getModelConvertConfig() {
ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1)
ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1")
ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a")
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(121)
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35)
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(37)
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(38)
ModelConvert.GPU_PADDLE_IMAGE = sec.Key("GPU_PADDLE_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:paddle2.3.0_gpu_cuda11.2_cudnn8")
ModelConvert.GPU_MXNET_IMAGE = sec.Key("GPU_MXNET_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:mxnet191cu_cuda102_py37")
ModelConvert.PaddleOnnxBootFile = sec.Key("PaddleOnnxBootFile").MustString("convert_paddle.py")


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

@@ -89,6 +89,10 @@ func (l *LocalStorage) UploadObject(fileName, filePath string) error {
return nil
}

func (l *LocalStorage) UploadContent(bucketName string, path string, r io.Reader) (int64, error) {
return int64(0), nil
}

func (l *LocalStorage) DeleteDir(dir string) error {
return nil
}

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

@@ -163,6 +163,10 @@ func (m *MinioStorage) UploadObject(fileName, filePath string) error {
return err
}

func (m *MinioStorage) UploadContent(bucketName string, path string, r io.Reader) (int64, error) {
return m.client.PutObject(bucketName, path, r, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"})
}

func GetMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

+ 33
- 1
modules/storage/obs.go View File

@@ -371,11 +371,13 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative
for {
output, err := ObsCli.ListObjects(input)
if err == nil {
log.Info("Page:%d\n", index)
log.Info("Page:%d\n input.Prefix=v%", index, input.Prefix)
log.Info("input.Prefix=" + input.Prefix)
index++
for _, val := range output.Contents {
var isDir bool
var fileName string
log.Info("val.key=" + val.Key)
if val.Key == input.Prefix {
continue
}
@@ -707,3 +709,33 @@ func IsObjectExist4Obs(bucket, key string) (bool, error) {
}
return true, nil
}

func PutStringToObs(bucket, key string, fileContent string) error {
log.Info("PutStringToObs bucket=" + bucket + " key=" + key)
input := &obs.PutObjectInput{}
input.Bucket = bucket
input.Key = key
input.Body = strings.NewReader(fileContent)
_, err := ObsCli.PutObject(input)
if err != nil {
if obsError, ok := err.(obs.ObsError); ok {
log.Info("Message:%s\n", obsError.Message)
}
}
return err
}

func PutReaderToObs(bucket, key string, reader io.Reader) error {
log.Info("PutStringToObs bucket=" + bucket + " key=" + key)
input := &obs.PutObjectInput{}
input.Bucket = bucket
input.Key = key
input.Body = reader
_, err := ObsCli.PutObject(input)
if err != nil {
if obsError, ok := err.(obs.ObsError); ok {
log.Info("Message:%s\n", obsError.Message)
}
}
return err
}

+ 4
- 2
modules/storage/storage.go View File

@@ -5,12 +5,13 @@
package storage

import (
"fmt"
"io"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/obs"
"code.gitea.io/gitea/modules/setting"
"fmt"
"github.com/minio/minio-go"
"io"
)

const (
@@ -29,6 +30,7 @@ type ObjectStorage interface {
PresignedPutURL(path string) (string, error)
HasObject(path string) (bool, error)
UploadObject(fileName, filePath string) error
UploadContent(bucketName string, path string, r io.Reader) (int64, error)
}

// Copy copys a file from source ObjectStorage to dest ObjectStorage


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

@@ -16,6 +16,7 @@ type CreateGrampusTrainJobOption struct {
ModelName string `json:"model_name"`
ModelVersion string `json:"model_version"`
CkptName string `json:"ckpt_name"`
ModelId string `json:"model_id"`
LabelName string `json:"label_names"`
PreTrainModelUrl string `json:"pre_train_model_url"`
SpecId int64 `json:"spec_id" binding:"Required"`
@@ -36,6 +37,7 @@ type CreateTrainJobOption struct {
ModelName string `json:"model_name"`
ModelVersion string `json:"model_version"`
CkptName string `json:"ckpt_name"`
ModelId string `json:"model_id"`
LabelName string `json:"label_names"`
PreTrainModelUrl string `json:"pre_train_model_url"`
SpecId int64 `json:"spec_id" binding:"Required"`
@@ -52,6 +54,7 @@ type CreateNotebookOption struct {
ModelName string `json:"model_name"`
ModelVersion string `json:"model_version"`
CkptName string `json:"ckpt_name"`
ModelId string `json:"model_id"`
LabelName string `json:"label_names"`
PreTrainModelUrl string `json:"pre_train_model_url"`
SpecId int64 `json:"spec_id" binding:"Required"`
@@ -91,6 +94,7 @@ type Cloudbrain struct {
ModelName string `json:"model_name"` //模型名称
ModelVersion string `json:"model_version"` //模型版本
CkptName string `json:"ckpt_name"` //权重文件名称
ModelId string `json:"model_id"` //权重文件名称
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
VersionName string `json:"version_name"`


+ 1
- 1
modules/templates/helper.go View File

@@ -794,7 +794,7 @@ func licenses() []string {

// Dataset tasks
func tasks() []string {
return []string{"machine_translation", "question_answering_system", "information_retrieval", "knowledge_graph", "text_annotation", "text_categorization", "emotion_analysis", "language_modeling", "speech_recognition", "automatic_digest", "information_extraction", "description_generation", "image_classification", "face_recognition", "image_search", "target_detection", "image_description_generation", "vehicle_license_plate_recognition", "medical_image_analysis", "unmanned", "unmanned_security", "drone", "vr_ar", "2_d_vision", "2.5_d_vision", "3_d_reconstruction", "image_processing", "video_processing", "visual_input_system", "speech_coding", "speech_enhancement", "speech_synthesis"}
return []string{"machine_translation", "question_answering_system", "information_retrieval", "knowledge_graph", "text_annotation", "text_categorization", "emotion_analysis", "language_modeling", "speech_recognition", "automatic_digest", "information_extraction", "description_generation", "image_classification", "face_recognition", "image_search", "target_detection", "image_description_generation", "vehicle_license_plate_recognition", "medical_image_analysis", "unmanned", "unmanned_security", "drone", "vr_ar", "2_d_vision", "2.5_d_vision", "3_d_reconstruction", "image_processing", "video_processing", "visual_input_system", "speech_coding", "speech_enhancement", "speech_synthesis","ROS_hmci"}
}

func GetRefType(ref string) string {


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

@@ -932,6 +932,7 @@ task.speech_coding= speech coding
task.speech_enhancement= speech enhancement
task.speech_recognition= speech recognition
task.speech_synthesis= speech synthesis
task.ROS_hmci=ROS-hmci Community
category.computer_vision= computer vision
category.natural_language_processing= natural language processing
category.speech_processing= speech processing
@@ -1059,6 +1060,7 @@ cloudbrain.time.starttime=Start run time
cloudbrain.time.endtime=End run time
cloudbrain.datasetdownload=Dataset download url
model_manager = Model
model_square = Model Square
model_experience = Model Experience
model_noright=You have no right to do the operation.
model_rename=Duplicate model name, please modify model name.
@@ -1263,6 +1265,7 @@ modelarts.infer_job.boot_file_helper=The startup file is the entry file for your
modelarts.infer_job.continue_helper=Check Reuse to copy the output result file of the last training task
modelarts.train_job.resource_helper=The "resource specification" is the hardware you use to run the task. In order for more people to use the resources of this platform, please select according to your actual needs
modelarts.infer_job.tooltip = The model has been deleted and cannot be viewed.
modelarts.infer_job.model_cant_see = You are currently unable to view the model, possibly due to permission restrictions or the model has been deleted.
modelarts.download_log=Download log file
modelarts.log_file = Log file
modelarts.fullscreen_log_file = View in full screen
@@ -1325,7 +1328,7 @@ model.manage.engine=Model engine
model.manage.select.engine=Select model engine
model.manage.modelfile=Model file
model.manage.modellabel=Model label
model.manage.modeldesc=Model description
model.manage.modeldesc=Model brief introduction
model.manage.modelaccess=Model Access
model.manage.modelaccess.public=Public
model.manage.modelaccess.private=Private
@@ -1369,6 +1372,7 @@ modelconvert.manage.model_file_not_exist=The model file in the task does not exi
modelconvert.manage.no_operate_right=You have no right to do the operation.

debug.manage.model_not_exist=The model in the task does not exist or has been deleted, please create a new debug job.
train.manage.model_not_exist=The model in the task does not exist or has been deleted, please create a new train job.
debug.manage.dataset_not_exist=The part of datasets in the task does not exist or has been deleted, please create a new debug job.

grampus.train_job.ai_center = AI Center
@@ -2139,7 +2143,7 @@ settings.wiki_deletion_success = The repository wiki data has been deleted.
settings.delete = Delete This Repository
settings.delete_desc = Deleting a repository is permanent and cannot be undone.
settings.delete_notices_1 = - This operation <strong>CANNOT</strong> be undone.
settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository including code, issues, comments, wiki data and collaborator settings.
settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository including the code, dataset, model, cloudbrain tasks, tasks, merge requests, and other contents.
settings.delete_notices_fork_1 = - Forks of this repository will become independent after deletion.
settings.deletion_success = The repository has been deleted.
settings.update_settings_success = The repository settings have been updated.
@@ -2619,6 +2623,7 @@ dashboard = Dashboard
users = User Accounts
organizations = Organizations
datasets= Dataset
models=Model
repositories = Repositories
hooks = Default Webhooks
systemhooks = System Webhooks
@@ -3161,7 +3166,7 @@ task_c2ent_gcutrainjob=`created GCU type train task <a href="%s/modelarts/train-
task_nputrainjob=`created NPU training task <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>`
task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>`
task_createmodel=`created new model <a href="%s/modelmanage/model_readme_tmpl?name=%s">%s</a>`
task_gputrainjob=`created CPU/GPU training task <a href="%s/cloudbrain/train-job/%s">%s</a>`
task_c2netnputrainjob=`created NPU training task <a href="%s/grampus/train-job/%s">%s</a>`
task_c2netgputrainjob=`created CPU/GPU training task <a href="%s/grampus/train-job/%s">%s</a>`


+ 8
- 3
options/locale/locale_zh-CN.ini View File

@@ -937,6 +937,7 @@ task.speech_coding=语音编码
task.speech_enhancement=语音增强
task.speech_recognition=语音识别
task.speech_synthesis=语音合成
task.ROS_hmci=开源开放社区
category.computer_vision=计算机视觉
category.natural_language_processing=自然语言处理
category.speech_processing=语音处理
@@ -1058,6 +1059,7 @@ datasets.desc=数据集功能
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等

model_manager = 模型
model_square = 模型广场
model_experience = 模型体验
model_noright=您没有操作权限。
model_rename=模型名称重复,请修改模型名称
@@ -1275,6 +1277,7 @@ modelarts.infer_job.boot_file_helper=启动文件是您程序执行的入口文
modelarts.infer_job.continue_helper=勾选复用将拷贝上次训练任务输出结果文件
modelarts.train_job.resource_helper=「资源规格」是您运行该任务使用的硬件,为了更多人能够使用本平台的资源,请按照您的实际需求进行选择。
modelarts.infer_job.tooltip = 该模型已删除,无法查看。
modelarts.infer_job.model_cant_see = 您暂时无法查看该模型,可能因为权限限制或模型已被删除。
modelarts.download_log=下载日志文件
modelarts.log_file=日志文件
modelarts.fullscreen_log_file=全屏查看
@@ -1338,7 +1341,7 @@ model.manage.engine=模型框架
model.manage.select.engine=选择模型框架
model.manage.modelfile=模型文件
model.manage.modellabel=模型标签
model.manage.modeldesc=模型描述
model.manage.modeldesc=模型简介
model.manage.modelaccess=模型权限
model.manage.modelaccess.public=公开
model.manage.modelaccess.private=私有
@@ -1383,6 +1386,7 @@ modelconvert.manage.no_operate_right=您没有操作权限。


debug.manage.model_not_exist=任务中选择的模型不存在或者已被删除,请新建调试任务。
train.manage.model_not_exist=任务中选择的模型不存在或者已被删除,请新建训练任务。
debug.manage.dataset_not_exist=任务中选择的部分数据集不存在或者已被删除,请新建调试任务。

grampus.train_job.ai_center=智算中心
@@ -2155,7 +2159,7 @@ settings.wiki_deletion_success=项目百科数据删除成功!
settings.delete=删除本项目
settings.delete_desc=删除项目是永久性的, 无法撤消。
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滚。
settings.delete_notices_2=- 此操作将永久删除项目 <strong>%s</strong>,包括 Git 数据、 任务、评论、百科和协作者的操作权限
settings.delete_notices_2=- 此操作将永久删除项目 <strong>%s</strong>,包括该项目中的代码、数据集、模型、云脑任务、任务、合并请求等内容
settings.delete_notices_fork_1=- 在此项目删除后,它的派生项目将变成独立项目。
settings.deletion_success=项目已被删除。
settings.deletion_notice_cloudbrain=请先停止项目内正在运行的云脑任务,然后再删除项目。
@@ -2638,6 +2642,7 @@ dashboard=管理面板
users=帐户管理
organizations=组织管理
datasets=数据集
models=模型
repositories=项目管理
hooks=默认Web钩子
systemhooks=系统 Web 钩子
@@ -3179,7 +3184,7 @@ task_c2ent_gcutrainjob=`创建了GCU类型训练任务 <a href="%s/grampus/train
task_nputrainjob=`创建了NPU类型训练任务 <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`创建了推理任务 <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`创建了评测任务 <a href="%s/cloudbrain/benchmark/%s">%s</a>`
task_createmodel=`导入了新模型 <a href="%s/modelmanage/show_model_info?name=%s">%s</a>`
task_createmodel=`导入了新模型 <a href="%s/modelmanage/model_readme_tmpl?name=%s">%s</a>`
task_gputrainjob=`创建了CPU/GPU类型训练任务 <a href="%s/cloudbrain/train-job/%s">%s</a>`
task_c2netnputrainjob=`创建了NPU类型训练任务 <a href="%s/grampus/train-job/%s">%s</a>`
task_c2netgputrainjob=`创建了CPU/GPU类型训练任务 <a href="%s/grampus/train-job/%s">%s</a>`


+ 89
- 0
package-lock.json View File

@@ -37,6 +37,7 @@
"jquery.are-you-sure": "1.9.0",
"js-cookie": "3.0.1",
"less-loader": "6.1.0",
"markdown-it": "13.0.1",
"mini-css-extract-plugin": "0.9.0",
"monaco-editor": "0.20.0",
"monaco-editor-webpack-plugin": "1.9.0",
@@ -10975,6 +10976,14 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
"node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@@ -11450,6 +11459,34 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/markdown-it/node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"engines": {
"node": ">=0.12"
}
},
"node_modules/markdown-table": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
@@ -11661,6 +11698,11 @@
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA=="
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -18795,6 +18837,11 @@
"node": "*"
}
},
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
@@ -29624,6 +29671,14 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
"linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@@ -30044,6 +30099,30 @@
"integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
"dev": true
},
"markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"requires": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
}
}
},
"markdown-table": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
@@ -30215,6 +30294,11 @@
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA=="
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -35978,6 +36062,11 @@
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz",
"integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ=="
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",


+ 1
- 0
package.json View File

@@ -36,6 +36,7 @@
"jquery.are-you-sure": "1.9.0",
"js-cookie": "3.0.1",
"less-loader": "6.1.0",
"markdown-it": "13.0.1",
"mini-css-extract-plugin": "0.9.0",
"monaco-editor": "0.20.0",
"monaco-editor-webpack-plugin": "1.9.0",


+ 3
- 3
public/home/home.js View File

@@ -244,7 +244,7 @@ document.onreadystatechange = function () {
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepotext(record) + "</a>"
}
else if(record.OpType == "24" || record.OpType == "26" || record.OpType == "27" || record.OpType == "28" || record.OpType == "30"
|| record.OpType == "31" || record.OpType == "32" || record.OpType == "33"){
|| record.OpType == "31" || record.OpType == "32" || record.OpType == "33" || record.OpType == "42"){
html += recordPrefix + actionName;
html += " <a href=\"" + getTaskLink(record) + "\" rel=\"nofollow\">" + record.RefName + "</a>"
}
@@ -290,10 +290,10 @@ function getTaskLink(record){
}else if(record.OpType == 29){
re = re + "/cloudbrain/benchmark/" + record.Content;
}else if(record.OpType == 30){
re = re + "/modelmanage/show_model_info?name=" + record.RefName;
re = re + "/modelmanage/model_readme_tmpl?name=" + record.RefName;
}else if(record.OpType == 31){
re = re + "/cloudbrain/train-job/" + record.Content;
}else if(record.OpType == 32 || record.OpType == 33){
}else if(record.OpType == 32 || record.OpType == 33 || record.OpType == 42){
re = re + "/grampus/train-job/" + record.Content;
}else if(record.OpType == 39 || record.OpType == 40 || record.OpType == 41){
re = re + "/grampus/notebook/" + record.Content;


+ 57
- 0
public/img/empty-box.svg View File

@@ -0,0 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg"
class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 fPsHiw svg-icon-path-icon" viewBox="0 0 430 298"
width="100" height="100" fill="none">
<defs data-reactroot=""></defs>
<g>
<path id="矩形 3" d="M391 124L430 124L392 62L391 62L391 124Z" fill-rule="evenodd"
fill="url(#paint_linear_3_11_0)"></path>
<path id="矩形 1" d="M54 62L235 62L235 298L78 298C64.7452 298 54 287.255 54 274L54 62Z" fill-rule="evenodd"
fill="url(#paint_linear_3_4_0)"></path>
<path id="矩形 1" d="M392 62L235 62L235 298L368 298C381.255 298 392 287.255 392 274L392 62Z"
fill-rule="evenodd" fill="url(#paint_linear_3_5_0)"></path>
<rect id="矩形 2" x="282.000000" y="143.000000" rx="10.000000" width="62.000000" height="20.000000"
fill="#AAAFBF"></rect>
<path id="矩形 3" d="M273 0L430 0L392 62L235 62L273 0Z" fill-rule="evenodd" fill="url(#paint_linear_3_7_0)">
</path>
<path id="矩形 3" d="M153 0L16 0L54 62L191 62L153 0Z" fill-rule="nonzero" fill="url(#paint_linear_3_8_0)">
</path>
<path id="矩形 3" d="M195 124L16 124L54 62L233 62L195 124Z" fill-rule="evenodd"
fill="url(#paint_linear_3_10_0)"></path>
<path id="减去顶层"
d="M54.5 217C24.4005 217 0 241.4 0 271.5C0 271.667 0.000747681 271.833 0.00224304 272L108.998 272C108.999 271.833 109 271.667 109 271.5C109 241.4 84.5995 217 54.5 217Z"
clip-rule="evenodd" fill-rule="evenodd" fill="#4D9AFF" fill-opacity="0.500000"></path>
<defs>
<linearGradient id="paint_linear_3_11_0" x1="430.000000" y1="124.000000" x2="430.000000" y2="62.000000"
gradientUnits="userSpaceOnUse">
<stop stop-color="#E2E3E7"></stop>
<stop offset="1.000000" stop-color="#AAAFBF"></stop>
</linearGradient>
<linearGradient id="paint_linear_3_4_0" x1="54.000084" y1="62.000008" x2="235.000000" y2="298.000000"
gradientUnits="userSpaceOnUse">
<stop stop-color="#DEE0E7"></stop>
<stop offset="1.000000" stop-color="#EBECF1"></stop>
</linearGradient>
<linearGradient id="paint_linear_3_5_0" x1="0.000092" y1="-0.000008" x2="157.000000" y2="236.000015"
gradientUnits="userSpaceOnUse">
<stop stop-color="#D8DAE2"></stop>
<stop offset="1.000000" stop-color="#D1D1DC"></stop>
</linearGradient>
<linearGradient id="paint_linear_3_7_0" x1="429.999969" y1="0.000000" x2="235.000000" y2="62.000061"
gradientUnits="userSpaceOnUse">
<stop stop-color="#D9DBE6"></stop>
<stop offset="0.992366" stop-color="#CACCD8"></stop>
</linearGradient>
<linearGradient id="paint_linear_3_8_0" x1="15.999954" y1="0.000000" x2="15.999954" y2="62.000000"
gradientUnits="userSpaceOnUse">
<stop stop-color="#EFEFF4"></stop>
<stop offset="0.992366" stop-color="#EAEBF0"></stop>
</linearGradient>
<linearGradient id="paint_linear_3_10_0" x1="16.000000" y1="124.000000" x2="16.000000" y2="62.000000"
gradientUnits="userSpaceOnUse">
<stop stop-color="#F5F4F7"></stop>
<stop offset="0.809160" stop-color="#E7E9EE"></stop>
<stop offset="1.000000" stop-color="#F2F2F5"></stop>
</linearGradient>
</defs>
</g>
</svg>

+ 1
- 0
public/img/holder.svg View File

@@ -0,0 +1 @@
<svg height="56" viewBox="0 0 12 56" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m3.86950483 4.06524758 8.13049517-4.06524758v56l-8.13049517-4.0652476c-2.3714882-1.1857441-3.86950483-3.6095859-3.86950483-6.2609903v-35.3475242c0-2.65140439 1.49801663-5.07524622 3.86950483-6.26099032z" fill="#e3e9ed" fill-rule="evenodd" transform="matrix(-1 0 0 1 12 0)"/></svg>

BIN
public/img/ros-hmci/05ba445b9835d86f81dd3d2d2fb0085b.png View File

Before After
Width: 42  |  Height: 38  |  Size: 328 B

BIN
public/img/ros-hmci/07101d729ec50d8bf8c0329224585f14.png View File

Before After
Width: 1118  |  Height: 688  |  Size: 326 KiB

BIN
public/img/ros-hmci/07efd9450ffe064783352fc7f834c818.png View File

Before After
Width: 60  |  Height: 60  |  Size: 7.3 KiB

BIN
public/img/ros-hmci/0ad3ccc7a16937626852494fe161f920.png View File

Before After
Width: 1920  |  Height: 1765  |  Size: 496 KiB

BIN
public/img/ros-hmci/0b51c576036515c0b151c2b73c848d5a.png View File

Before After
Width: 54  |  Height: 40  |  Size: 1.0 KiB

BIN
public/img/ros-hmci/0bcaad921656ccd036d59b5001290107.png View File

Before After
Width: 200  |  Height: 200  |  Size: 29 KiB

BIN
public/img/ros-hmci/0e3b98bffa39d78df6519384523216d4.png View File

Before After
Width: 26  |  Height: 24  |  Size: 477 B

BIN
public/img/ros-hmci/0f386ae5fc2a0ff6c19600002d0e5321.png View File

Before After
Width: 28  |  Height: 28  |  Size: 704 B

BIN
public/img/ros-hmci/1266ef6d15c9a75a4e74980373438d12.png View File

Before After
Width: 61  |  Height: 29  |  Size: 1.9 KiB

BIN
public/img/ros-hmci/12a58f09aa65651a4e8457a87d0c47c9.png View File

Before After
Width: 3840  |  Height: 3044  |  Size: 1.5 MiB

BIN
public/img/ros-hmci/1483edffca1c70a08974d6b7de6a3fdb.png View File

Before After
Width: 1920  |  Height: 285  |  Size: 934 KiB

BIN
public/img/ros-hmci/15d30eeae7c75d1c55c672cee086d023.png View File

Before After
Width: 34  |  Height: 32  |  Size: 872 B

BIN
public/img/ros-hmci/15e78788894611bd018de8f762e13b1d.png View File

Before After
Width: 84  |  Height: 2  |  Size: 138 B

BIN
public/img/ros-hmci/18bc9f0fd8ffe1059aa8e57019ba88e8.png View File

Before After
Width: 34  |  Height: 28  |  Size: 565 B

BIN
public/img/ros-hmci/191a154003e8bbbd8b2faa94df79c381.png View File

Before After
Width: 5  |  Height: 33  |  Size: 220 B

BIN
public/img/ros-hmci/1a356bb5a7ce93c23243062386ea60e9.png View File

Before After
Width: 61  |  Height: 25  |  Size: 2.3 KiB

BIN
public/img/ros-hmci/1d7748ff8d2c3b099e0d8c2db16a0a0a.png View File

Before After
Width: 62  |  Height: 62  |  Size: 4.2 KiB

BIN
public/img/ros-hmci/1ea818c19c5613897903f3f07e4aabea.png View File

Before After
Width: 34  |  Height: 32  |  Size: 874 B

BIN
public/img/ros-hmci/202c82cca2cccbe1919fcee768356fa1.png View File

Before After
Width: 30  |  Height: 22  |  Size: 768 B

BIN
public/img/ros-hmci/227958a1d5796fb19d379cf8df9c873f.png View File

Before After
Width: 74  |  Height: 74  |  Size: 10 KiB

BIN
public/img/ros-hmci/23ea1b095bd7856806cbffaeaf3160bb.png View File

Before After
Width: 30  |  Height: 30  |  Size: 2.5 KiB

BIN
public/img/ros-hmci/2742681bb0685ab3ec198a5239289f24.png View File

Before After
Width: 30  |  Height: 30  |  Size: 2.4 KiB

BIN
public/img/ros-hmci/27d598cdd229958d8d8b3e1259e287b6.png View File

Before After
Width: 28  |  Height: 24  |  Size: 404 B

BIN
public/img/ros-hmci/2b245f6e8732299f6c5d29d45c09f4ab.png View File

Before After
Width: 34  |  Height: 52  |  Size: 463 B

BIN
public/img/ros-hmci/2b91f419b0c3fbd48469905da58b368a.png View File

Before After
Width: 44  |  Height: 40  |  Size: 949 B

BIN
public/img/ros-hmci/2d4d93f3962be672964d8e494dae69a9.png View File

Before After
Width: 538  |  Height: 438  |  Size: 74 KiB

BIN
public/img/ros-hmci/2dc305b08d2bff74de723e660cf54f51.png View File

Before After
Width: 11  |  Height: 11  |  Size: 222 B

BIN
public/img/ros-hmci/2df728971445f735584502351e69f404.png View File

Before After
Width: 62  |  Height: 62  |  Size: 3.9 KiB

BIN
public/img/ros-hmci/2dfd8be62195aea32d3721e9c44a7b65.png View File

Before After
Width: 30  |  Height: 30  |  Size: 2.0 KiB

BIN
public/img/ros-hmci/2fb2e97a136836d83ca1b1970d5ebc05.png View File

Before After
Width: 182  |  Height: 128  |  Size: 2.2 KiB

BIN
public/img/ros-hmci/307193d9e46833b97c8e5afae89a3b84.png View File

Before After
Width: 1324  |  Height: 195  |  Size: 50 KiB

BIN
public/img/ros-hmci/328f39c65f2fad357fd239d70f9853d3.png View File

Before After
Width: 92  |  Height: 80  |  Size: 5.1 KiB

BIN
public/img/ros-hmci/32f93a9ac08c57dfb50d38eef5828a13.png View File

Before After
Width: 26  |  Height: 24  |  Size: 410 B

BIN
public/img/ros-hmci/36d96691d2b74c84ca57e270907a9596.png View File

Before After
Width: 24  |  Height: 24  |  Size: 276 B

BIN
public/img/ros-hmci/372a8bfa767dfa44c42afe1be7a3341b.png View File

Before After
Width: 61  |  Height: 26  |  Size: 2.2 KiB

BIN
public/img/ros-hmci/375deb080d12485d7c5b020a91cac3f5.png View File

Before After
Width: 22  |  Height: 26  |  Size: 509 B

BIN
public/img/ros-hmci/38b556121ea08c3a34ebd7947ff818ef.png View File

Before After
Width: 45  |  Height: 26  |  Size: 1.8 KiB

BIN
public/img/ros-hmci/39ea174f887d877ea76ba31228a6315d.png View File

Before After
Width: 34  |  Height: 34  |  Size: 1.0 KiB

BIN
public/img/ros-hmci/3a6453ce7a73331de8dc8d46ac792980.png View File

Before After
Width: 74  |  Height: 74  |  Size: 11 KiB

BIN
public/img/ros-hmci/3bbd57a73399bf2077275457666e5e37.png View File

Before After
Width: 1920  |  Height: 2205  |  Size: 21 KiB

BIN
public/img/ros-hmci/3cc371058d1857c44ab96a2ddd28159b.png View File

Before After
Width: 478  |  Height: 164  |  Size: 29 KiB

BIN
public/img/ros-hmci/3d0cdf6c59b3734bdcaa492f430697ae.png View File

Before After
Width: 34  |  Height: 34  |  Size: 1.2 KiB

BIN
public/img/ros-hmci/3e56d7dc07ba43c2fc3777593c616ba9.png View File

Before After
Width: 10  |  Height: 12  |  Size: 119 B

BIN
public/img/ros-hmci/41526c6a56ab35fbfd75efe611e6a269.png View File

Before After
Width: 1920  |  Height: 870  |  Size: 8.6 KiB

BIN
public/img/ros-hmci/43e3b14c6e2a924e143faab617e1b449.png View File

Before After
Width: 124  |  Height: 124  |  Size: 6.1 KiB

BIN
public/img/ros-hmci/449b407d5174de110f663f1b72471720.png View File

Before After
Width: 1920  |  Height: 2869  |  Size: 261 KiB

BIN
public/img/ros-hmci/45351da17710517dfb616133de40bc17.png View File

Before After
Width: 202  |  Height: 198  |  Size: 25 KiB

BIN
public/img/ros-hmci/4949f8f2b7bae0d43a4aa67699c10335.png View File

Before After
Width: 33  |  Height: 21  |  Size: 898 B

BIN
public/img/ros-hmci/4b4c4662629e074227c63d23f46271ac.png View File

Before After
Width: 34  |  Height: 32  |  Size: 656 B

BIN
public/img/ros-hmci/4dcdce6ea20fc6126991a3a9ce999064.png View File

Before After
Width: 13  |  Height: 43  |  Size: 993 B

BIN
public/img/ros-hmci/5520ba673bc80210912d830a304adddd.png View File

Before After
Width: 50  |  Height: 26  |  Size: 439 B

BIN
public/img/ros-hmci/556e5bde0bcecb4a5313962a5cf935fe.png View File

Before After
Width: 5  |  Height: 33  |  Size: 216 B

BIN
public/img/ros-hmci/55e24ed247765c26ba9ebdc7178aa587.png View File

Before After
Width: 74  |  Height: 74  |  Size: 9.4 KiB

BIN
public/img/ros-hmci/573ef7ee84a6b4884195d6d20d48d192.png View File

Before After
Width: 30  |  Height: 30  |  Size: 2.6 KiB

BIN
public/img/ros-hmci/58287c3a4b1f6c90d86a18c1ce3fe9a0.png View File

Before After
Width: 1920  |  Height: 614  |  Size: 695 KiB

BIN
public/img/ros-hmci/58c00cc05cb3a7614393125e1a0bd7ba.png View File

Before After
Width: 34  |  Height: 34  |  Size: 1.4 KiB

BIN
public/img/ros-hmci/5b08f8e6adcee3691cc86af6a880afb6.png View File

Before After
Width: 28  |  Height: 28  |  Size: 703 B

BIN
public/img/ros-hmci/5fda1de7e984f5c1ec553662ab771407.png View File

Before After
Width: 33  |  Height: 21  |  Size: 901 B

BIN
public/img/ros-hmci/624b71c49ce138ae6ce2dff0de4f81cc.png View File

Before After
Width: 30  |  Height: 28  |  Size: 366 B

BIN
public/img/ros-hmci/62b53dd597736adecf97d25b2889c5e2.png View File

Before After
Width: 18  |  Height: 12  |  Size: 251 B

BIN
public/img/ros-hmci/649898031748a5867af33a892716a817.png View File

Before After
Width: 34  |  Height: 28  |  Size: 543 B

BIN
public/img/ros-hmci/64a805a2c15419c356ca28f95ee943b6.png View File

Before After
Width: 14  |  Height: 26  |  Size: 271 B

BIN
public/img/ros-hmci/64feeeb56b3e341ea6bb89649896adf6.png View File

Before After
Width: 62  |  Height: 62  |  Size: 5.5 KiB

BIN
public/img/ros-hmci/66fa35144bcca1d59efbd809308d8978.png View File

Before After
Width: 30  |  Height: 26  |  Size: 1003 B

BIN
public/img/ros-hmci/68acd342613a54742d5e94bb85df2128.png View File

Before After
Width: 34  |  Height: 22  |  Size: 934 B

BIN
public/img/ros-hmci/6ae4d710aaf64c9fb32198a417e7deda.png View File

Before After
Width: 74  |  Height: 74  |  Size: 12 KiB

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

Loading…
Cancel
Save