#5269 合并自定义镜像功能一些Bug到主分支中

Merged
ychao_1983 merged 14 commits from zouap_dev into V20240129 2 months ago
  1. +25
    -0
      models/cloudbrain_image.go
  2. +7
    -1
      routers/admin/resources.go
  3. +9
    -0
      routers/api/v1/repo/images.go
  4. +3
    -0
      routers/routes/routes.go
  5. +33
    -2
      web_src/js/components/images/adminImages.vue
  6. +8
    -2
      web_src/js/features/i18nVue.js
  7. +45
    -28
      web_src/vuepages/components/cloudbrain/ImageSelectV1.vue
  8. +1
    -0
      web_src/vuepages/langs/config/en-US.js
  9. +2
    -1
      web_src/vuepages/langs/config/zh-CN.js
  10. +1
    -1
      web_src/vuepages/pages/images/square/components/Condition.vue
  11. +2
    -2
      web_src/vuepages/pages/images/square/components/Item.vue
  12. +6
    -3
      web_src/vuepages/pages/images/submit/index.vue

+ 25
- 0
models/cloudbrain_image.go View File

@@ -112,6 +112,11 @@ type SearchAvailableValueOptions struct {
Framework string
FrameworkVersion string
PythonVersion string
ComputeResource string
OnlyRecommend bool
IncludeOwnerOnly bool
IncludeStarByMe bool
UID int64
}

type SearchImageOptions struct {
@@ -487,6 +492,26 @@ func GetImageAvailableColumnValues(opts *SearchAvailableValueOptions) []string {
if opts.PythonVersion != "" {
cond = cond.And(builder.Eq{"python_version": opts.PythonVersion})
}
if opts.ComputeResource != "" {
cond = cond.And(builder.Eq{"compute_resource": opts.ComputeResource})
}
if opts.OnlyRecommend {
cond = cond.And(builder.Eq{"type": RECOMMOND_TYPE})
}
if opts.IncludeOwnerOnly {

cond = cond.And(builder.Eq{"uid": opts.UID})
}

if opts.IncludeStarByMe {

subQuery := builder.Select("image_id").From("image_star").
Where(builder.Eq{"uid": opts.UID})
var starCond = builder.In("id", subQuery)
cond = cond.And(starCond)

}

cond = cond.And(builder.NotNull{opts.Column})

var columnValues []string


+ 7
- 1
routers/admin/resources.go View File

@@ -123,9 +123,15 @@ func SyncGrampusQueue(ctx *context.Context) {
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
err = resource.SyncGrampusImage(ctx.User.ID)
ctx.JSON(http.StatusOK, response.Success())
}

func SyncGrampusImage(ctx *context.Context) {
err := resource.SyncGrampusImage(ctx.User.ID)
if err != nil {
log.Error("sync image error. %v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
ctx.JSON(http.StatusOK, response.Success())
}


+ 9
- 0
routers/api/v1/repo/images.go View File

@@ -99,6 +99,10 @@ func GetAvailableFilerInfo(ctx *context.APIContext) {
frameWork := ctx.Query("framework")
version := ctx.Query("version")
pythonVersion := ctx.Query("python")
compute_resource := ctx.Query("compute_resource")
onlyRecommend := ctx.QueryBool("recommend")
includeMineOnly := ctx.QueryBool("mine")
starByMe := ctx.QueryBool("star")
if i < 0 || i >= len(columns) {
i = 0
}
@@ -109,6 +113,11 @@ func GetAvailableFilerInfo(ctx *context.APIContext) {
Framework: frameWork,
FrameworkVersion: version,
PythonVersion: pythonVersion,
ComputeResource: compute_resource,
OnlyRecommend: onlyRecommend,
IncludeOwnerOnly: includeMineOnly,
IncludeStarByMe: starByMe,
UID: getUID(ctx),
}
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{
Data: models.GetImageAvailableColumnValues(opts),


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

@@ -748,6 +748,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/add", binding.Bind(models.ResourceSceneReq{}), admin.AddResourceScene)
m.Post("/update/:id", binding.BindIgnErr(models.ResourceSceneReq{}), admin.UpdateResourceScene)
})
m.Group("/image", func() {
m.Post("/sync", admin.SyncGrampusImage)
})
})
m.Group("/ai_model", func() {
m.Post("/update_version", repo.UpdateAllModelMeta)


+ 33
- 2
web_src/js/components/images/adminImages.vue View File

@@ -86,8 +86,11 @@
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="ui six wide column right aligned" style="margin: 1rem 0;">
<a class="ui blue small button" href="/admin/images/commit_image">{{
<div class="ui six wide column right aligned" style="margin:1rem 0;display: flex;align-items:center;
justify-content:flex-end;">
<el-button size="medium" icon="el-icon-refresh" @click="syncComputerNetwork" v-loading="syncLoading">
{{ $i18n['cloudeBrainMirror']['syncAiNetwork'] }}</el-button>
<a class="ui blue small button" style="margin-left:10px" href="/admin/images/commit_image">{{
$i18n['cloudeBrainMirror']['create_cloud_brain_mirror'] }}</a>
</div>
<div class="ui sixteen wide column" style="padding: 0;overflow-x:auto;">
@@ -311,6 +314,8 @@ export default {
reasonDialogTitle: '',
reasonDialogContent: '',
reasonDialogData: null,

syncLoading: false,
};
},
methods: {
@@ -370,6 +375,32 @@ export default {
eidtImage(id) {
location.href = `/image/${id}/imageAdmin?${qs.stringify(this.paramsCustom)}`
},
syncComputerNetwork() {
this.syncLoading = true;
this.$axios.post(`/admin/resources/image/sync?_csrf=${csrf}`).then(res => {
this.syncLoading = false;
res = res.data;
if (res.Code === 0) {
this.$message({
type: 'success',
message: this.$i18n['submittedSuccessfully']
});
this.getImageListCustom()
} else {
this.$message({
type: 'error',
message: this.$i18n['submittedFailed']
});
}
}).catch(err => {
console.log(err);
this.syncLoading = false;
this.$message({
type: 'error',
message: this.$i18n['submittedFailed']
});
});
},
imageStar(index, id, isStar) {
if (isStar) {
this.$axios.put(`/image/${id}/action/unstar`).then((res) => {


+ 8
- 2
web_src/js/features/i18nVue.js View File

@@ -147,13 +147,15 @@ export const i18nVue = {
notRemind: '不再提醒',
close: '关闭',
warmPrompt: '温馨提示',
submittedSuccessfully: '提交成功!',
submittedFailed: '提交失败!',

cloudeBrainMirror: {
cloud_brain_mirror: '云脑镜像',
public_mirror: '公开镜像',
recommendImages: '平台推荐镜像',
platform_recommendations:'仅显示平台推荐',
placeholder: '搜镜像Tag/描述/标签...',
placeholder: '搜镜像Tag/描述/操作系统/安装的软件包/标签...',
search:'搜索',
mirror_tag:'镜像Tag',
mirror_description:'镜像描述',
@@ -179,6 +181,7 @@ export const i18nVue = {
cancel_recommendation: '取消推荐',
set_as_recommended: '设为推荐',
create_cloud_brain_mirror: '创建云脑镜像',
syncAiNetwork: '同步智算网络',
openi: '启智',
c2net: '智算网络',
defaultsort: '默认排序',
@@ -391,13 +394,15 @@ export const i18nVue = {
notRemind: 'Don\'t remind again',
close: 'Close',
warmPrompt: 'Tips',
submittedSuccessfully: 'Submitted Successfully!',
submittedFailed: 'Submitted Failed!',

cloudeBrainMirror: {
cloud_brain_mirror: 'Cloud Brain Mirror',
public_mirror: 'Public Mirror',
recommendImages: 'Recommend Mirror',
platform_recommendations:'Show platform recommendations only',
placeholder: 'Search Mirror tag / description / label ... ',
placeholder: 'Search Mirror tag/description/operating system/python library/label...',
search:'Search',
mirror_tag:'Mirror Tag',
mirror_description:'Mirror Description ',
@@ -423,6 +428,7 @@ export const i18nVue = {
cancel_recommendation: 'Cancel recommendation',
set_as_recommended: 'Set as recommended',
create_cloud_brain_mirror: 'Create cloud brain mirror',
syncAiNetwork: 'Sync C2Net Network',
openi: 'OpenI',
c2net: 'C²NET',
defaultsort: 'Default Sort',


+ 45
- 28
web_src/vuepages/components/cloudbrain/ImageSelectV1.vue View File

@@ -142,20 +142,44 @@ export default {
lazy: true,
lazyLoad: (node, resolve) => {
const { level } = node;
const framework = node.path[0];
const version = node.path[1];
const python = node.path[2];
getImageAvailabelFilter({ index: level, framework, version, python }).then(res => {
const path = node.path || [];
const framework = path[0];
const version = path[1];
const python = path[2];
getImageAvailabelFilter({
index: level,
framework,
version,
python,
compute_resource: this.configs.computerResouce,
recommend: this.dlgActiveName == 'first' ? true : undefined,
mine: this.dlgActiveName == 'second' ? true : undefined,
star: this.dlgActiveName == 'third' ? true : undefined,
}).then(res => {
if (res.data.code == 0) {
const nodes = (res.data.data).map(item => ({
value: item,
label: item ? item : 'None',
leaf: level >= (this.configs.computerResouce == 'GPU' ? 3 : 2)
}));
if (!nodes.length) {
node.config.leaf = true;
if (level == 0) {
let data = res.data.data || [];
if (data.indexOf('Other') >= 0) {
data = data.filter(item => item !== 'Other');
data.push('Other');
}
const nodes = data.map(item => ({
value: item,
label: item,
leaf: item == 'Other' ? true : false,
}));
resolve(nodes);
} else {
const nodes = (res.data.data).map(item => ({
value: item,
label: item ? item : 'None',
leaf: level >= (this.configs.computerResouce == 'GPU' ? 3 : 2)
}));
if (!nodes.length) {
node.config.leaf = true;
}
resolve(nodes);
}
resolve(nodes);
} else {
resolve([]);
}
@@ -212,6 +236,7 @@ export default {
dlgTabClick(tab, event) {
this.dlgTotal = 0;
this.dlgPage = 1;
this.resetDlgCascaderFilter();
this.searchImageData();
},
search() {
@@ -219,6 +244,11 @@ export default {
this.dlgPage = 1;
this.searchImageData();
},
resetDlgCascaderFilter() {
this.dlgCascaderFilter.value = [];
this.dlgCascaderFilter.options = [];
this.handleDlgCascaderFilterExpandChange([]);
},
handleDlgCascaderFilterVisibleChange() {
const popper = document.querySelector(`.${this.dlgCascaderFilter.popperClass}`);
if (popper && popper.querySelector('.popper-filter-title')) return;
@@ -243,7 +273,9 @@ export default {
},
handleDlgCascaderFilterExpandChange(value) {
const popper = document.querySelector(`.${this.dlgCascaderFilter.popperClass}`);
if (!popper) return;
const title = popper.querySelector('.popper-filter-title');
if (!title) return;
const items = title.querySelectorAll('.popper-filter-title-item');
items.forEach((item, index) => {
const style = item.style;
@@ -344,22 +376,7 @@ export default {
},
},
beforeMount() {
getImageAvailabelFilter({ index: 0 }).then(res => {
if (res.data.code == 0) {
let data = res.data.data || [];
if (data.indexOf('Other') >= 0) {
data = data.filter(item => item !== 'Other');
data.push('Other');
}
this.dlgCascaderFilter.options = data.map(item => ({
value: item,
label: item,
leaf: item == 'Other' ? true : false,
}));
}
}).catch(err => {
console.log(err);
})
this.resetDlgCascaderFilter();
},
mounted() { },
};


+ 1
- 0
web_src/vuepages/langs/config/en-US.js View File

@@ -585,6 +585,7 @@ const en = {
recentupdate: "Recently updated",
leastupdate: "Least recently updated",
moststars: "Collection Nums",
mostCollections: "Most Stars",
mostusecount: "Most Quote",
sort: "Sort",
unstarSuccess: "Cancel favorite successfully!",


+ 2
- 1
web_src/vuepages/langs/config/zh-CN.js View File

@@ -498,7 +498,7 @@ const zh = {
cloudbrain_images: '云脑镜像',
openIGPU: '启智GPU',
c2netGPU: '智算GPU',
images_search: '搜镜像Tag/描述/操作系统/安装的软件包/标签',
images_search: '搜镜像Tag/描述/操作系统/安装的软件包/标签...',
image_public: '平台推荐镜像',
image_my: '我的镜像',
image_collected: '我收藏的镜像',
@@ -600,6 +600,7 @@ const zh = {
recentupdate: "最近更新",
leastupdate: "最少更新",
moststars: "收藏数量",
mostCollections: "最多收藏",
mostusecount: "最多引用",
sort: "排序",
unstarSuccess: "取消收藏成功!",


+ 1
- 1
web_src/vuepages/pages/images/square/components/Condition.vue View File

@@ -35,7 +35,7 @@ const SortList = [{
label: i18n.t('datasets.default'),
}, {
key: 'moststars',
label: i18n.t('datasets.moststars'),
label: i18n.t('datasets.mostCollections'),
}, {
key: 'mostused',
label: i18n.t('datasets.mostusecount'),


+ 2
- 2
web_src/vuepages/pages/images/square/components/Item.vue View File

@@ -84,7 +84,7 @@
<span v-if="data.status === 1">{{ $t('imagesObj.commitSuccess') }}</span>
<span v-if="data.status === 2">{{ $t('imagesObj.commitFailed') }}</span>
</span>
<span class="apply-status">
<span class="apply-status" v-if="condition.tab == 1">
<div v-if="data.status === 1">
<div v-if="data.apply_status === 2" style="display: flex;align-items:center;justify-content:center;">
<el-tooltip effect="dark" :content="$t('imagesObj.recommendNeedReview')" placement="top">
@@ -117,7 +117,7 @@
<i class="ri-rocket-2-line" style="margin-right:0;"></i>
<span>{{ $t('imagesObj.applyForRecommend') }}</span>
</a>
<a v-if="condition.tab == 1" class="btn-op" href="javascript:void(0);" @click="edit(data)">
<a v-if="condition.tab == 1 && data.apply_status != 3" class="btn-op" href="javascript:void(0);" @click="edit(data)">
<i class="el-icon-edit-outline"></i>
<span>{{ $t('modelManage.edit') }}</span>
</a>


+ 6
- 3
web_src/vuepages/pages/images/submit/index.vue View File

@@ -73,7 +73,7 @@
<div v-show="frameworkVersionList.length" class="content"
:class="errors.framework_version ? 'error' : ''">
<el-select class="field-input" v-model="form.framework_version"
@change="checkNull('framework_version')">
@change="checkNull('framework_version')" filterable>
<el-option v-for="item in frameworkVersionList" :key="item.k" :value="item.k"
:label="item.v"></el-option>
</el-select>
@@ -83,7 +83,7 @@
<div class="form-row">
<div class="title"><span class="required">{{ $t('imagesObj.pyVersion') }}</span></div>
<div class="content" :class="errors.python ? 'error' : ''">
<el-select class="field-input" v-model="form.python" @change="checkNull('python')">
<el-select class="field-input" v-model="form.python" @change="checkNull('python')" filterable>
<el-option v-for="item in pythonList" :key="item.k" :value="item.k" :label="item.v"></el-option>
</el-select>
</div>
@@ -91,7 +91,7 @@
<div class="form-row" v-if="form.compute_resource == 'GPU'">
<div class="title"><span class="required">{{ $t('imagesObj.cudaVersion') }}</span></div>
<div class="content" :class="errors.cuda ? 'error' : ''">
<el-select class="field-input" v-model="form.cuda" @change="checkNull('cuda')">
<el-select class="field-input" v-model="form.cuda" @change="checkNull('cuda')" filterable>
<el-option v-for="item in cudaList" :key="item.k" :value="item.k" :label="item.v"></el-option>
</el-select>
</div>
@@ -311,6 +311,7 @@ export default {
submit() {
let hasError = false;
for (let key in this.errors) {
this.form[key] = this.form[key].trim();
let isError = false;
if (this.pageType == 'submit' && key == 'place') continue;
if (key == 'place' && this.form.compute_resource != 'GPU') continue;
@@ -323,6 +324,8 @@ export default {
} else if (key == 'cuda') {
if (this.form.compute_resource == 'GPU') {
isError = this.checkNull(key);
} else {
this.form.cuda = '';
}
} else {
isError = this.checkNull(key);


Loading…
Cancel
Save