mirror of
https://github.com/XShengTech/MEGREZ.git
synced 2026-05-03 13:02:38 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fc2c3ec09 | |||
| 011827f5c7 | |||
| 69554b5e39 | |||
| a24fb8e8ad | |||
| 42de9caf52 | |||
| 5780f84714 | |||
| de8c601be9 | |||
| e283a626a1 | |||
| 37ba1baf71 | |||
| 81b52e80b5 | |||
| 13bd350274 |
@@ -46,7 +46,7 @@
|
|||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> 部署仓库: [XShengTech/MEGREZ-Deploy](https://github.com/XShengTech/MEGREZ-Deploy)
|
> 部署仓库: [XShengTech/MEGREZ-Deploy](https://github.com/XShengTech/MEGREZ-Deploy)
|
||||||
>
|
>
|
||||||
> 查看文档 [**>>> 🚧 正在施工中 <<<**]()
|
> 查看文档 [**>>> MEGREZ 文档 <<<**](http://docs.megrez.xsheng-ai.com/)
|
||||||
|
|
||||||
|
|
||||||
## 📌 效果展示
|
## 📌 效果展示
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
| VSCode 网页版 | Jupyter Notebook | Grafana 资源监控 |
|
| VSCode 网页版 | Jupyter Notebook | Grafana 资源监控 |
|
||||||
| ---------------------------------------------------- | ----------------------------------------------- | -------------------------------- |
|
| ---------------------------------------------------- | ----------------------------------------------- | -------------------------------- |
|
||||||
|  |  |  |
|
|  |  |  |
|
||||||
|
|
||||||
### 系统管理
|
### 系统管理
|
||||||
|
|
||||||
|
|||||||
@@ -56,15 +56,9 @@ const model = ref([
|
|||||||
{
|
{
|
||||||
label: '使用文档',
|
label: '使用文档',
|
||||||
icon: 'pi pi-fw pi-book text-amber-500',
|
icon: 'pi pi-fw pi-book text-amber-500',
|
||||||
url: '#',
|
url: 'http://docs.megrez.xsheng-ai.com/guide/usage/',
|
||||||
target: '_blank'
|
target: '_blank'
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// label: '开源信息',
|
|
||||||
// icon: 'pi pi-fw pi-cog',
|
|
||||||
// url: 'https://github.com/primefaces/sakai-vue',
|
|
||||||
// target: '_blank'
|
|
||||||
// },
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -4,10 +4,36 @@ const layoutConfig = reactive({
|
|||||||
preset: 'Aura',
|
preset: 'Aura',
|
||||||
primary: 'blue',
|
primary: 'blue',
|
||||||
surface: null,
|
surface: null,
|
||||||
darkTheme: false,
|
darkTheme: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches,
|
||||||
menuMode: 'static'
|
menuMode: 'static'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for changes to the prefers-color-scheme media query
|
||||||
|
if (window.matchMedia) {
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||||
|
layoutConfig.darkTheme = e.matches;
|
||||||
|
toggleDarkMode();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleDarkMode = () => {
|
||||||
|
if (!document.startViewTransition) {
|
||||||
|
executeDarkModeToggle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.startViewTransition(() => executeDarkModeToggle(event));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layoutConfig.darkTheme) {
|
||||||
|
toggleDarkMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
const executeDarkModeToggle = () => {
|
||||||
|
layoutConfig.darkTheme = !layoutConfig.darkTheme;
|
||||||
|
document.documentElement.classList.toggle('app-dark');
|
||||||
|
};
|
||||||
|
|
||||||
const layoutState = reactive({
|
const layoutState = reactive({
|
||||||
staticMenuDesktopInactive: false,
|
staticMenuDesktopInactive: false,
|
||||||
overlayMenuActive: false,
|
overlayMenuActive: false,
|
||||||
@@ -39,21 +65,6 @@ export function useLayout() {
|
|||||||
layoutConfig.menuMode = mode;
|
layoutConfig.menuMode = mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleDarkMode = () => {
|
|
||||||
if (!document.startViewTransition) {
|
|
||||||
executeDarkModeToggle();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.startViewTransition(() => executeDarkModeToggle(event));
|
|
||||||
};
|
|
||||||
|
|
||||||
const executeDarkModeToggle = () => {
|
|
||||||
layoutConfig.darkTheme = !layoutConfig.darkTheme;
|
|
||||||
document.documentElement.classList.toggle('app-dark');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMenuToggle = () => {
|
const onMenuToggle = () => {
|
||||||
if (layoutConfig.menuMode === 'overlay') {
|
if (layoutConfig.menuMode === 'overlay') {
|
||||||
layoutState.overlayMenuActive = !layoutState.overlayMenuActive;
|
layoutState.overlayMenuActive = !layoutState.overlayMenuActive;
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-slate-600">记起密码?<span
|
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-slate-600">记起密码?<span
|
||||||
class="text-primary" @click="handleLogin">立即登入</span></span>
|
class="text-primary" @click="handleLogin">立即登入</span></span>
|
||||||
</div>
|
</div>
|
||||||
<Button label="发送邮件" class="w-full" @click="handleSubmit"></Button>
|
<Button v-if="!requesting" label="发送邮件" class="w-full" @click="handleSubmit"></Button>
|
||||||
|
<Button v-else label="发送中" icon="pi pi-spin pi-spinner" disabled class="w-full"></Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,16 +41,20 @@ import { useRouter } from 'vue-router';
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
|
const requesting = ref(false)
|
||||||
const form = ref({
|
const form = ref({
|
||||||
email: ''
|
email: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
|
requesting.value = true
|
||||||
api.UserForgetRequest(form.value).then(res => {
|
api.UserForgetRequest(form.value).then(res => {
|
||||||
toast.add({ severity: 'success', summary: '发送成功', detail: '请查看邮箱', life: 3000 })
|
toast.add({ severity: 'success', summary: '发送成功', detail: '请查看邮箱', life: 3000 })
|
||||||
|
requesting.value = false
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
toast.add({ severity: 'error', summary: '发送失败', detail: '请检查后重新尝试', life: 3000 })
|
toast.add({ severity: 'error', summary: '发送失败', detail: '请检查后重新尝试', life: 3000 })
|
||||||
|
requesting.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-slate-600">记起密码?<span
|
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-slate-600">记起密码?<span
|
||||||
class="text-primary" @click="handleLogin">立即登入</span></span>
|
class="text-primary" @click="handleLogin">立即登入</span></span>
|
||||||
</div>
|
</div>
|
||||||
<Button label="注册" class="w-full" @click="handleSubmit"></Button>
|
<Button label="重置密码" class="w-full" @click="handleSubmit"></Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -121,13 +121,13 @@
|
|||||||
</Fieldset>
|
</Fieldset>
|
||||||
<Fieldset legend="GPU">
|
<Fieldset legend="GPU">
|
||||||
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.gpu_type }} * {{ instanceDetail.gpu_count
|
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.gpu_type }} * {{ instanceDetail.gpu_count
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-else>无卡模式</span>
|
<span v-else>无卡模式</span>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
<div class="flex flex-col md:flex-row gap-4">
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
<Fieldset class="flex flex-wrap gap-2 w-full" legend="CPU">
|
<Fieldset class="flex flex-wrap gap-2 w-full" legend="CPU">
|
||||||
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.cpu_count_per_gpu * instanceDetail.gpu_count
|
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.cpu_count_per_gpu * instanceDetail.gpu_count
|
||||||
}}
|
}}
|
||||||
核</span>
|
核</span>
|
||||||
<span v-else>1 核</span>
|
<span v-else>1 核</span>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
@@ -498,6 +498,9 @@ const instanceModify = async () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getInstances()
|
getInstances()
|
||||||
}, 100);
|
}, 100);
|
||||||
|
if (instanceConfiguration.value.cpu_only) {
|
||||||
|
delete instanceConfiguration.value.gpu_count
|
||||||
|
}
|
||||||
await api.AdminInstancesModify(instanceDetail.value.id, instanceConfiguration.value).then(async (res) => {
|
await api.AdminInstancesModify(instanceDetail.value.id, instanceConfiguration.value).then(async (res) => {
|
||||||
toast.add({ severity: 'success', summary: '调整配置', detail: '已调整配置', life: 3000 });
|
toast.add({ severity: 'success', summary: '调整配置', detail: '已调整配置', life: 3000 });
|
||||||
instanceModifyVisible.value = false
|
instanceModifyVisible.value = false
|
||||||
|
|||||||
@@ -125,13 +125,13 @@
|
|||||||
</Fieldset>
|
</Fieldset>
|
||||||
<Fieldset legend="GPU">
|
<Fieldset legend="GPU">
|
||||||
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.gpu_type }} * {{ instanceDetail.gpu_count
|
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.gpu_type }} * {{ instanceDetail.gpu_count
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-else>无卡模式</span>
|
<span v-else>无卡模式</span>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
<div class="flex flex-col md:flex-row gap-4">
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
<Fieldset class="flex flex-wrap gap-2 w-full" legend="CPU">
|
<Fieldset class="flex flex-wrap gap-2 w-full" legend="CPU">
|
||||||
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.cpu_count_per_gpu * instanceDetail.gpu_count
|
<span v-if="instanceDetail.gpu_count !== 0">{{ instanceDetail.cpu_count_per_gpu * instanceDetail.gpu_count
|
||||||
}}
|
}}
|
||||||
核</span>
|
核</span>
|
||||||
<span v-else>1 核</span>
|
<span v-else>1 核</span>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
@@ -501,6 +501,9 @@ const instanceModify = async () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getInstances()
|
getInstances()
|
||||||
}, 100);
|
}, 100);
|
||||||
|
if (instanceConfiguration.value.cpu_only) {
|
||||||
|
delete instanceConfiguration.value.gpu_count
|
||||||
|
}
|
||||||
await api.UserInstancesModify(instanceDetail.value.id, instanceConfiguration.value).then(async (res) => {
|
await api.UserInstancesModify(instanceDetail.value.id, instanceConfiguration.value).then(async (res) => {
|
||||||
toast.add({ severity: 'success', summary: '调整配置', detail: '已调整配置', life: 3000 });
|
toast.add({ severity: 'success', summary: '调整配置', detail: '已调整配置', life: 3000 });
|
||||||
instanceModifyVisible.value = false
|
instanceModifyVisible.value = false
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func EmailFormat(email string) bool {
|
func EmailFormat(email string) bool {
|
||||||
pattern := `^\w+(-+.\w+)*@\w+(-.\w+)*.\w+(-.\w+)*$`
|
pattern := `\w[-\w.+]*@([-A-Za-z0-9]+\.)+[A-Za-z]{2,14}`
|
||||||
match, err := regexp.MatchString(pattern, email)
|
match, err := regexp.MatchString(pattern, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
l.SetModel("main")
|
||||||
l.Info("Branch: %s", BRANCH)
|
l.Info("Branch: %s", BRANCH)
|
||||||
l.Info("Version: %s", VERSION)
|
l.Info("Version: %s", VERSION)
|
||||||
l.Info("Commit: %s", COMMIT)
|
l.Info("Commit: %s", COMMIT)
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ func modifyHandler(ctx iris.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.CpuOnly {
|
||||||
|
req.GpuCount = nil
|
||||||
|
}
|
||||||
|
|
||||||
if req.GpuCount != nil {
|
if req.GpuCount != nil {
|
||||||
if *req.GpuCount < 0 {
|
if *req.GpuCount < 0 {
|
||||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||||
@@ -62,7 +66,17 @@ func modifyHandler(ctx iris.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.CpuOnly == instance.CpuOnly && req.CpuOnly {
|
hasChanges := false
|
||||||
|
if req.CpuOnly != instance.CpuOnly {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if req.GpuCount != nil && *req.GpuCount != instance.GpuCount {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if req.VolumeSize != nil && *req.VolumeSize != instance.VolumeSize {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if !hasChanges {
|
||||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ func modifyHandler(ctx iris.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.CpuOnly {
|
||||||
|
req.GpuCount = nil
|
||||||
|
}
|
||||||
|
|
||||||
if req.GpuCount != nil {
|
if req.GpuCount != nil {
|
||||||
if *req.GpuCount < 0 {
|
if *req.GpuCount < 0 {
|
||||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||||
@@ -68,7 +72,17 @@ func modifyHandler(ctx iris.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.CpuOnly == instance.CpuOnly && req.CpuOnly {
|
hasChanges := false
|
||||||
|
if req.CpuOnly != instance.CpuOnly {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if req.GpuCount != nil && *req.GpuCount != instance.GpuCount {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if req.VolumeSize != nil && *req.VolumeSize != instance.VolumeSize {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if !hasChanges {
|
||||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,19 @@ func modify(serverID uint, data Data) (err error) {
|
|||||||
return errors.New("instance status error")
|
return errors.New("instance status error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.CpuOnly == instance.CpuOnly && data.CpuOnly {
|
hasChanges := false
|
||||||
lc.Error("instance already cpu_only mode")
|
if data.CpuOnly != instance.CpuOnly {
|
||||||
return errors.New("instance already cpu_only mode")
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if data.GpuCount != nil && *data.GpuCount != instance.GpuCount {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if data.VolumeSize != nil && *data.VolumeSize != instance.VolumeSize {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
if !hasChanges {
|
||||||
|
lc.Error("no changes")
|
||||||
|
return errors.New("no changes")
|
||||||
}
|
}
|
||||||
|
|
||||||
oldVolumeSize := instance.VolumeSize
|
oldVolumeSize := instance.VolumeSize
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func createInstance(ip string, port int, apikey string,
|
|||||||
if config.GetSystemMountDir() != "" {
|
if config.GetSystemMountDir() != "" {
|
||||||
data.Binds = append(data.Binds, bindStruct{
|
data.Binds = append(data.Binds, bindStruct{
|
||||||
Src: config.GetSystemMountDir(),
|
Src: config.GetSystemMountDir(),
|
||||||
Dest: "/root/megrez-pub",
|
Dest: "/root/megrez-mnt",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ func patchGpu(ip string, port int, apikey string,
|
|||||||
Dest: "/root/megrez-tmp",
|
Dest: "/root/megrez-tmp",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
data.GpuPatch = &gpuPatchStruct{
|
||||||
|
GpuCount: gpuCount,
|
||||||
|
}
|
||||||
|
data.CpuPatch = &cpuPatchStruct{
|
||||||
|
CpuCount: cpuCountPerGpu * gpuCount,
|
||||||
|
}
|
||||||
|
data.MemoryPatch = &MemoryPatchStruct{
|
||||||
|
Memory: strconv.Itoa(memoryPerGpu*gpuCount) + "GB",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBytes, err := json.Marshal(data)
|
reqBytes, err := json.Marshal(data)
|
||||||
|
|||||||
Reference in New Issue
Block a user