@@ -71,6 +71,19 @@ | |||
.ui.secondary.hometop.segment #navbar{ | |||
z-index: 10; | |||
} | |||
.ui.secondary.c2net.segment{ | |||
/* background: #f8faff; | |||
border: none;*/ | |||
margin-bottom: 5em; | |||
padding-top: 2em; | |||
color: rgba(0,0,0,.87); | |||
background-image: linear-gradient(to bottom left,var(--tw-gradient-stops)); | |||
--tw-gradient-from: #f5f3ff; | |||
--tw-gradient-stops: var(--tw-gradient-from),#fff,var(--tw-gradient-to,hsla(0,0%,100%,0)); | |||
--tw-gradient-to: rgba(219,234,254,0.4); | |||
border-top: 1px solid rgba(243,244,246,1)!important; | |||
border-bottom: 1px solid rgba(243,244,246,1)!important; | |||
} | |||
.hometop .ui.secondary.menu .active.item{ | |||
color: #000; | |||
@@ -134,8 +147,13 @@ | |||
.i-code-pic > img{ | |||
margin-bottom: -3.0rem; | |||
} | |||
.i-env .ui.cards>.card{ | |||
box-shadow:none; | |||
} | |||
.i-env .ui.cards>.card>.image{ | |||
background: none; | |||
width: 60%; | |||
margin: auto; | |||
} | |||
.i-env .ui.cards>.card>.content{ | |||
border-top: none; | |||
@@ -168,7 +186,7 @@ | |||
bottom: 0; | |||
background-color: rgba(105, 192, 255, .4); | |||
width: 2px; | |||
} | |||
} | |||
.homenews .time-since{ | |||
padding-left: 1em; | |||
color: #888888; | |||
@@ -185,7 +203,7 @@ | |||
padding: 0; | |||
} | |||
.newslist{ | |||
height: 325px; | |||
height: 300px; | |||
overflow: hidden; | |||
} | |||
@@ -208,14 +226,25 @@ | |||
height: auto; | |||
border-top: 2px solid #3291F8; | |||
border-right: 2px solid #3291F8; | |||
border-bottom: 2px solid #3291F8; | |||
border-radius: 0 4.0em 4.0em 0; | |||
border-radius: 0 4.0em 0 0; | |||
width: 10em; | |||
z-index: 6; | |||
} | |||
.leftline02::after, .leftline02-2::after{ | |||
content: ''; | |||
position: absolute; | |||
transform: translate(55%,50%); | |||
right: 0; | |||
bottom: 0; | |||
width: 1.0em; | |||
height: 1.0em; | |||
background-color: #FFF; | |||
border: 2px solid #3291F8; | |||
border-radius: 1em; | |||
} | |||
.leftline03{ | |||
border-radius: 4.0em 0 0 0; | |||
border-top: 2px solid #3291F8; | |||
border-top: 2px solid #3291F8; | |||
border-bottom:none; | |||
top: -2.0em; | |||
} | |||
@@ -224,6 +253,9 @@ | |||
width: 7em; | |||
z-index: 5; | |||
} | |||
.leftline02-2::after{ | |||
border-color: rgba(105, 192, 255, .4); | |||
} | |||
.leftline04{ | |||
border-radius: 0; | |||
border-top: none; | |||
@@ -280,6 +312,9 @@ | |||
.i-env > div{ | |||
position: relative; | |||
} | |||
.event-list .ui.card>.image>img{ | |||
height: 146px !important; | |||
} | |||
@media only screen and (max-width: 767px) { | |||
.am-mt-30{ margin-top: 1.5rem !important;} | |||
@@ -376,4 +411,40 @@ | |||
@media only screen and (min-width: 1920px) { | |||
} | |||
/* rotation3D */ | |||
#app{ | |||
width: 800px; | |||
margin: 0 auto; | |||
} | |||
.rotation3D-baseMap{ | |||
position: absolute; left: 0; right: 0; top: 270px; margin: auto; | |||
width: 800px; height: 516px; | |||
background: url("../rotation3D/img/baseMap.png") no-repeat; | |||
background-size: cover; | |||
} | |||
.rotation3D-baseMap::before{ | |||
position: absolute; | |||
margin: auto; z-index: 99; | |||
left:50%; top: -150px; | |||
transform:translate(-50%,0); | |||
width: 342px; height: 470px; display: block; content: ''; | |||
background: url("../rotation3D/img/baseLogo.svg"); | |||
/*animation: 10s bounceUpDown infinite;*/ | |||
} | |||
.rotation3D-baseMap::after{ | |||
position: absolute; | |||
margin: auto; z-index: 100; | |||
left:50%; top:0; | |||
transform:translate(-50%,0); | |||
width: 110px; height: 86px; display: block; content: ''; | |||
background: url("../rotation3D/img/brain.svg"); | |||
animation: 6s bounceUpDown infinite; | |||
mix-blend-mode: color-dodge; | |||
} | |||
@keyframes bounceUpDown{ | |||
0% {transform: translate(-50%, 0px);} | |||
50% {transform: translate(-50%, -15px);} | |||
100% {transform: translate(-50%, 0px);} | |||
} |
@@ -0,0 +1,152 @@ | |||
/* | |||
椭圆会使内部失真 transform: rotateX(50deg); | |||
*/ | |||
.rotation3D{ | |||
position: relative; width: 800px; height: 600px; user-select: none; | |||
margin: 0 auto; | |||
/* border: 1px solid white; border-radius: 100%; */ | |||
/* cursor: move; */ | |||
} | |||
.rotation3D .center{ | |||
display: none; | |||
position: absolute; left: 50%; top: 50%; | |||
transform: translate(-50%, -50%); | |||
} | |||
.rotation3D .itemList{ position: absolute; width: 100%; height: 100%; z-index: 20; } | |||
.rotation3D .lineList{ | |||
position: absolute; width: 100%; height: 100%; z-index: 10; | |||
transform-style: preserve-3d; | |||
} | |||
/*---------------------------点样式---------------------------*/ | |||
.rotation3D__item{ | |||
position: absolute; display: block; width: 161px; height: 188px; | |||
text-align: center; line-height: 30px; font-size: 16px; color: white; | |||
/*background: #2292ef; border-radius: 4px;*/ | |||
/*cursor: pointer; */ | |||
} | |||
.rotation3D__item .scale{ position: absolute; top: 0; width: 100%; height: 100%; } | |||
.rotation3D__item .cont{ position: relative; z-index: 2; } | |||
.rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; } | |||
.rotation3D__item .cont p{ color: #101010; } | |||
.itemList .rotation3D__item .cont p::after{ | |||
font-size: 12px; | |||
content: ''; | |||
position: absolute; | |||
left: 0; | |||
right: 0; | |||
margin-top: 60px; | |||
color: #101010; | |||
} | |||
.itemList .rotation3D__item:nth-child(1) .cont p::after{ | |||
content: "鹏城云脑一号"; | |||
} | |||
.itemList .rotation3D__item:nth-child(2) .cont p::after{ | |||
content: "鹏城云脑二号"; | |||
} | |||
.itemList .rotation3D__item:nth-child(3) .cont p::after{ | |||
content: "北大人工智能集群系统"; | |||
} | |||
.itemList .rotation3D__item:nth-child(4) .cont p::after{ | |||
content: "合肥类脑智能开放平台"; | |||
} | |||
.itemList .rotation3D__item:nth-child(5) .cont p::after{ | |||
content: "武汉人工智能计算中心"; | |||
} | |||
.itemList .rotation3D__item:nth-child(6) .cont p::after{ | |||
content: "西安未来人工智能计算中心"; | |||
} | |||
.itemList .rotation3D__item:nth-child(7) .cont p::after{ | |||
content: "更多接入中…"; | |||
} | |||
.itemList .rotation3D__item:nth-child(8) .cont p::after{ | |||
content: "中原人工智能计算中心"; | |||
} | |||
.itemList .rotation3D__item:nth-child(9) .cont p::after{ | |||
content: "成都人工智能计算中心"; | |||
} | |||
.itemList .rotation3D__item:nth-child(10) .cont p::after{ | |||
content: "横琴先进智能计算中心"; | |||
} | |||
.itemList .rotation3D__item:nth-child(11) .cont p::after{ | |||
content: "国家超级计算济南中心"; | |||
} | |||
.rotation3D__item.blue{ color: #01e9fc; } | |||
.rotation3D__item.green{ color: #b4b3ca; } | |||
.rotation3D__item.yellow{ color: #ffd200; } | |||
/*底座*/ | |||
.rotation3D__item .baseImg{ position: absolute; width: 100%; height: 100%; z-index: 1; } | |||
.rotation3D__item.blue .baseImg{ background: url("img/idc-red.png"); } | |||
.rotation3D__item.green .baseImg{ background: url("img/idc-green.png"); } | |||
.rotation3D__item.yellow .baseImg{ background: url("img/idc-yellow.png"); } | |||
/*--------------------------- | |||
线样式 | |||
线高为总高的一般 | |||
---------------------------*/ | |||
.rotation3D__line{ | |||
position: absolute; left: 50%; top: 50%; | |||
display: block; width: 1px; height: 50%; | |||
padding-top: 60px; color: #fff; font-size: 50px; | |||
/*background: #fff;*/ | |||
/*原点设置在中间*/ | |||
transform-origin: 50% 0; | |||
transform-style: preserve-3d; | |||
} | |||
.rotation3D__line .pos{ position: absolute; top: 0; } | |||
.rotation3D__line svg { position: absolute; top: 0; } | |||
.rotation3D__line svg path { | |||
stroke: #fff; fill: none; | |||
stroke-width: 2; | |||
animation: path-animation 100s linear 0s infinite normal; | |||
} | |||
@keyframes path-animation { | |||
0% { stroke-dashoffset:500; } | |||
100% { stroke-dashoffset:0; } | |||
} | |||
.rotation3D__line .dot { | |||
position: absolute; top: 0; left: 0; text-align: center; | |||
/*width: 35px; height: 35px; font-size: 35px; */ | |||
width: 19px; height: 19px; font-size: 19px; | |||
} | |||
.rotation3D__line .dot1,.rotation3D__line .dot3,.rotation3D__line .dot4{ | |||
animation: svg-path-animation 6s ease-in-out 0s infinite normal; | |||
} | |||
.rotation3D__line .dot1{ | |||
offset-path: path("M0 400, 0 0"); offset-distance: 0%; | |||
} | |||
.rotation3D__line .dot2{ | |||
offset-path: path("M0 200, 0 0"); offset-distance: 0%; | |||
background: #ffd200; border-radius: 100%; | |||
font-size: 22px; color: #000; | |||
} | |||
.rotation3D__line .dot3{ | |||
offset-path: path("M20 400 S 0 200, 20 0"); offset-distance: 0%; | |||
} | |||
.rotation3D__line .dot4{ | |||
position: relative; | |||
offset-path: path("M20 0 S 40 200, 20 400"); offset-distance: 0%; | |||
} | |||
@keyframes svg-path-animation { | |||
from {offset-distance: 100%;} | |||
to {offset-distance: 0%;} | |||
} | |||
.dot1 > span{ | |||
position: absolute; | |||
font-size: 12px; | |||
color: #888; | |||
transform: rotate(180deg)scale(0.80); | |||
} | |||
/*颜色*/ | |||
.rotation3D__line.blue { color: #07b2f9; } | |||
.rotation3D__line.green { color: #ac94ee; } | |||
.rotation3D__line.yellow { color: #ffd500; } | |||
.rotation3D__line.blue svg path { stroke: #07b2f9; } | |||
.rotation3D__line.green svg path { stroke: #ac94ee; } | |||
.rotation3D__line.yellow svg path { stroke: #ffd500; } |
@@ -0,0 +1,380 @@ | |||
var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame; | |||
var requestFrame = window.requestAnimationFrame; | |||
var time = !window.performance || !window.performance.now ? | |||
function () {return +new Date()}: | |||
function () {return performance.now()}; | |||
/** | |||
* 计算两点距离 | |||
* @param points | |||
* @returns {number} | |||
* distance([{x:0,y:0},{x:1,y:1}]); | |||
*/ | |||
var distance = function(points) { | |||
var p1=points[0]; | |||
var p2=points[1]; | |||
var a = p2.x-p1.x; | |||
var b = p2.y-p1.y; | |||
return Math.sqrt(a*a+b*b); | |||
}; | |||
/** | |||
* 圆公式 | |||
* @param rotation 弧度 | |||
* 计算公式: | |||
* Math.PI; //圆周率 | |||
* Math.sin(); //正弦 x -左 +右 | |||
* Math.cos; //余弦 y -下 +上 | |||
*/ | |||
var circleMath = { | |||
/** | |||
* 根据弧度计算角度 | |||
* @param rotation 弧度 | |||
* rotation, farScale, xs, xr, ys, yr, itemWidth | |||
*/ | |||
// parseRotate: function (rotation) { | |||
// return (180 / Math.PI * rotation) - 180; | |||
// }, | |||
parseRotate: function (rotation, self) { | |||
var sin = Math.sin(rotation), cos = Math.cos(rotation); | |||
var sin_cos = sin*cos; //得出偏移正负值,从0°向左依次 +-+- | |||
var angle = (180 / Math.PI * rotation) - 180; | |||
var lastAngle = angle; | |||
// console.log('rotation',rotation) | |||
// console.log('sin',sin) | |||
// console.log('cos',cos) | |||
// console.log('sin*cos',sin*cos); | |||
// console.log('统一偏移角度',self.yr * (sin_cos/Math.PI)) | |||
lastAngle = angle + (self.yr * (sin_cos/(Math.PI+1))); | |||
return lastAngle; | |||
}, | |||
/** | |||
* 计算scale,x,y | |||
* scale 最小尺寸 + ((1 - 最小尺寸) * (sin正弦 + 1) * 0.5) | |||
* x x起点 + (尺寸 * cos余弦 * x半径) - 元素宽度一半 | |||
* y y起点 + (尺寸 * sin正弦 * x半径) - 元素宽度一半 | |||
* farScale, xs, xr, ys, yr, itemWidth | |||
*/ | |||
parseSXY: function (rotation, self) { | |||
var farScale=self.farScale; | |||
var itemWidth=self.itemWidth; | |||
var xs=self.xs; var xr=self.xr; var ys=self.ys; var yr=self.yr; | |||
var sin = Math.sin(rotation), cos = Math.cos(rotation); | |||
var scale = farScale + ((1 - farScale) * (sin + 1) * 0.5); //单个尺寸 | |||
// 按设置尺寸 | |||
// var x = xs + (scale * cos * xr) - (itemWidth * 0.5); | |||
// var y = ys + (scale * sin * yr) - (itemWidth * 0.5); | |||
// 不使用压缩 | |||
// var x = xs + (cos * xs) - (itemWidth * 0.5); | |||
// var y = ys + (sin * ys) - (itemWidth * 0.5); | |||
// 使用压缩 | |||
var x = xs + (cos * xr) - (itemWidth * 0.5); | |||
var y = ys + (sin * yr) - (itemWidth * 0.5); | |||
var distanceNumber = distance([ | |||
{x:self.$rotation.width()/2 - self.$item.width()/2, y:self.$rotation.height()/2 - self.$item.height()/2}, | |||
{x:x,y:y}] | |||
); | |||
// console.log({x:self.$rotation.width()/2, y:self.$rotation.height()/2}) | |||
// console.log('x,y',x,y) | |||
// console.log('两点距离',distanceNumber) | |||
return { | |||
x: x, | |||
y: y, | |||
scale: scale, | |||
distanceNumber: distanceNumber, | |||
} | |||
}, | |||
} | |||
/** | |||
* 3D旋转 | |||
* @param id | |||
*/ | |||
var Rotation3D = window.Rotation3D = function (_opts) { | |||
var self=this; | |||
this.$rotation = $(_opts.id) | |||
this.$lineList = this.$rotation.find('.lineList') | |||
this.$item = this.$rotation.find('.rotation3D__item') | |||
this.$line = this.$rotation.find('.rotation3D__line') | |||
this.itemWidth = this.$item.width(); | |||
this.itemHeight = this.$item.height(); | |||
this.length = this.$item.length; | |||
// 圆计算 | |||
this.rotation = Math.PI / 2; //圆周率/2 | |||
this.destRotation = this.rotation; | |||
var xr = this.$rotation.width() * 0.5; | |||
var yr = this.$rotation.height() * 0.5; | |||
var xRadius = _opts.xRadius || 0; | |||
var yRadius = _opts.yRadius || 0; | |||
var opts = Object.assign({ | |||
farScale: 1, // 最小尺寸 | |||
xs: xr, // x起点 | |||
ys: yr, // y起点 | |||
xr: xr - xRadius, // x半径-压缩 | |||
yr: yr - yRadius, // y半径-压缩 | |||
// 播放 | |||
autoPlay:false, | |||
autoPlayDelay:3000, | |||
currenIndex:-1, | |||
fps:30, | |||
speed:4, | |||
},_opts) | |||
Object.assign(this, opts) | |||
// 遍历子元素 | |||
this.$item.each(function (index) { | |||
$(this).click(function () { | |||
$(this).addClass('active').siblings().removeClass('active') | |||
self.goTo(index) | |||
}) | |||
}) | |||
// 当前控件进入离开 | |||
this.$rotation.mouseenter(function () { | |||
clearInterval(self.autoPlayTimer) | |||
}) | |||
this.$rotation.mouseleave(function () { | |||
self.onAutoPlay() | |||
}) | |||
this.onAutoPlay() | |||
this.onDrag() | |||
this.render() | |||
} | |||
/** | |||
* item样式 | |||
* x x起点 + (尺寸 * 余弦 * x压缩) - 元素宽度一半 | |||
* y y起点 + (尺寸 * 正弦 * y压缩) - 元素宽度一半 | |||
*/ | |||
Rotation3D.prototype.itemStyle = function($item, index, rotation) { | |||
//console.log("itemStyle=" + rotation + " index=" + index); | |||
var parseSXY = circleMath.parseSXY(rotation, this); | |||
var scale = parseSXY.scale; | |||
var x = parseSXY.x; | |||
var y = parseSXY.y; | |||
var $line = this.$lineList.find('.rotation3D__line').eq(index); | |||
//设置当前子菜单的位置(left,top) = (x,y) | |||
$item.find('.scale').css({ | |||
'transform': `scale(${scale})`, | |||
// 'top': `${this.itemWidth * (1-scale) }`, | |||
}) | |||
$item.css({ | |||
position: 'absolute', | |||
display: 'inline-block', | |||
// opacity: scale, | |||
'z-index': parseInt(scale * 100), | |||
'transform-origin': '0px 0px', | |||
// 'transform': `translate(${x}px, ${y}px) scale(${scale})`, | |||
'transform': `translate(${x}px, ${y}px)`, | |||
}); | |||
/** | |||
* 线样式 | |||
*/ | |||
$line.css({ | |||
height:parseSXY.distanceNumber, | |||
}) | |||
$line.find('svg').css({ | |||
height:parseSXY.distanceNumber, | |||
}) | |||
$line.find('.dot1').css({ | |||
'offset-path':`path("M0 ${parseSXY.distanceNumber}, 0 0")`, | |||
}) | |||
$line.find('#path1').attr({ | |||
'd':`M0 ${parseSXY.distanceNumber}, 0 0`, | |||
}) | |||
$line.find('.dot2').css({ | |||
'offset-path':`path("M0 ${parseSXY.distanceNumber/2}, 0 0")`, | |||
}) | |||
$line.find('#path2').attr({ | |||
'd':`M0 ${parseSXY.distanceNumber}, 0 0`, | |||
}) | |||
$line.find('.dot3').css({ | |||
'offset-path':`path("M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0")`, | |||
}) | |||
$line.find('#path3').attr({ | |||
'd':`M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0`, | |||
}) | |||
$line.find('.dot4').css({ | |||
'offset-path':`path("M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}")`, | |||
}) | |||
$line.find('#path4').attr({ | |||
'd':`M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}`, | |||
}) | |||
} | |||
/** | |||
* line样式 | |||
*/ | |||
Rotation3D.prototype.lineStyle = function($line, index, rotation) { | |||
var rotate = circleMath.parseRotate(rotation, this) | |||
//console.log("lineStyle=" + rotation + " index=" + index); | |||
$line.css({ | |||
transform: 'rotate(' + rotate + 'deg)', | |||
}) | |||
this.$lineList.css({ | |||
// transform: `rotateX(${this.yRadius / 3}deg)`, | |||
}) | |||
} | |||
/** | |||
* 旋转至index | |||
*/ | |||
Rotation3D.prototype.goTo = function (index) { | |||
var self = this; | |||
this.currenIndex = index; | |||
//console.log('goTo currenIndex', index); | |||
/** | |||
* 1.计算floatIndex,用于控死amdiff | |||
*/ | |||
var itemsRotated = this.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI); | |||
var floatIndex = itemsRotated % this.length; | |||
if (floatIndex < 0) { floatIndex = floatIndex + this.length; } | |||
/** | |||
* 2.计算diff,判断方向正反 | |||
*/ | |||
var diff = index - (floatIndex % this.length); | |||
if (2 * Math.abs(diff) > this.length) { | |||
diff -= (diff > 0) ? this.length : -this.length; | |||
} | |||
// 停止任何正在进行的旋转 | |||
this.destRotation += (2 * Math.PI / this.length) * -diff; | |||
this.scheduleNextFrame(); | |||
} | |||
/** | |||
* 定时器渐近旋转 | |||
*/ | |||
Rotation3D.prototype.scheduleNextFrame = function () { | |||
var self = this | |||
this.lastTime = time(); | |||
// 暂停 | |||
var pause = function () { | |||
cancelFrame ? cancelFrame(this.timer) : clearTimeout(self.timer); | |||
self.timer = 0; | |||
} | |||
// 渐进播放 | |||
var playFrame = function () { | |||
var rem = self.destRotation - self.rotation; | |||
var now = time(), dt = (now - self.lastTime) * 0.002; | |||
self.lastTime = now; | |||
// console.log('rem',rem) | |||
if (Math.abs(rem) < 0.003) { | |||
self.rotation = self.destRotation; | |||
pause(); | |||
} else { | |||
// 渐近地接近目的地 | |||
self.rotation = self.destRotation - rem / (1 + (self.speed * dt)); | |||
self.scheduleNextFrame(); | |||
} | |||
self.render(); | |||
} | |||
this.timer = cancelFrame ? | |||
requestFrame(playFrame) : | |||
setTimeout(playFrame, 1000 / this.fps); | |||
} | |||
/** | |||
* 更新 | |||
*/ | |||
Rotation3D.prototype.render = function () { | |||
var self=this; | |||
// 图形间隔:弧度 | |||
var spacing = 2 * Math.PI / this.$item.length; | |||
var itemRotation = this.rotation; | |||
var lineRotation = this.rotation + (Math.PI/2); | |||
this.$item.each(function (index) { | |||
self.itemStyle($(this), index, itemRotation) | |||
itemRotation += spacing; | |||
}) | |||
this.$line.each(function (index) { | |||
self.lineStyle($(this), index, lineRotation) | |||
lineRotation += spacing; | |||
}) | |||
} | |||
/** | |||
* 自动播放 | |||
*/ | |||
Rotation3D.prototype.onAutoPlay = function () { | |||
var self = this; | |||
if (this.autoPlay) { | |||
this.autoPlayTimer = setInterval(function () { | |||
if (self.currenIndex < 0) { | |||
self.currenIndex = self.length - 1 | |||
} | |||
//console.log("autoPlayTimer...."); | |||
self.goTo(self.currenIndex); | |||
self.currenIndex--; //倒叙 | |||
}, this.autoPlayDelay) | |||
} | |||
} | |||
/** | |||
* 拖拽 | |||
*/ | |||
Rotation3D.prototype.onDrag = function () { | |||
var self = this; | |||
var startX, startY, moveX, moveY, endX, endY; | |||
//console.log("onDrag...."); | |||
// 拖拽:三个事件-按下 移动 抬起 | |||
//按下 | |||
this.$rotation.mousedown(function (e) { | |||
startX = e.pageX; startY = e.pageY; | |||
//console.log("mousedown...."); | |||
// 移动 | |||
$(document).mousemove(function (e) { | |||
// console.log('移动'); | |||
endX = e.pageX; endY = e.pageY; | |||
moveX = endX - startX; moveY = endY - startY; | |||
// console.log('x,y',moveX,moveY); | |||
}) | |||
// 抬起 | |||
$(document).mouseup(function (e) { | |||
endX = e.pageX; endY = e.pageY; | |||
moveX = endX - startX; moveY = endY - startY; | |||
//console.log("mouseup...."); | |||
// 每40旋转一步 | |||
var moveIndex = parseInt(Math.abs(moveX) / 50) | |||
//console.log('moveIndex',moveIndex) | |||
if (moveIndex > 0) { | |||
// console.log(moveX<0 ? '向左' : '向右') | |||
if (moveX < 0) { //向左 | |||
self.currenIndex = self.currenIndex - moveIndex | |||
play(moveIndex) | |||
} else { //向右 | |||
self.currenIndex = self.currenIndex + moveIndex | |||
play(moveIndex) | |||
} | |||
} | |||
// 解绑 | |||
$(document).unbind("mousemove"); | |||
$(document).unbind("mouseup"); | |||
}) | |||
}) | |||
function play() { | |||
if (self.currenIndex == 0) { | |||
self.currenIndex = self.length - 1 | |||
} | |||
self.goTo(self.currenIndex % self.length); | |||
} | |||
} |
@@ -1291,7 +1291,8 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) | |||
builder.Eq{"cloudbrain.job_id": jobId}, | |||
) | |||
cond = cond.And( | |||
builder.Eq{"cloudbrain.Status": "COMPLETED"}, | |||
builder.In("cloudbrain.Status", "COMPLETED", "SUCCEEDED"), | |||
//builder.Eq{"cloudbrain.Status": "COMPLETED"}, | |||
) | |||
sess.OrderBy("cloudbrain.created_unix DESC") | |||
@@ -1312,7 +1313,7 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { | |||
builder.Eq{"repo_id": repoId}, | |||
) | |||
cond = cond.And( | |||
builder.Eq{"Status": "COMPLETED"}, | |||
builder.In("Status", "COMPLETED", "SUCCEEDED"), | |||
) | |||
cond = cond.And( | |||
builder.Eq{"job_type": "TRAIN"}, | |||
@@ -0,0 +1,22 @@ | |||
package models | |||
import "code.gitea.io/gitea/modules/log" | |||
func GetAllStatusCloudBrain() map[string]int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
cloudbrains := make([]*CloudbrainInfo, 0) | |||
if err := sess.Table(&Cloudbrain{}).Unscoped(). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
cloudBrainStatusResult := make(map[string]int) | |||
for _, cloudbrain := range cloudbrains { | |||
if _, ok := cloudBrainStatusResult[cloudbrain.Status]; !ok { | |||
cloudBrainStatusResult[cloudbrain.Status] = 1 | |||
} else { | |||
cloudBrainStatusResult[cloudbrain.Status] += 1 | |||
} | |||
} | |||
return cloudBrainStatusResult | |||
} |
@@ -719,12 +719,11 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
userIndexMap := make(map[int64]float64, 0) | |||
maxUserIndex := 0.0 | |||
minUserIndex := 100000000.0 | |||
dateRecordBatch := make([]UserBusinessAnalysisAll, 0) | |||
for { | |||
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
userList := make([]*User, 0) | |||
sess.Find(&userList) | |||
dateRecordBatch := make([]UserBusinessAnalysisAll, 0) | |||
for _, userRecord := range userList { | |||
var dateRecordAll UserBusinessAnalysisAll | |||
dateRecordAll.ID = userRecord.ID | |||
@@ -789,7 +788,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
dateRecordBatch = append(dateRecordBatch, dateRecordAll) | |||
if len(dateRecordBatch) >= BATCH_INSERT_SIZE { | |||
insertTable(dateRecordBatch, tableName, statictisSess) | |||
err := insertTable(dateRecordBatch, tableName, statictisSess) | |||
insertCount += BATCH_INSERT_SIZE | |||
if err != nil { | |||
log.Info("insert all data failed." + err.Error()) | |||
@@ -804,18 +803,19 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
} | |||
} | |||
} | |||
if len(dateRecordBatch) > 0 { | |||
err := insertTable(dateRecordBatch, tableName, statictisSess) | |||
insertCount += len(dateRecordBatch) | |||
if err != nil { | |||
log.Info("insert all data failed." + err.Error()) | |||
} | |||
} | |||
indexTotal += PAGE_SIZE | |||
if indexTotal >= count { | |||
break | |||
} | |||
} | |||
if len(dateRecordBatch) > 0 { | |||
insertTable(dateRecordBatch, tableName, statictisSess) | |||
insertCount += len(dateRecordBatch) | |||
if err != nil { | |||
log.Info("insert all data failed." + err.Error()) | |||
} | |||
} | |||
if tableName == "user_business_analysis_all" { | |||
log.Info("TotalHasActivityUser=" + fmt.Sprint(userMetrics["TotalHasActivityUser"])) | |||
} | |||
@@ -835,7 +835,7 @@ func updateUserIndex(tableName string, statictisSess *xorm.Session, userId int64 | |||
statictisSess.Exec(updateSql) | |||
} | |||
func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) { | |||
func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) error { | |||
insertBatchSql := "INSERT INTO public." + tableName + | |||
"(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + | |||
@@ -854,7 +854,8 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||
} | |||
} | |||
statictisSess.Exec(insertBatchSql) | |||
_, err := statictisSess.Exec(insertBatchSql) | |||
return err | |||
} | |||
func RefreshUserStaticAllTabel(wikiCountMap map[string]int, userMetrics map[string]int) { | |||
@@ -2057,7 +2058,9 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s | |||
} else { | |||
resultMap[cloudTaskRecord.UserID] += 1 | |||
} | |||
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap) | |||
if cloudTaskRecord.Duration < 100000000 && cloudTaskRecord.Duration > 0 { | |||
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap) | |||
} | |||
if cloudTaskRecord.Type == 1 { //npu | |||
if cloudTaskRecord.JobType == "TRAIN" { | |||
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
@@ -39,6 +39,14 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { | |||
return f, nil | |||
} | |||
func (l *LocalStorage) DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) { | |||
f, err := os.Open(filepath.Join(l.dir, objectName)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return f, nil | |||
} | |||
// Save save a file | |||
func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { | |||
p := filepath.Join(l.dir, path) | |||
@@ -59,6 +59,16 @@ func (m *MinioStorage) buildMinioPath(p string) string { | |||
return strings.TrimPrefix(path.Join(m.basePath, p), "/") | |||
} | |||
func (m *MinioStorage) DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) { | |||
var opts = minio.GetObjectOptions{} | |||
object, err := m.client.GetObject(m.bucket, objectName, opts) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return object, nil | |||
} | |||
// Open open a file | |||
func (m *MinioStorage) Open(path string) (io.ReadCloser, error) { | |||
var opts = minio.GetObjectOptions{} | |||
@@ -113,7 +113,141 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz | |||
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/") | |||
return minioClient.GenUploadPartSignedUrl(uploadId, bucketName, objectName, partNumber, partSize, PresignedUploadPartUrlExpireTime, setting.Attachment.Minio.Location) | |||
} | |||
func GetAllObjectByBucketAndPrefixMinio(bucket string, prefix string) ([]FileInfo, error) { | |||
_, core, err := getClients() | |||
if err != nil { | |||
log.Error("getClients failed:", err.Error()) | |||
return nil, err | |||
} | |||
prefixLen := len(prefix) | |||
delimiter := "" | |||
marker := "" | |||
index := 1 | |||
fileInfoList := FileInfoList{} | |||
for { | |||
output, err := core.ListObjects(bucket, prefix, marker, delimiter, 1000) | |||
if err == nil { | |||
log.Info("Page:%d\n", index) | |||
index++ | |||
for _, val := range output.Contents { | |||
var isDir bool | |||
if prefixLen == len(val.Key) { | |||
continue | |||
} | |||
if strings.HasSuffix(val.Key, "/") { | |||
isDir = true | |||
} else { | |||
isDir = false | |||
} | |||
fileInfo := FileInfo{ | |||
ModTime: val.LastModified.Format("2006-01-02 15:04:05"), | |||
FileName: val.Key[prefixLen:], | |||
Size: val.Size, | |||
IsDir: isDir, | |||
ParenDir: "", | |||
} | |||
fileInfoList = append(fileInfoList, fileInfo) | |||
} | |||
if output.IsTruncated { | |||
marker = output.NextMarker | |||
} else { | |||
break | |||
} | |||
} else { | |||
log.Info("list error." + err.Error()) | |||
return nil, err | |||
} | |||
} | |||
sort.Sort(fileInfoList) | |||
return fileInfoList, nil | |||
} | |||
func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, relativePath string) ([]FileInfo, error) { | |||
_, core, err := getClients() | |||
if err != nil { | |||
log.Error("getClients failed:", err.Error()) | |||
return nil, err | |||
} | |||
Prefix := prefixRootPath + relativePath | |||
if !strings.HasSuffix(Prefix, "/") { | |||
Prefix += "/" | |||
} | |||
log.Info("bucket=" + bucket + " Prefix=" + Prefix) | |||
output, err := core.ListObjects(bucket, Prefix, "", "", 1000) | |||
fileInfos := make([]FileInfo, 0) | |||
prefixLen := len(Prefix) | |||
if err == nil { | |||
for _, val := range output.Contents { | |||
log.Info("val key=" + val.Key) | |||
var isDir bool | |||
var fileName string | |||
if val.Key == Prefix { | |||
continue | |||
} | |||
if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||
continue | |||
} | |||
if strings.HasSuffix(val.Key, "/") { | |||
isDir = true | |||
fileName = val.Key[prefixLen : len(val.Key)-1] | |||
relativePath += val.Key[prefixLen:] | |||
} else { | |||
isDir = false | |||
fileName = val.Key[prefixLen:] | |||
} | |||
fileInfo := FileInfo{ | |||
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||
FileName: fileName, | |||
Size: val.Size, | |||
IsDir: isDir, | |||
ParenDir: relativePath, | |||
} | |||
fileInfos = append(fileInfos, fileInfo) | |||
} | |||
return fileInfos, err | |||
} else { | |||
log.Error("Message:%s", err.Error()) | |||
return nil, err | |||
} | |||
} | |||
func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { | |||
_, core, err := getClients() | |||
var fileTotalSize int64 | |||
fileTotalSize = 0 | |||
if err != nil { | |||
log.Error("getClients failed:", err.Error()) | |||
return fileTotalSize, err | |||
} | |||
delimiter := "" | |||
marker := "" | |||
for { | |||
output, err := core.ListObjects(bucketName, srcPath, marker, delimiter, 1000) | |||
if err == nil { | |||
for _, val := range output.Contents { | |||
srcObjectName := val.Key | |||
destObjectName := destPath + srcObjectName[len(srcPath):] | |||
log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName) | |||
core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, val.UserMetadata) | |||
fileTotalSize += val.Size | |||
} | |||
if output.IsTruncated { | |||
marker = output.NextMarker | |||
} else { | |||
break | |||
} | |||
} else { | |||
log.Info("list error." + err.Error()) | |||
return 0, err | |||
} | |||
} | |||
return fileTotalSize, nil | |||
} | |||
func NewMultiPartUpload(uuid string) (string, error) { | |||
@@ -22,6 +22,7 @@ const ( | |||
type ObjectStorage interface { | |||
Save(path string, r io.Reader) (int64, error) | |||
Open(path string) (io.ReadCloser, error) | |||
DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) | |||
Delete(path string) error | |||
DeleteDir(dir string) error | |||
PresignedGetURL(path string, fileName string) (string, error) | |||
@@ -1452,6 +1452,7 @@ issues.filter_sort.feweststars = Fewest stars | |||
issues.filter_sort.mostforks = Most forks | |||
issues.filter_sort.fewestforks = Fewest forks | |||
issues.filter_sort.downloadtimes = Most downloaded | |||
issues.filter_sort.citations=Citations | |||
issues.filter_sort.mostusecount = Most Quote | |||
issues.filter_sort.fewestusecount=Fewest Quote | |||
issues.action_open = Open | |||
@@ -226,7 +226,7 @@ contributors=贡献者 | |||
contributor=贡献者 | |||
page_title=探索更好的AI | |||
page_small_title=启智AI开发协作平台 | |||
page_small_title=启智AI协作平台 | |||
page_description=面向AI领域的一站式协同开发环境,提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线 | |||
page_use=立即使用 | |||
page_only_dynamic=仅展示开源项目动态 | |||
@@ -1462,9 +1462,11 @@ issues.filter_sort.feweststars=点赞由少到多 | |||
issues.filter_sort.mostforks=派生由多到少 | |||
issues.filter_sort.fewestforks=派生由少到多 | |||
issues.filter_sort.downloadtimes=下载次数 | |||
issues.filter_sort.citations=引用次数 | |||
issues.filter_sort.moststars=收藏数量 | |||
issues.filter_sort.mostusecount=最多引用 | |||
issues.filter_sort.fewestusecount=最少引用 | |||
issues.action_open=开启 | |||
issues.action_close=关闭 | |||
issues.action_label=标签 | |||
@@ -9,7 +9,7 @@ if(isEmpty(token)){ | |||
var swiperNewMessage = new Swiper(".newslist", { | |||
direction: "vertical", | |||
slidesPerView: 10, | |||
slidesPerView: 9, | |||
loop: true, | |||
autoplay: { | |||
delay: 2500, | |||
@@ -17,7 +17,7 @@ var swiperNewMessage = new Swiper(".newslist", { | |||
}, | |||
}); | |||
var swiperEvent = new Swiper(".event-list", { | |||
slidesPerView: 2, | |||
slidesPerView: 3, | |||
spaceBetween: 30, | |||
pagination: { | |||
el: ".swiper-pagination", | |||
@@ -117,6 +117,7 @@ socket.onmessage = function (e) { | |||
continue; | |||
} | |||
} | |||
refresh3DInfo(record); | |||
var recordPrefix = getMsg(record); | |||
if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){ | |||
html += recordPrefix + actionName; | |||
@@ -200,6 +201,29 @@ function getTaskLink(record){ | |||
return re; | |||
} | |||
function refresh3DInfo(record){ | |||
if(record.OpType == "25" || record.OpType == "29" || record.OpType == "31"){ | |||
//cloudbrain one | |||
var lines = $('.rotation3D__line'); | |||
var span = $('.rotation3D__line').find("span")[0]; | |||
//console.log(span); | |||
span.innerText =record.RefName; | |||
//$('.rotation3D__line').find("span").eq(0).text(record.RefName) | |||
//console.log("cloudbrain one line length=" + lines.length); | |||
//lines[0].find("span").text(record.RefName); | |||
}else if(record.OpType == "26" || record.OpType == "27" || record.OpType == "28"){ | |||
//cloudbrain two | |||
var lines = $('.rotation3D__line'); | |||
//console.log("cloudbrain two line length=" + lines.length); | |||
var span = $('.rotation3D__line').find("span")[1]; | |||
//console.log(span); | |||
span.innerText =record.RefName; | |||
//$('.rotation3D__line').find("span").eq(1).text(record.RefName) | |||
//lines[1].find("span").text(record.RefName); | |||
} | |||
} | |||
function getMsg(record){ | |||
var html =""; | |||
html += "<div class=\"swiper-slide item\">"; | |||
@@ -425,13 +449,50 @@ function queryRecommendData(){ | |||
dataType:"json", | |||
async:false, | |||
success:function(json){ | |||
displayOrg(json.org); | |||
displayRepo(json.repo); | |||
displayActivity(json.image) | |||
displayOrg(json.org); | |||
displayRepo(json.repo); | |||
displayActivity(json.image); | |||
displayCloudBrain(json.cloudbrain) | |||
}, | |||
error:function(response) { | |||
} | |||
}); | |||
// $.ajax({ | |||
// type:"GET", | |||
// url:"/recommend/repo", | |||
// headers: { | |||
// authorization:token, | |||
// }, | |||
// dataType:"json", | |||
// async:false, | |||
// success:function(json){ | |||
// displayRepo(json); | |||
// }, | |||
// error:function(response) { | |||
// } | |||
// }); | |||
// $.ajax({ | |||
// type:"GET", | |||
// url:"/recommend/imageinfo", | |||
// headers: { | |||
// authorization:token, | |||
// }, | |||
// dataType:"json", | |||
// async:false, | |||
// success:function(json){ | |||
// displayActivity(json); | |||
// }, | |||
// error:function(response) { | |||
// } | |||
// }); | |||
} | |||
function displayCloudBrain(json){ | |||
$('#completed_task').text(json.completed_task); | |||
$('#running_task').text(json.running_task); | |||
$('#wait_task').text(json.wait_task); | |||
} | |||
function displayActivity(json){ | |||
@@ -573,6 +573,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
//cloudbrain board | |||
m.Group("/cloudbrainboard", func() { | |||
m.Get("/downloadAll", repo.DownloadCloudBrainBoard) | |||
m.Group("/cloudbrain", func() { | |||
m.Get("/status_analysis", repo.GetCloudbrainsStatusAnalysis) | |||
}) | |||
}, operationReq) | |||
// Users | |||
m.Group("/users", func() { | |||
@@ -11,6 +11,16 @@ import ( | |||
"github.com/360EntSecGroup-Skylar/excelize/v2" | |||
) | |||
type CloudbrainsStatusAnalysis struct { | |||
JobWaitingCount int64 `json:"jobWaitingCount"` | |||
JobRunningCount int64 `json:"jobRunningCount"` | |||
JobStoppedCount int64 `json:"jobStoppedCount"` | |||
JobCompletedCount int64 `json:"jobCompletedCount"` | |||
JobFailedCount int64 `json:"jobFailedCount"` | |||
JobKilledCount int64 `json:"jobKilledCount"` | |||
JobInitCount int64 `json:"jobInitCount"` | |||
} | |||
func DownloadCloudBrainBoard(ctx *context.Context) { | |||
page := 1 | |||
@@ -133,3 +143,9 @@ func getBrainWaitTime(rs *models.CloudbrainInfo) string { | |||
return models.ConvertDurationToStr(int64(waitTime)) | |||
} | |||
} | |||
func GetCloudbrainsStatusAnalysis(ctx *context.Context) { | |||
cloudBrainStatusResult := models.GetAllStatusCloudBrain() | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"cloudBrainStatusResult": cloudBrainStatusResult, | |||
}) | |||
} |
@@ -7,6 +7,7 @@ package routers | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
@@ -750,6 +751,15 @@ func GetRankUser(index string) ([]map[string]interface{}, error) { | |||
return resultOrg, nil | |||
} | |||
// func GetImageInfoFromPromote(ctx *context.Context) { | |||
// imageInfo, err := GetImageInfo() | |||
// if err != nil { | |||
// ctx.ServerError("500", err) | |||
// return | |||
// } | |||
// ctx.JSON(200, imageInfo) | |||
// } | |||
func GetUserRankFromPromote(ctx *context.Context) { | |||
index := ctx.Params("index") | |||
resultUserRank, err := GetRankUser(index) | |||
@@ -773,13 +783,36 @@ func RecommendHomeInfo(ctx *context.Context) { | |||
if err != nil { | |||
log.Info("error." + err.Error()) | |||
} | |||
resultCloudBrain, err := getCloudbrainNums() | |||
if err != nil { | |||
log.Info("error." + err.Error()) | |||
} | |||
mapInterface := make(map[string]interface{}) | |||
mapInterface["org"] = resultOrg | |||
mapInterface["repo"] = resultRepo | |||
mapInterface["image"] = resultImage | |||
mapInterface["cloudbrain"] = resultCloudBrain | |||
ctx.JSON(http.StatusOK, mapInterface) | |||
} | |||
func getCloudbrainNums() (map[string]string, error) { | |||
result := make(map[string]string) | |||
cloudStatusMap := models.GetAllStatusCloudBrain() | |||
result["completed_task"] = fmt.Sprint(cloudStatusMap["COMPLETED"]) | |||
result["running_task"] = fmt.Sprint(cloudStatusMap["RUNNING"]) | |||
result["wait_task"] = fmt.Sprint(cloudStatusMap["WAITING"]) | |||
return result, nil | |||
} | |||
// func RecommendOrgFromPromote(ctx *context.Context) { | |||
// resultOrg, err := GetRecommendOrg() | |||
// if err != nil { | |||
// ctx.ServerError("500", err) | |||
// return | |||
// } | |||
// ctx.JSON(200, resultOrg) | |||
// } | |||
func RecommendRepoFromPromote(ctx *context.Context) { | |||
result, err := repository.GetRecommendRepoFromPromote("projects") | |||
if err != nil { | |||
@@ -6,6 +6,7 @@ import ( | |||
"errors" | |||
"fmt" | |||
"net/http" | |||
"net/url" | |||
"path" | |||
"strings" | |||
@@ -27,19 +28,22 @@ const ( | |||
MODEL_NOT_LATEST = 0 | |||
) | |||
func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { | |||
func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error { | |||
aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName) | |||
if err != nil { | |||
log.Info("query task error." + err.Error()) | |||
return err | |||
aiTask, err = models.GetRepoCloudBrainByJobID(ctx.Repo.Repository.ID, jobId) | |||
if err != nil { | |||
log.Info("query task error." + err.Error()) | |||
return err | |||
} else { | |||
log.Info("query gpu train task.") | |||
} | |||
} | |||
uuid := uuid.NewV4() | |||
id := uuid.String() | |||
modelPath := id | |||
var lastNewModelId string | |||
var modelSize int64 | |||
cloudType := models.TypeCloudBrainTwo | |||
log.Info("find task name:" + aiTask.JobName) | |||
aimodels := models.QueryModelByName(name, aiTask.RepoID) | |||
@@ -53,7 +57,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
} | |||
} | |||
} | |||
cloudType = aiTask.Type | |||
cloudType := aiTask.Type | |||
//download model zip //train type | |||
if cloudType == models.TypeCloudBrainTwo { | |||
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl) | |||
@@ -61,6 +65,12 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
log.Info("download model from CloudBrainTwo faild." + err.Error()) | |||
return err | |||
} | |||
} else if cloudType == models.TypeCloudBrainOne { | |||
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl) | |||
if err != nil { | |||
log.Info("download model from CloudBrainOne faild." + err.Error()) | |||
return err | |||
} | |||
} | |||
accuracy := make(map[string]string) | |||
accuracy["F1"] = "" | |||
@@ -131,7 +141,7 @@ func SaveNewNameModel(ctx *context.Context) { | |||
return | |||
} | |||
SaveModel(ctx) | |||
ctx.Status(200) | |||
log.Info("save model end.") | |||
} | |||
@@ -143,8 +153,9 @@ func SaveModel(ctx *context.Context) { | |||
version := ctx.Query("Version") | |||
label := ctx.Query("Label") | |||
description := ctx.Query("Description") | |||
engine := ctx.QueryInt("Engine") | |||
trainTaskCreate := ctx.QueryBool("trainTaskCreate") | |||
log.Info("engine=" + fmt.Sprint(engine)) | |||
if !trainTaskCreate { | |||
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||
//ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
@@ -163,14 +174,14 @@ func SaveModel(ctx *context.Context) { | |||
return | |||
} | |||
err := saveModelByParameters(JobId, VersionName, name, version, label, description, ctx) | |||
err := saveModelByParameters(JobId, VersionName, name, version, label, description, engine, ctx) | |||
if err != nil { | |||
log.Info("save model error." + err.Error()) | |||
ctx.Error(500, fmt.Sprintf("save model error. %v", err)) | |||
return | |||
} | |||
ctx.Status(200) | |||
log.Info("save model end.") | |||
} | |||
@@ -199,6 +210,22 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir | |||
return dataActualPath, size, nil | |||
} | |||
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { | |||
modelActualPath := storage.GetMinioPath(jobName, "/model/") | |||
log.Info("modelActualPath=" + modelActualPath) | |||
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | |||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | |||
bucketName := setting.Attachment.Minio.Bucket | |||
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) | |||
size, err := storage.MinioPathCopy(bucketName, modelSrcPrefix, destKeyNamePrefix) | |||
if err == nil { | |||
dataActualPath := bucketName + "/" + destKeyNamePrefix | |||
return dataActualPath, size, nil | |||
} else { | |||
return "", 0, nil | |||
} | |||
} | |||
func DeleteModel(ctx *context.Context) { | |||
log.Info("delete model start.") | |||
id := ctx.Query("ID") | |||
@@ -277,51 +304,117 @@ func DownloadMultiModelFile(ctx *context.Context) { | |||
} | |||
path := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
if task.Type == models.TypeCloudBrainTwo { | |||
downloadFromCloudBrainTwo(path, task, ctx, id) | |||
} else if task.Type == models.TypeCloudBrainOne { | |||
downloadFromCloudBrainOne(path, task, ctx, id) | |||
} | |||
} | |||
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) | |||
func MinioDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) { | |||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName)) | |||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
w := zip.NewWriter(ctx.Resp) | |||
defer w.Close() | |||
for _, oneFile := range allFile { | |||
if oneFile.IsDir { | |||
log.Info("zip dir name:" + oneFile.FileName) | |||
} else { | |||
log.Info("zip file name:" + oneFile.FileName) | |||
fDest, err := w.Create(oneFile.FileName) | |||
if err != nil { | |||
log.Info("create zip entry error, download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} | |||
log.Info("minio file path=" + (path + oneFile.FileName)) | |||
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, path+oneFile.FileName) | |||
if err != nil { | |||
log.Info("download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} else { | |||
defer body.Close() | |||
p := make([]byte, 1024) | |||
var readErr error | |||
var readCount int | |||
// 读取对象内容 | |||
for { | |||
readCount, readErr = body.Read(p) | |||
if readCount > 0 { | |||
fDest.Write(p[:readCount]) | |||
} | |||
if readErr != nil { | |||
break | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *context.Context, id string) { | |||
allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path) | |||
if err == nil { | |||
//count++ | |||
models.ModifyModelDownloadCount(id) | |||
returnFileName := task.Name + "_" + task.Version + ".zip" | |||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+returnFileName) | |||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
w := zip.NewWriter(ctx.Resp) | |||
defer w.Close() | |||
for _, oneFile := range allFile { | |||
if oneFile.IsDir { | |||
log.Info("zip dir name:" + oneFile.FileName) | |||
MinioDownloadManyFile(path, ctx, returnFileName, allFile) | |||
} else { | |||
log.Info("error,msg=" + err.Error()) | |||
ctx.ServerError("no file to download.", err) | |||
} | |||
} | |||
func ObsDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) { | |||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName)) | |||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
w := zip.NewWriter(ctx.Resp) | |||
defer w.Close() | |||
for _, oneFile := range allFile { | |||
if oneFile.IsDir { | |||
log.Info("zip dir name:" + oneFile.FileName) | |||
} else { | |||
log.Info("zip file name:" + oneFile.FileName) | |||
fDest, err := w.Create(oneFile.FileName) | |||
if err != nil { | |||
log.Info("create zip entry error, download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) | |||
if err != nil { | |||
log.Info("download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} else { | |||
log.Info("zip file name:" + oneFile.FileName) | |||
fDest, err := w.Create(oneFile.FileName) | |||
if err != nil { | |||
log.Info("create zip entry error, download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) | |||
if err != nil { | |||
log.Info("download file failed: %s\n", err.Error()) | |||
ctx.ServerError("download file failed:", err) | |||
return | |||
} else { | |||
defer body.Close() | |||
p := make([]byte, 1024) | |||
var readErr error | |||
var readCount int | |||
// 读取对象内容 | |||
for { | |||
readCount, readErr = body.Read(p) | |||
if readCount > 0 { | |||
fDest.Write(p[:readCount]) | |||
} | |||
if readErr != nil { | |||
break | |||
} | |||
defer body.Close() | |||
p := make([]byte, 1024) | |||
var readErr error | |||
var readCount int | |||
// 读取对象内容 | |||
for { | |||
readCount, readErr = body.Read(p) | |||
if readCount > 0 { | |||
fDest.Write(p[:readCount]) | |||
} | |||
if readErr != nil { | |||
break | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *context.Context, id string) { | |||
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) | |||
if err == nil { | |||
//count++ | |||
models.ModifyModelDownloadCount(id) | |||
returnFileName := task.Name + "_" + task.Version + ".zip" | |||
ObsDownloadManyFile(path, ctx, returnFileName, allFile) | |||
} else { | |||
log.Info("error,msg=" + err.Error()) | |||
ctx.ServerError("no file to download.", err) | |||
@@ -374,42 +467,55 @@ func DownloadSingleModelFile(ctx *context.Context) { | |||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
return | |||
} | |||
if setting.PROXYURL != "" { | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, path) | |||
if err != nil { | |||
log.Info("download error.") | |||
if task.Type == models.TypeCloudBrainTwo { | |||
if setting.PROXYURL != "" { | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, path) | |||
if err != nil { | |||
log.Info("download error.") | |||
} else { | |||
//count++ | |||
models.ModifyModelDownloadCount(id) | |||
defer body.Close() | |||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName) | |||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
p := make([]byte, 1024) | |||
var readErr error | |||
var readCount int | |||
// 读取对象内容 | |||
for { | |||
readCount, readErr = body.Read(p) | |||
if readCount > 0 { | |||
ctx.Resp.Write(p[:readCount]) | |||
//fmt.Printf("%s", p[:readCount]) | |||
} | |||
if readErr != nil { | |||
break | |||
} | |||
} | |||
} | |||
} else { | |||
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) | |||
if err != nil { | |||
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||
ctx.ServerError("GetObsCreateSignedUrl", err) | |||
return | |||
} | |||
//count++ | |||
models.ModifyModelDownloadCount(id) | |||
defer body.Close() | |||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName) | |||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
p := make([]byte, 1024) | |||
var readErr error | |||
var readCount int | |||
// 读取对象内容 | |||
for { | |||
readCount, readErr = body.Read(p) | |||
if readCount > 0 { | |||
ctx.Resp.Write(p[:readCount]) | |||
//fmt.Printf("%s", p[:readCount]) | |||
} | |||
if readErr != nil { | |||
break | |||
} | |||
} | |||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||
} | |||
} else { | |||
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) | |||
} else if task.Type == models.TypeCloudBrainOne { | |||
log.Info("start to down load minio file.") | |||
url, err := storage.Attachments.PresignedGetURL(path, fileName) | |||
if err != nil { | |||
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||
ctx.ServerError("GetObsCreateSignedUrl", err) | |||
log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||
ctx.ServerError("Get minio get SignedUrl failed", err) | |||
return | |||
} | |||
//count++ | |||
models.ModifyModelDownloadCount(id) | |||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||
} | |||
} | |||
func ShowModelInfo(ctx *context.Context) { | |||
@@ -684,14 +790,22 @@ func QueryModelListForPredict(ctx *context.Context) { | |||
func QueryModelFileForPredict(ctx *context.Context) { | |||
id := ctx.Query("ID") | |||
model, err := models.QueryModelById(id) | |||
if err != nil { | |||
if err == nil { | |||
if model.Type == models.TypeCloudBrainTwo { | |||
prefix := model.Path[len(setting.Bucket)+1:] | |||
fileinfos, _ := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} else if model.Type == models.TypeCloudBrainOne { | |||
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] | |||
fileinfos, _ := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, prefix) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} | |||
} else { | |||
log.Error("no such model!", err.Error()) | |||
ctx.ServerError("no such model:", err) | |||
return | |||
} | |||
prefix := model.Path[len(setting.Bucket)+1:] | |||
fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} | |||
func QueryOneLevelModelFile(ctx *context.Context) { | |||
@@ -703,7 +817,16 @@ func QueryOneLevelModelFile(ctx *context.Context) { | |||
ctx.ServerError("no such model:", err) | |||
return | |||
} | |||
prefix := model.Path[len(setting.Bucket)+1:] | |||
fileinfos, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
if model.Type == models.TypeCloudBrainTwo { | |||
log.Info("TypeCloudBrainTwo list model file.") | |||
prefix := model.Path[len(setting.Bucket)+1:] | |||
fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} else if model.Type == models.TypeCloudBrainOne { | |||
log.Info("TypeCloudBrainOne list model file.") | |||
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] | |||
fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir) | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} | |||
} |
@@ -324,7 +324,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
go routers.SocketManager.Run() | |||
m.Get("/action/notification", routers.ActionNotification) | |||
m.Get("/recommend/home", routers.RecommendHomeInfo) | |||
//m.Get("/recommend/org", routers.RecommendOrgFromPromote) | |||
//m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | |||
m.Get("/recommend/userrank/:index", routers.GetUserRankFromPromote) | |||
//m.Get("/recommend/imageinfo", routers.GetImageInfoFromPromote) | |||
m.Post("/all/search/", routers.Search) | |||
m.Get("/all/search/", routers.EmptySearch) | |||
m.Get("/all/dosearch/", routers.SearchApi) | |||
@@ -1093,9 +1096,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) | |||
m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList) | |||
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) | |||
m.Get("/query_model_for_predict", reqRepoCloudBrainReader, repo.QueryModelListForPredict) | |||
m.Get("/query_modelfile_for_predict", reqRepoCloudBrainReader, repo.QueryModelFileForPredict) | |||
m.Get("/query_onelevel_modelfile", reqRepoCloudBrainReader, repo.QueryOneLevelModelFile) | |||
m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict) | |||
m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict) | |||
m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile) | |||
m.Group("/:ID", func() { | |||
m.Get("", repo.ShowSingleModel) | |||
m.Get("/downloadsingle", repo.DownloadSingleModelFile) | |||
@@ -13,6 +13,9 @@ | |||
{{template "base/footer_content" .}} | |||
<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script> | |||
{{if .RequireSimpleMDE}} | |||
<script src="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js"></script> | |||
<script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script> | |||
@@ -43,5 +46,46 @@ | |||
<script src="{{StaticUrlPrefix}}/fomantic/semantic.min.js?v={{MD5 AppVer}}"></script> | |||
<script src="{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}"></script> | |||
{{template "custom/footer" .}} | |||
{{if .PageIsHome}} | |||
<!--script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script--> | |||
<script src="/rotation3D/vue-2.6.10.min.js"></script> | |||
<script src="/rotation3D/rotation3D.js?v={{MD5 AppVer}}"></script> | |||
<script> | |||
var app = new Vue({ | |||
el: "#app", | |||
//数据 blue, green, yellow | |||
data: { | |||
itemList: [ | |||
{ name:'鹏城云脑一号', type:'blue', icon:'', }, | |||
{ name:'鹏城云脑二号', type:'blue', icon:'', }, | |||
{ name:'北大人工智能集群系统', type:'green', icon:'', }, | |||
{ name:'合肥类脑智能开放平台', type:'green', icon:'', }, | |||
{ name:'武汉人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'西安未来人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'……', type:'yellow', icon:'', }, | |||
{ name:'中原人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'成都人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'横琴先进智能计算中心', type:'green', icon:'', }, | |||
{ name:'国家超级计算济南中心', type:'green', icon:'', }, | |||
], | |||
}, | |||
mounted: function () { | |||
new Rotation3D({ | |||
id: '#rotation3D', | |||
farScale: 0.6, | |||
// farScale: 1, | |||
xRadius: 0, //x半径压缩 | |||
yRadius: 130, //y半径压缩 | |||
// yRadius: 0, //y半径压缩 | |||
// autoPlay:true, | |||
// autoPlayDelay:6000, | |||
}) | |||
}, | |||
methods: {}, | |||
}); | |||
</script> | |||
{{end}} | |||
</body> | |||
</html> |
@@ -192,6 +192,8 @@ var _hmt = _hmt || []; | |||
<!-- Swiper --> | |||
<link rel="stylesheet" href="/swiper/swiper-bundle.min.css"> | |||
<script src="/swiper/swiper-bundle.min.js"></script> | |||
<!-- rotation3D --> | |||
<link rel="stylesheet" href="/rotation3D/rotation3D.css"> | |||
</head> | |||
<body> | |||
{{template "custom/body_outer_pre" .}} | |||
@@ -34,7 +34,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<div class="ui dropdown item" id='dropdown_explore'> | |||
<div class="ui simple dropdown item" id='dropdown_explore'> | |||
{{.i18n.Tr "explore"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
@@ -65,7 +65,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<div class="ui dropdown item" id='dropdown_PageHome'> | |||
<div class="ui simple dropdown item" id='dropdown_PageHome'> | |||
{{.i18n.Tr "explore"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu" > | |||
@@ -120,7 +120,7 @@ | |||
</span> | |||
</a> | |||
<div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted"> | |||
<div class="ui simple dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted"> | |||
<span class="text"> | |||
<span class="fitted">{{svg "octicon-plus" 16}}</span> | |||
<span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span> | |||
@@ -141,7 +141,7 @@ | |||
</div><!-- end content create new menu --> | |||
</div><!-- end dropdown menu create new --> | |||
<div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted"> | |||
<div class="ui simple dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted"> | |||
<span class="text"> | |||
<img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}"> | |||
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span> | |||
@@ -186,7 +186,7 @@ | |||
src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}} | |||
{{if $.IsSigned}} | |||
<span | |||
style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;font-size: 12px;font-weight: normal;flex: 1;" | |||
style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;font-size: 12px;font-weight: normal;flex: 1;margin-left: 1.5rem;" | |||
@click.stop="postSquareStar({{.ID}},'{{.Repo.Link}}/datasets',{{$k}})"> | |||
<div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;"> | |||
@@ -256,12 +256,14 @@ | |||
<span | |||
style="color: #999999;font-size: 12px;margin-left: 0.5rem;">{{TimeSinceUnixShort .CreatedUnix}}</span> | |||
<span | |||
style="display: flex;align-items: center;justify-content: center;margin: 0 1rem;"> | |||
style="display: flex;align-items: center;justify-content: center;margin: 0 1rem;" | |||
title="{{$.i18n.Tr "repo.issues.filter_sort.citations"}}"> | |||
<i class="ri-link"></i> | |||
<span | |||
style="color: #101010; font-size: 12px;margin-left: 0.2rem;">{{.UseCount}}</span> | |||
</span> | |||
<span style=" display: flex;align-items: center;justify-content: center;"> | |||
<span style=" display: flex;align-items: center;justify-content: center;" | |||
title='{{$.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}'> | |||
<i class="ri-download-line"></i> | |||
<span | |||
style="color: #101010;font-size: 12px;margin-left: 0.2rem;">{{.DownloadTimes}}</span> | |||
@@ -1,6 +1,6 @@ | |||
{{template "base/head_home" .}} | |||
<div class="ui vertical masthead secondary hometop segment"> | |||
<div class="ui container" style="position: relative;"> | |||
<div class="ui container" style="position: relative;"> | |||
<div class="ui center homebanner"> | |||
<h1 class="ui huge header"> | |||
{{.page_title}} | |||
@@ -17,7 +17,7 @@ | |||
{{end}} | |||
</div> | |||
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div> | |||
<div id="homenews" class="ui container"> | |||
<div id="homenews"> | |||
<p>* {{.page_only_dynamic}}</p> | |||
<div class="ui grid"> | |||
<div class="sixteen wide mobile twelve wide tablet ten wide computer column homenews"> | |||
@@ -35,33 +35,32 @@ | |||
<!--组织--> | |||
<div class="ui container homeorg"> | |||
<div class="ui stackable grid"> | |||
<div class="ui stackable grid"> | |||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
<h2>{{.page_recommend_activity}}</h2> | |||
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p> | |||
<h2>{{.page_recommend_org}}</h2> | |||
<p><span class="ui text grey">{{.page_recommend_org_desc}} </span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p> | |||
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a> | |||
</div> | |||
<div class="sixteen wide tablet twelve wide computer column"> | |||
<div class="event-list"> | |||
<div class="swiper-wrapper" id="recommendactivity"> | |||
<div class="homeorg-list"> | |||
<div class="swiper-wrapper" id="recommendorg"> | |||
</div> | |||
<div class="swiper-pagination"></div> | |||
</div> | |||
</div> | |||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
<h2>{{.page_recommend_org}}</h2> | |||
<p><span class="ui text grey">{{.page_recommend_org_desc}} </span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p> | |||
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a> | |||
<h2>{{.page_recommend_activity}}</h2> | |||
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p> | |||
</div> | |||
<div class="sixteen wide tablet twelve wide computer column"> | |||
<div class="homeorg-list"> | |||
<div class="swiper-wrapper" id="recommendorg"> | |||
<div class="event-list"> | |||
<div class="swiper-wrapper" id="recommendactivity"> | |||
</div> | |||
<div class="swiper-pagination"></div> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -87,56 +86,112 @@ | |||
</div> | |||
<div class="ui vertical masthead secondary c2net segment"> | |||
<div class="ui container"> | |||
<div class="ui center am-pt-30 am-pb-30"> | |||
<h2>智算网络</h2> | |||
<p><span class="ui text grey">人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P</p> | |||
</div> | |||
<div id="app" v-cloak> | |||
<!--数据 | |||
<div class="aiData"> | |||
<p>完成AI任务<br><strong id="completed_task">1716</strong></p> | |||
<p>运行AI任务<br><strong id="running_task">120</strong></p> | |||
<p>等待AI任务<br><strong id="wait_task">80</strong></p> | |||
</div>--> | |||
<!--底座--> | |||
<div class="rotation3D-baseMap"></div> | |||
<!--旋转3D--> | |||
<div id="rotation3D" class="rotation3D"> | |||
<button class="center">中心</button> | |||
<div class="itemList"> | |||
<div class="rotation3D__item" :class="item.type" v-for="item in itemList"> | |||
<div class="scale"> | |||
<div class="baseImg"></div> | |||
<div class="cont"> | |||
<i class="iconfont" :class="item.icon"></i> | |||
<p></p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="lineList"> | |||
<div class="rotation3D__line" v-for="item in itemList" :class="item.type"> | |||
<div v-if="item.type=='blue'" class="pos"> | |||
<svg width="50" height="400"> | |||
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot1 ri-arrow-left-s-line"><span></span></div> | |||
</div> | |||
<div v-if="item.type=='yellow'" class="pos"> | |||
<svg width="10" height="400"> | |||
<path id="path2" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot2"><i class="el-icon-close"></i></div> | |||
</div> | |||
<div v-if="item.type=='green'" class="pos"> | |||
<svg width="50" height="400"> | |||
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot1 ri-arrow-left-s-line"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div><!--rotation3D end--> | |||
</div> | |||
</div> | |||
<a name="fourth"></a> | |||
<div class="ui container i-env"> | |||
<div class="ui center am-pb-30"> | |||
<div class="leftline03"></div> | |||
<h2>{{.page_dev_env}}</h2> | |||
<p><span class="ui text grey">{{.page_dev_env_desc}}</p> | |||
</div> | |||
<div class="ui four doubling cards"> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-01.svg"> | |||
<img src="/img/i-pic-01.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">{{.page_dev_env_desc_title}}</h3> | |||
<div class="description"> | |||
<div class="description ui text grey"> | |||
{{.page_dev_env_desc_desc}} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-02.svg"> | |||
<img src="/img/i-pic-02.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">{{.page_dev_env_desc1_title}}</h3> | |||
<div class="description"> | |||
<div class="description ui text grey"> | |||
{{.page_dev_env_desc1_desc}} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-03.svg"> | |||
<img src="/img/i-pic-03.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">{{.page_dev_env_desc2_title}}</h3> | |||
<div class="description"> | |||
<div class="description ui text grey"> | |||
{{.page_dev_env_desc2_desc}} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-04.svg"> | |||
<img src="/img/i-pic-04.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">{{.page_dev_env_desc3_title}}</h3> | |||
<div class="description"> | |||
<div class="description ui text grey"> | |||
{{.page_dev_env_desc3_desc}} | |||
</div> | |||
</div> | |||
@@ -172,8 +227,8 @@ | |||
</div> | |||
</div> | |||
<div class="am-mt-30"></div> | |||
<script src="/self/js/jquery.min.js" type="text/javascript"></script> | |||
<script src="/home/home.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||
<script src="/self/js/jquery.min.js" type="text/javascript"></script> | |||
<script src="/home/home.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||
{{template "base/footer" .}} |
@@ -152,7 +152,7 @@ | |||
</div> | |||
<div class="inline field"> | |||
<div class="ui checkbox" id="auto-init"> | |||
<input class="hidden" name="auto_agree" type="checkbox" checked="checked"> | |||
<input class="hidden" name="auto_agree" type="checkbox"> | |||
<label | |||
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}} | |||
<a href="/home/term/">{{.i18n.Tr "repo.openi_use_agreement"}}</a></label> | |||
@@ -130,6 +130,19 @@ | |||
<label>模型版本</label> | |||
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255"> | |||
</div> | |||
<div class="unite min_title inline field required"> | |||
<label>模型框架</label> | |||
<div class="ui dropdown selection search width70" id="choice_Engine"> | |||
<input type="hidden" id="Engine" name="Engine" required> | |||
<div class="default text">选择模型框架</div> | |||
<i class="dropdown icon"></i> | |||
<div class="menu" id="job-Engine"> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="inline field"> | |||
<label>模型标签</label> | |||
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | |||
@@ -161,7 +174,7 @@ | |||
let repoId = {{$repository}} | |||
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
$('input[name="_csrf"]').val(csrf) | |||
let modelData; | |||
function createModelName(){ | |||
let repoName = location.pathname.split('/')[2] | |||
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4) | |||
@@ -185,6 +198,7 @@ | |||
document.getElementById("formId").reset(); | |||
$('#choice_model').dropdown('clear') | |||
$('#choice_version').dropdown('clear') | |||
$('#choice_Engine').dropdown('clear') | |||
$('.ui.dimmer').css({"background-color":""}) | |||
$('.ui.error.message').text() | |||
$('.ui.error.message').css('display','none') | |||
@@ -197,10 +211,24 @@ | |||
$(function(){ | |||
$('#choice_model').dropdown({ | |||
onChange:function(value){ | |||
$(".ui.dropdown.selection.search.width70").addClass("loading") | |||
$('#choice_version').dropdown('clear') | |||
$("#job-version").empty() | |||
loadTrainVersion(value) | |||
$(".ui.dropdown.selection.search.width70").addClass("loading") | |||
$('#choice_version').dropdown('clear') | |||
$("#job-version").empty() | |||
loadTrainVersion(value) | |||
} | |||
}) | |||
$('#choice_version').dropdown({ | |||
onChange:function(value){ | |||
console.log("model version:" + value); | |||
if(modelData != null){ | |||
for(var i=0; i < modelData.length;i++){ | |||
if(modelData[i].VersionName == value){ | |||
setEngine(modelData[i]) | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
}) | |||
}) | |||
@@ -240,7 +268,8 @@ | |||
let JobID = !value ?$('#choice_model input[name="JobId"]').val(): value | |||
$.get(`${repolink}/modelmanage/query_train_job_version?JobID=${JobID}`, (data) => { | |||
const n_length = data.length | |||
let train_html='' | |||
let train_html=''; | |||
modelData = data; | |||
for (let i=0;i<n_length;i++){ | |||
train_html += `<div class="item" data-value="${data[i].VersionName}">${data[i].VersionName}</div>` | |||
train_html += '</div>' | |||
@@ -248,11 +277,59 @@ | |||
if(data.length){ | |||
$("#job-version").append(train_html) | |||
$(".ui.dropdown.selection.search.width70").removeClass("loading") | |||
$('#choice_version .default.text').text(data[0].VersionName) | |||
$('#choice_version input[name="VersionName"]').val(data[0].VersionName) | |||
var versionName = data[0].VersionName; | |||
if(versionName==null || versionName==""){ | |||
versionName="V0001"; | |||
} | |||
$('#choice_version .default.text').text(versionName) | |||
$('#choice_version input[name="VersionName"]').val(versionName) | |||
console.log("1111111111"); | |||
setEngine(data[0]) | |||
} | |||
}) | |||
} | |||
function setEngine(modelVersion){ | |||
console.log("modelVersion=" + modelVersion); | |||
$('#choice_Engine').dropdown('clear') | |||
$("#job-Engine").empty() | |||
if(modelVersion.EngineName != null && modelVersion.EngineName != ""){ | |||
srcEngine = modelVersion.EngineName.split('-')[0] | |||
srcEngine = srcEngine.trim(); | |||
let selectedText = "Pytorch"; | |||
let selectedValue = 0; | |||
let itemHtml = "<option class=\"item\" data-value=\"0\">Pytorch</option>"; | |||
if(srcEngine =='TensorFlow'){ | |||
selectedText ="TensorFlow"; | |||
selectedValue = 1; | |||
itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>"; | |||
}else{ | |||
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"; | |||
} | |||
if(srcEngine =='MindSpore'){ | |||
selectedText ="MindSpore"; | |||
selectedValue = 2; | |||
itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>"; | |||
}else{ | |||
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"; | |||
} | |||
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | |||
$('#choice_Engine .default.text').text(selectedText) | |||
$('#choice_Engine input[name="Engine"]').val(selectedValue) | |||
$("#job-Engine").append(itemHtml); | |||
$("#choice_Engine").addClass('disabled') | |||
}else{ | |||
let itemHtml = "<option class=\"active item\" data-value=\"0\">Pytorch</option>"; | |||
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>" | |||
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>" | |||
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" | |||
$('#choice_Engine .default.text').text("Pytorch"); | |||
$('#choice_Engine input[name="Engine"]').val(0) | |||
$("#job-Engine").append(itemHtml); | |||
$("#choice_Engine").removeClass('disabled'); | |||
} | |||
} | |||
</script> | |||
@@ -10,9 +10,9 @@ | |||
{{.i18n.Tr "home.wecome_AI_plt"}} | |||
</div> | |||
<div class="content"> | |||
<p >{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p> | |||
<p >{{.i18n.Tr "home.use_plt__fuction"}} <a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p> | |||
<p > {{.i18n.Tr "home.provide_resoure"}}</p> | |||
<p class="ui text grey">{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p> | |||
<p><span class="ui text grey">{{.i18n.Tr "home.use_plt__fuction"}}</span> <a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p> | |||
<p class="ui text grey">{{.i18n.Tr "home.provide_resoure"}}</p> | |||
</div> | |||
<div class="guide "> | |||
<a class="mini ui blue basic button" style="font-weight:700" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}} <i class="ri-arrow-right-line" ></i></a> | |||
@@ -66,19 +66,12 @@ | |||
} | |||
.w_title{ | |||
padding-top: 25px; | |||
margin-bottom: 20px; | |||
color: rgba(16, 16, 16, 100); | |||
font-size: 20px; | |||
text-align: left; | |||
font-weight: 700; | |||
} | |||
.content{ | |||
color: rgba(80, 85, 89, 100); | |||
font-size: 14px; | |||
text-align: left; | |||
font-family: SourceHanSansSC-regular; | |||
margin-top: 20px; | |||
} | |||
.guide{ | |||
margin-top:30px; | |||
padding-bottom: 30px; | |||
@@ -6,7 +6,7 @@ | |||
<div class="ui grid"> | |||
<div class="ui fourteen wide column"> | |||
<div class="{{if or (eq .GetOpType 5) (eq .GetOpType 18)}}push news{{end}}"> | |||
<p> | |||
<p class="text truncate"> | |||
{{if gt .ActUser.ID 0}} | |||
<a href="{{AppSubUrl}}/{{.GetActUserName}}" title="{{.GetDisplayNameTitle}}">{{.GetDisplayName}}</a> | |||
{{else}} | |||
@@ -168,7 +168,7 @@ export default { | |||
tableData= res.data | |||
for(let i=0;i<tableData.length;i++){ | |||
TrainTaskInfo = JSON.parse(tableData[i].TrainTaskInfo) | |||
tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0] | |||
tableData[i].EngineName = this.getEngineName(tableData[i]) | |||
tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||
tableData[i].cName=tableData[i].Name | |||
tableData[i].Name='' | |||
@@ -218,6 +218,7 @@ export default { | |||
$('input[name="Name"]').removeAttr('readonly') | |||
$('#choice_model').dropdown('clear') | |||
$('#choice_version').dropdown('clear') | |||
$('#choice_Engine').dropdown('clear') | |||
$('.ui.dimmer').css({"background-color":""}) | |||
$('.ui.error.message').text() | |||
$('.ui.error.message').css('display','none') | |||
@@ -347,6 +348,18 @@ export default { | |||
}) | |||
.modal('show') | |||
}, | |||
getEngineName(model){ | |||
if(model.Engine == 0){ | |||
return "Pytorch"; | |||
}else if(model.Engine == 1 || model.Engine == 121){ | |||
return "TensorFlow"; | |||
}else if(model.Engine == 2 || model.Engine == 122){ | |||
return "MindSpore"; | |||
}else{ | |||
return "Other" | |||
} | |||
}, | |||
getModelList(){ | |||
try { | |||
this.$refs.table.store.states.lazyTreeNodeMap = {} | |||
@@ -360,7 +373,7 @@ export default { | |||
for(let i=0;i<this.tableData.length;i++){ | |||
TrainTaskInfo = JSON.parse(this.tableData[i].TrainTaskInfo) | |||
this.tableData[i].cName=this.tableData[i].Name | |||
this.tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0] | |||
this.tableData[i].EngineName = this.getEngineName(this.tableData[i]) | |||
this.tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||
this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true | |||
} | |||
@@ -82,6 +82,10 @@ | |||
line-height: 1.2; | |||
p { | |||
max-width: 100%; | |||
} | |||
> .ui.grid { | |||
margin-left: auto; | |||
margin-right: auto; | |||