mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-11-06 16:05:21 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
726fd94e07 | ||
|
|
95f12c16c3 | ||
|
|
7a40ef9725 | ||
|
|
ea31289da3 |
+2
-12
@@ -4,8 +4,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/service"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/accelerator"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -21,20 +19,12 @@ func (b *BaseApi) LoadModelGPUDevices(c *gin.Context) {
|
||||
// @Security Timestamp
|
||||
// @Router /ai/gpu/load [get]
|
||||
func (b *BaseApi) LoadGpuInfo(c *gin.Context) {
|
||||
ok, client := accelerator.New()
|
||||
if ok {
|
||||
snapshot, err := client.Collect(c.Request.Context())
|
||||
info, err := service.LoadGPUInfo(c.Request.Context(), c.Query("refresh") == "true")
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
if warning := snapshot.Warning(); warning != nil {
|
||||
global.LOG.Warnf("load realtime accelerator data partially failed, err: %v", warning)
|
||||
}
|
||||
helper.SuccessWithData(c, &snapshot.Info)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, &accelerator.Info{})
|
||||
helper.SuccessWithData(c, info)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/accelerator"
|
||||
)
|
||||
|
||||
type GPURealtimeInfo struct {
|
||||
accelerator.Info
|
||||
Environment GPUEnvironment `json:"environment"`
|
||||
Summaries []GPUSummary `json:"summaries"`
|
||||
}
|
||||
|
||||
type GPUEnvironment struct {
|
||||
CheckedAt time.Time `json:"checkedAt"`
|
||||
HardwareStatus string `json:"hardwareStatus"`
|
||||
Checks []GPUEnvironmentCheck `json:"checks"`
|
||||
}
|
||||
|
||||
type GPUEnvironmentCheck struct {
|
||||
Vendor string `json:"vendor"`
|
||||
Item string `json:"item"`
|
||||
Status string `json:"status"`
|
||||
Code string `json:"code,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type GPUSummary struct {
|
||||
Vendor string `json:"vendor"`
|
||||
DriverVersion string `json:"driverVersion"`
|
||||
CudaVersion string `json:"cudaVersion"`
|
||||
CardCount *int `json:"cardCount"`
|
||||
MemoryTotal *float64 `json:"memoryTotal"`
|
||||
SharedMemoryTotal *float64 `json:"sharedMemoryTotal"`
|
||||
MemoryPartial bool `json:"memoryPartial"`
|
||||
}
|
||||
@@ -192,6 +192,18 @@ func (u *DockerService) LoadDockerStatus() *dto.DockerStatus {
|
||||
return &data
|
||||
}
|
||||
|
||||
func readDockerDaemonConfig() (map[string]interface{}, error) {
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
daemonMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(file, &daemonMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return daemonMap, nil
|
||||
}
|
||||
|
||||
func (u *DockerService) LoadDockerConf() (*dto.DaemonJsonConf, error) {
|
||||
ctx := context.Background()
|
||||
var data dto.DaemonJsonConf
|
||||
@@ -210,18 +222,11 @@ func (u *DockerService) LoadDockerConf() (*dto.DaemonJsonConf, error) {
|
||||
if strings.Contains(stdout2, "Swarm: active") {
|
||||
data.IsSwarm = true
|
||||
}
|
||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
||||
return &data, nil
|
||||
}
|
||||
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||
daemonMap, err := readDockerDaemonConfig()
|
||||
if err != nil {
|
||||
return &data, nil
|
||||
}
|
||||
var conf daemonJsonItem
|
||||
daemonMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(file, &daemonMap); err != nil {
|
||||
return &data, nil
|
||||
}
|
||||
arr, err := json.Marshal(daemonMap)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/accelerator"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/gpu"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/npu"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/xpu"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
)
|
||||
|
||||
const gpuEnvironmentCacheKey = "gpu:environment"
|
||||
|
||||
var gpuEnvironmentLock = make(chan struct{}, 1)
|
||||
|
||||
var gpuVendors = []string{"nvidia", "intel", "ascend", "amd"}
|
||||
|
||||
type gpuEnvironmentProbe struct {
|
||||
CheckedAt time.Time `json:"checkedAt"`
|
||||
Hardware map[string]int `json:"hardware"`
|
||||
HardwareError string `json:"hardwareError,omitempty"`
|
||||
Commands map[string]bool `json:"commands"`
|
||||
NVIDIAChecked bool `json:"nvidiaChecked"`
|
||||
Checks []dto.GPUEnvironmentCheck `json:"checks"`
|
||||
}
|
||||
|
||||
func LoadGPUInfo(ctx context.Context, refresh bool) (*dto.GPURealtimeInfo, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
snapshot := &accelerator.Snapshot{}
|
||||
var collectErr error
|
||||
if available, client := accelerator.New(); available {
|
||||
collected, err := client.Collect(ctx)
|
||||
collectErr = err
|
||||
if collected != nil {
|
||||
snapshot = collected
|
||||
}
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if collectErr != nil {
|
||||
snapshot.Info.Warnings = append(snapshot.Info.Warnings, collectErr.Error())
|
||||
}
|
||||
if snapshot.Info.CollectedAt.IsZero() {
|
||||
snapshot.Info.CollectedAt = time.Now()
|
||||
}
|
||||
if global.LOG != nil {
|
||||
for _, warning := range snapshot.Info.Warnings {
|
||||
global.LOG.Warnf("load realtime accelerator data: %s", warning)
|
||||
}
|
||||
}
|
||||
summaries := summarizeGPUs(snapshot)
|
||||
nvidiaPresent := slices.ContainsFunc(summaries, func(item dto.GPUSummary) bool { return item.Vendor == "nvidia" })
|
||||
probe := loadGPUEnvironmentProbe(ctx, refresh, nvidiaPresent)
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
environment := assembleGPUEnvironment(probe, summaries, collectErr, snapshot.Info)
|
||||
for _, check := range environment.Checks {
|
||||
if check.Item == "driver" && check.Vendor != "" && !slices.ContainsFunc(summaries, func(item dto.GPUSummary) bool { return item.Vendor == check.Vendor }) {
|
||||
summaries = append(summaries, dto.GPUSummary{Vendor: check.Vendor, MemoryPartial: true})
|
||||
}
|
||||
}
|
||||
return &dto.GPURealtimeInfo{Info: snapshot.Info, Environment: environment, Summaries: summaries}, nil
|
||||
}
|
||||
|
||||
func loadGPUEnvironmentProbe(ctx context.Context, refresh, nvidiaPresent bool) gpuEnvironmentProbe {
|
||||
select {
|
||||
case gpuEnvironmentLock <- struct{}{}:
|
||||
defer func() { <-gpuEnvironmentLock }()
|
||||
case <-ctx.Done():
|
||||
return gpuEnvironmentProbe{CheckedAt: time.Now(), HardwareError: ctx.Err().Error()}
|
||||
}
|
||||
if !refresh && global.CACHE != nil {
|
||||
var cached gpuEnvironmentProbe
|
||||
if value := global.CACHE.Get(gpuEnvironmentCacheKey); value != "" && json.Unmarshal([]byte(value), &cached) == nil && (!nvidiaPresent || cached.NVIDIAChecked) {
|
||||
return cached
|
||||
}
|
||||
}
|
||||
probe := gpuEnvironmentProbe{CheckedAt: time.Now(), Commands: map[string]bool{}}
|
||||
var err error
|
||||
probe.Hardware, err = detectGPUHardware("/sys/bus/pci/devices")
|
||||
if err != nil {
|
||||
probe.HardwareError = err.Error()
|
||||
}
|
||||
for vendor := range gpu.ManagementCommands() {
|
||||
probe.Commands[vendor] = true
|
||||
}
|
||||
probe.Commands["intel"], _ = xpu.New()
|
||||
probe.Commands["ascend"], _ = npu.New()
|
||||
if nvidiaPresent || probe.Hardware["nvidia"] > 0 {
|
||||
probe.NVIDIAChecked = true
|
||||
probe.Checks = checkNVIDIAContainerEnvironment(ctx)
|
||||
}
|
||||
if ctx.Err() == nil && global.CACHE != nil {
|
||||
if data, err := json.Marshal(probe); err == nil {
|
||||
global.CACHE.SetWithTTL(gpuEnvironmentCacheKey, string(data), time.Minute)
|
||||
}
|
||||
}
|
||||
return probe
|
||||
}
|
||||
|
||||
func detectGPUHardware(directory string) (map[string]int, error) {
|
||||
devices := map[string]int{}
|
||||
entries, err := os.ReadDir(directory)
|
||||
if err != nil {
|
||||
return devices, err
|
||||
}
|
||||
var readErrors []string
|
||||
for _, entry := range entries {
|
||||
path := filepath.Join(directory, entry.Name())
|
||||
vendorData, err := os.ReadFile(filepath.Join(path, "vendor"))
|
||||
if err != nil {
|
||||
readErrors = append(readErrors, err.Error())
|
||||
continue
|
||||
}
|
||||
vendor := map[string]string{"0x10de": "nvidia", "0x8086": "intel", "0x19e5": "ascend", "0x1002": "amd"}[strings.ToLower(strings.TrimSpace(string(vendorData)))]
|
||||
if vendor == "" {
|
||||
continue
|
||||
}
|
||||
classData, err := os.ReadFile(filepath.Join(path, "class"))
|
||||
if err != nil {
|
||||
readErrors = append(readErrors, err.Error())
|
||||
continue
|
||||
}
|
||||
class, err := strconv.ParseUint(strings.TrimSpace(string(classData)), 0, 32)
|
||||
if err != nil {
|
||||
readErrors = append(readErrors, fmt.Sprintf("read PCI class for %s: %v", entry.Name(), err))
|
||||
continue
|
||||
}
|
||||
baseClass := class >> 16
|
||||
if (vendor == "ascend" && baseClass == 0x12) || (vendor != "ascend" && (baseClass == 0x03 || (vendor == "nvidia" && baseClass == 0x12))) {
|
||||
devices[vendor]++
|
||||
}
|
||||
}
|
||||
if len(readErrors) > 0 {
|
||||
return devices, fmt.Errorf("PCI inventory incomplete: %s", strings.Join(readErrors, "; "))
|
||||
}
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func assembleGPUEnvironment(probe gpuEnvironmentProbe, summaries []dto.GPUSummary, collectErr error, info accelerator.Info) dto.GPUEnvironment {
|
||||
result := dto.GPUEnvironment{CheckedAt: probe.CheckedAt, HardwareStatus: "not_detected", Checks: []dto.GPUEnvironmentCheck{}}
|
||||
if len(probe.Hardware) > 0 || len(summaries) > 0 {
|
||||
result.HardwareStatus = "detected"
|
||||
} else if probe.HardwareError != "" {
|
||||
result.HardwareStatus = "unknown"
|
||||
}
|
||||
for _, vendor := range gpuVendors {
|
||||
index := slices.IndexFunc(summaries, func(item dto.GPUSummary) bool { return item.Vendor == vendor })
|
||||
if index < 0 && probe.Hardware[vendor] == 0 && !(probe.HardwareError != "" && probe.Commands[vendor] && collectErr != nil) {
|
||||
continue
|
||||
}
|
||||
check := dto.GPUEnvironmentCheck{Vendor: vendor, Item: "driver", Status: "unknown"}
|
||||
switch {
|
||||
case index >= 0:
|
||||
check.Status = "passed"
|
||||
check.Version = summaries[index].DriverVersion
|
||||
if vendor == "intel" {
|
||||
var readErrors []string
|
||||
for _, device := range info.XPUs {
|
||||
if device.ReadError != "" {
|
||||
readErrors = append(readErrors, device.ReadError)
|
||||
}
|
||||
}
|
||||
if len(readErrors) > 0 {
|
||||
check.Status = "unknown"
|
||||
if len(readErrors) == len(info.XPUs) {
|
||||
check.Status = "failed"
|
||||
}
|
||||
check.Reason = strings.Join(readErrors, "; ")
|
||||
}
|
||||
}
|
||||
case !probe.Commands[vendor]:
|
||||
check.Status = "missing"
|
||||
check.Reason = "The device management utility was not found; check the driver and management tool installation."
|
||||
case collectErr != nil:
|
||||
check.Status = "failed"
|
||||
check.Reason = collectErr.Error()
|
||||
default:
|
||||
check.Reason = "The management utility returned no readable devices."
|
||||
if len(info.Warnings) > 0 {
|
||||
check.Status = "failed"
|
||||
check.Reason = strings.Join(info.Warnings, "; ")
|
||||
}
|
||||
}
|
||||
result.Checks = append(result.Checks, check)
|
||||
}
|
||||
result.Checks = append(result.Checks, probe.Checks...)
|
||||
if probe.HardwareError != "" {
|
||||
result.Checks = append(result.Checks, dto.GPUEnvironmentCheck{Item: "driver", Status: "unknown", Reason: probe.HardwareError})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func findGPUContainerCommand(name string) string {
|
||||
for _, path := range []string{name, filepath.Join("/usr/bin", name), filepath.Join("/usr/sbin", name), filepath.Join("/usr/local/bin", name), filepath.Join("/usr/local/sbin", name), filepath.Join("/usr/local/nvidia/toolkit", name)} {
|
||||
if cmd.Which(path) {
|
||||
return path
|
||||
}
|
||||
if filepath.IsAbs(path) {
|
||||
if info, err := os.Stat(path); err == nil && !info.IsDir() {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func checkNVIDIAContainerEnvironment(ctx context.Context) []dto.GPUEnvironmentCheck {
|
||||
toolkitCtx, cancelToolkit := context.WithTimeout(ctx, 5*time.Second)
|
||||
toolkit := checkNVIDIAToolkit(toolkitCtx, findGPUContainerCommand, func(ctx context.Context, path string) (string, error) {
|
||||
return cmd.NewCommandMgr(cmd.WithContext(ctx), cmd.WithTimeout(3*time.Second)).RunWithStdout(path, "--version")
|
||||
})
|
||||
cancelToolkit()
|
||||
dockerCtx, cancelDocker := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancelDocker()
|
||||
dockerCheck := dto.GPUEnvironmentCheck{Vendor: "nvidia", Item: "docker", Status: "failed"}
|
||||
cli, err := docker.NewDockerClient()
|
||||
if err == nil {
|
||||
defer cli.Close()
|
||||
var info system.Info
|
||||
info, err = cli.Info(dockerCtx)
|
||||
if err == nil {
|
||||
dockerCheck = checkNVIDIADockerInfo(info, false)
|
||||
if cli.DaemonHost() == "unix:///var/run/docker.sock" {
|
||||
dockerCheck = checkNVIDIADockerConfig(info, readDockerDaemonConfig, findGPUContainerCommand)
|
||||
} else {
|
||||
dockerCheck.Status = "unknown"
|
||||
dockerCheck.Reason = "The selected Docker daemon's NVIDIA runtime cannot be verified using local executables or the default daemon.json."
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
dockerCheck.Reason = err.Error()
|
||||
}
|
||||
return []dto.GPUEnvironmentCheck{toolkit, dockerCheck}
|
||||
}
|
||||
|
||||
func checkNVIDIAToolkit(ctx context.Context, findCommand func(string) string, runVersion func(context.Context, string) (string, error)) dto.GPUEnvironmentCheck {
|
||||
toolkit := dto.GPUEnvironmentCheck{Vendor: "nvidia", Item: "toolkit", Status: "missing"}
|
||||
cli := findCommand("nvidia-container-cli")
|
||||
if cli == "" {
|
||||
toolkit.Reason = "The required nvidia-container-cli component was not found."
|
||||
return toolkit
|
||||
}
|
||||
runtime := findCommand("nvidia-container-runtime")
|
||||
if runtime == "" {
|
||||
runtime = findCommand("nvidia-container-runtime-hook")
|
||||
}
|
||||
if runtime == "" {
|
||||
toolkit.Reason = "The NVIDIA container runtime and runtime hook were not found."
|
||||
return toolkit
|
||||
}
|
||||
data, err := runVersion(ctx, cli)
|
||||
if err != nil || strings.TrimSpace(data) == "" {
|
||||
toolkit.Status = "failed"
|
||||
toolkit.Reason = "nvidia-container-cli returned an empty version."
|
||||
if err != nil {
|
||||
toolkit.Reason = err.Error()
|
||||
}
|
||||
return toolkit
|
||||
}
|
||||
toolkit.Status = "passed"
|
||||
toolkit.Version = strings.SplitN(strings.TrimSpace(data), "\n", 2)[0]
|
||||
if data, err := runVersion(ctx, runtime); err != nil || strings.TrimSpace(data) == "" {
|
||||
toolkit.Status = "failed"
|
||||
toolkit.Reason = "The NVIDIA container runtime returned an empty version."
|
||||
if err != nil {
|
||||
toolkit.Reason = err.Error()
|
||||
}
|
||||
return toolkit
|
||||
}
|
||||
return toolkit
|
||||
}
|
||||
|
||||
func checkNVIDIADockerInfo(info system.Info, hookInstalled bool) dto.GPUEnvironmentCheck {
|
||||
result := dto.GPUEnvironmentCheck{Vendor: "nvidia", Item: "docker", Status: "unconfigured", Version: info.ServerVersion}
|
||||
if _, ok := info.Runtimes["nvidia"]; ok {
|
||||
result.Status = "passed"
|
||||
return result
|
||||
}
|
||||
if hookInstalled {
|
||||
result.Status = "unknown"
|
||||
result.Reason = "NVIDIA runtime hook is installed, but Docker does not expose its GPU device-driver registration."
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func checkNVIDIADockerConfig(info system.Info, readConfig func() (map[string]interface{}, error), findCommand func(string) string) dto.GPUEnvironmentCheck {
|
||||
result := checkNVIDIADockerInfo(info, false)
|
||||
if result.Status == "passed" {
|
||||
runtimePath := info.Runtimes["nvidia"].Path
|
||||
if runtimePath == "" {
|
||||
result.Status = "unknown"
|
||||
result.Reason = "Docker registered an NVIDIA runtime without an executable path; its availability cannot be verified."
|
||||
return result
|
||||
}
|
||||
resolved := runtimePath
|
||||
if !filepath.IsAbs(runtimePath) {
|
||||
resolved = findCommand(runtimePath)
|
||||
}
|
||||
if resolved == "" || !cmd.Which(resolved) {
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigInvalid"
|
||||
result.Reason = fmt.Sprintf("The registered NVIDIA runtime %q cannot be found or executed.", runtimePath)
|
||||
}
|
||||
return result
|
||||
}
|
||||
if hook := findCommand("nvidia-container-runtime-hook"); hook != "" && cmd.Which(hook) {
|
||||
result = checkNVIDIADockerInfo(info, true)
|
||||
}
|
||||
config, err := readConfig()
|
||||
if err != nil {
|
||||
var syntaxError *json.SyntaxError
|
||||
var typeError *json.UnmarshalTypeError
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
if result.Status == "unknown" {
|
||||
return result
|
||||
}
|
||||
result.Code = "dockerConfigMissing"
|
||||
result.Reason = fmt.Sprintf("Docker configuration %s is missing; configure runtimes.nvidia.path and restart Docker.", constant.DaemonJsonPath)
|
||||
case errors.As(err, &syntaxError), errors.As(err, &typeError):
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigInvalid"
|
||||
result.Reason = fmt.Sprintf("Cannot parse Docker configuration %s: %v", constant.DaemonJsonPath, err)
|
||||
default:
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigUnreadable"
|
||||
result.Reason = fmt.Sprintf("Cannot read Docker configuration %s: %v", constant.DaemonJsonPath, err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
if config == nil {
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigInvalid"
|
||||
result.Reason = "Docker configuration must be a JSON object."
|
||||
return result
|
||||
}
|
||||
runtimes, ok := config["runtimes"].(map[string]interface{})
|
||||
if config["runtimes"] == nil || (ok && runtimes["nvidia"] == nil) {
|
||||
if result.Status == "unknown" {
|
||||
return result
|
||||
}
|
||||
result.Code = "dockerConfigMissing"
|
||||
result.Reason = fmt.Sprintf("Docker configuration %s has no runtimes.nvidia entry.", constant.DaemonJsonPath)
|
||||
return result
|
||||
}
|
||||
nvidia, ok := runtimes["nvidia"].(map[string]interface{})
|
||||
runtimePath, pathOK := nvidia["path"].(string)
|
||||
if !ok || !pathOK || strings.TrimSpace(runtimePath) == "" || (!filepath.IsAbs(runtimePath) && filepath.Base(runtimePath) != runtimePath) {
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigInvalid"
|
||||
result.Reason = "runtimes.nvidia.path must contain a runtime executable name or absolute path."
|
||||
return result
|
||||
}
|
||||
resolved := findCommand(runtimePath)
|
||||
if resolved == "" || !cmd.Which(resolved) {
|
||||
result.Status = "failed"
|
||||
result.Code = "dockerConfigInvalid"
|
||||
result.Reason = fmt.Sprintf("The configured NVIDIA runtime %q cannot be found or executed.", runtimePath)
|
||||
return result
|
||||
}
|
||||
result.Status = "unconfigured"
|
||||
result.Code = "dockerConfigPending"
|
||||
result.Reason = "The default daemon.json contains runtimes.nvidia.path, but the running Docker daemon has not registered the NVIDIA runtime; confirm the daemon uses this configuration file, then restart Docker and check again."
|
||||
return result
|
||||
}
|
||||
|
||||
func summarizeGPUs(snapshot *accelerator.Snapshot) []dto.GPUSummary {
|
||||
result := []dto.GPUSummary{}
|
||||
for _, vendor := range gpuVendors {
|
||||
summary := dto.GPUSummary{Vendor: vendor}
|
||||
cards, chips := map[string]bool{}, map[string]bool{}
|
||||
var versions []string
|
||||
for _, device := range snapshot.Devices {
|
||||
deviceVendor := device.Vendor
|
||||
if device.XPU != nil {
|
||||
deviceVendor = "intel"
|
||||
}
|
||||
if deviceVendor != vendor || device.ParentID != "" || chips[device.ID] {
|
||||
continue
|
||||
}
|
||||
chips[device.ID] = true
|
||||
cardID := device.ID
|
||||
if device.NPU != nil {
|
||||
cardID = strconv.Itoa(device.NPUIndex)
|
||||
}
|
||||
cards[cardID] = true
|
||||
if device.DriverVersion != "" && !slices.Contains(versions, device.DriverVersion) {
|
||||
versions = append(versions, device.DriverVersion)
|
||||
}
|
||||
if !device.Metrics.MemoryTotal.Available() {
|
||||
summary.MemoryPartial = true
|
||||
continue
|
||||
}
|
||||
bytes := device.Metrics.MemoryTotal.ValueOrZero() * 1024 * 1024
|
||||
if device.GPU != nil && device.GPU.SharedMemory {
|
||||
if summary.SharedMemoryTotal == nil || bytes > *summary.SharedMemoryTotal {
|
||||
summary.SharedMemoryTotal = &bytes
|
||||
}
|
||||
} else {
|
||||
if summary.MemoryTotal == nil {
|
||||
summary.MemoryTotal = new(float64)
|
||||
}
|
||||
*summary.MemoryTotal += bytes
|
||||
}
|
||||
}
|
||||
if len(cards) > 0 {
|
||||
count := len(cards)
|
||||
summary.CardCount = &count
|
||||
summary.DriverVersion = strings.Join(versions, " / ")
|
||||
if vendor == "nvidia" {
|
||||
summary.CudaVersion = snapshot.Info.CudaVersion
|
||||
}
|
||||
result = append(result, summary)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -39,6 +39,7 @@ func normalizeGPU(item *gpu.Device) Device {
|
||||
Vendor: item.Type,
|
||||
Index: int(item.Index),
|
||||
Name: item.ProductName,
|
||||
DriverVersion: item.DriverVersion,
|
||||
Label: fmt.Sprintf("%d - %s", item.Index, item.ProductName),
|
||||
BusID: item.BusID,
|
||||
Metrics: metrics,
|
||||
@@ -121,6 +122,7 @@ func normalizeXPU(item *xpu.Device) Device {
|
||||
Vendor: item.Basic.VendorName,
|
||||
Index: item.Basic.DeviceID,
|
||||
Name: item.Basic.DeviceName,
|
||||
DriverVersion: item.Basic.DriverVersion,
|
||||
Label: fmt.Sprintf("%d - %s", item.Basic.DeviceID, item.Basic.DeviceName),
|
||||
BusID: item.Basic.PciBdfAddress,
|
||||
Metrics: metrics,
|
||||
|
||||
@@ -56,7 +56,9 @@ func (p npuProvider) Collect(ctx context.Context) (*ProviderSnapshot, error) {
|
||||
NPUs: info.Devices,
|
||||
}
|
||||
for index := range result.NPUs {
|
||||
result.Devices = append(result.Devices, normalizeNPU(&result.NPUs[index]))
|
||||
device := normalizeNPU(&result.NPUs[index])
|
||||
device.DriverVersion = info.DriverVersion
|
||||
result.Devices = append(result.Devices, device)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ type Device struct {
|
||||
NPUIndex int
|
||||
ChipIndex int
|
||||
Name string
|
||||
DriverVersion string
|
||||
Label string
|
||||
BusID string
|
||||
Metrics Metrics
|
||||
|
||||
@@ -23,12 +23,24 @@ type providerResult struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func New() (bool, Client) {
|
||||
client := Client{}
|
||||
func ManagementCommands() map[string]string {
|
||||
commands := make(map[string]string)
|
||||
if cmd.Which(nvidiaSMICommand) {
|
||||
client.providers = append(client.providers, nvidiaSMI{})
|
||||
commands["nvidia"] = nvidiaSMICommand
|
||||
}
|
||||
if command, ok := findAMDSMI(); ok {
|
||||
commands["amd"] = command
|
||||
}
|
||||
return commands
|
||||
}
|
||||
|
||||
func New() (bool, Client) {
|
||||
client := Client{}
|
||||
commands := ManagementCommands()
|
||||
if commands["nvidia"] != "" {
|
||||
client.providers = append(client.providers, nvidiaSMI{})
|
||||
}
|
||||
if command := commands["amd"]; command != "" {
|
||||
client.providers = append(client.providers, amdSMI{command: command})
|
||||
}
|
||||
return len(client.providers) > 0, client
|
||||
|
||||
@@ -63,6 +63,7 @@ type Info struct {
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
ReadError string `json:"-"`
|
||||
Tiles []TileStats `json:"tiles"`
|
||||
ProcessStatus string `json:"processStatus"`
|
||||
|
||||
|
||||
@@ -122,8 +122,9 @@ func (c Client) loadDeviceInfo(ctx context.Context, device discoveryDevice, wg *
|
||||
wgCmd.Wait()
|
||||
|
||||
if xpuErr != nil {
|
||||
xpu.ReadError = fmt.Sprintf("xpu-smi device %d: %v", device.DeviceID, xpuErr)
|
||||
mu.Lock()
|
||||
res.Warnings = append(res.Warnings, fmt.Sprintf("xpu-smi device %d: %v", device.DeviceID, xpuErr))
|
||||
res.Warnings = append(res.Warnings, xpu.ReadError)
|
||||
res.Devices = append(res.Devices, xpu)
|
||||
mu.Unlock()
|
||||
return
|
||||
@@ -131,8 +132,9 @@ func (c Client) loadDeviceInfo(ctx context.Context, device discoveryDevice, wg *
|
||||
|
||||
var info discoveryDevice
|
||||
if err := json.Unmarshal([]byte(xpuData), &info); err != nil {
|
||||
xpu.ReadError = fmt.Sprintf("xpu-smi device %d output: %v", device.DeviceID, err)
|
||||
mu.Lock()
|
||||
res.Warnings = append(res.Warnings, fmt.Sprintf("xpu-smi device %d output: %v", device.DeviceID, err))
|
||||
res.Warnings = append(res.Warnings, xpu.ReadError)
|
||||
res.Devices = append(res.Devices, xpu)
|
||||
mu.Unlock()
|
||||
return
|
||||
|
||||
@@ -37,6 +37,28 @@ export namespace AI {
|
||||
info?: string;
|
||||
}
|
||||
|
||||
export interface GPUEnvironmentCheck {
|
||||
vendor: string;
|
||||
item: 'driver' | 'toolkit' | 'docker';
|
||||
status: 'passed' | 'missing' | 'unconfigured' | 'failed' | 'unknown';
|
||||
code?: string;
|
||||
version?: string;
|
||||
reason?: string;
|
||||
}
|
||||
export interface GPUEnvironment {
|
||||
checkedAt: string;
|
||||
hardwareStatus: 'detected' | 'not_detected' | 'unknown';
|
||||
checks: GPUEnvironmentCheck[];
|
||||
}
|
||||
export interface GPUSummary {
|
||||
vendor: string;
|
||||
driverVersion: string;
|
||||
cudaVersion: string;
|
||||
cardCount: number | null;
|
||||
memoryTotal: number | null;
|
||||
sharedMemoryTotal: number | null;
|
||||
memoryPartial: boolean;
|
||||
}
|
||||
export interface Info {
|
||||
collectedAt?: string;
|
||||
warnings?: string[];
|
||||
@@ -47,6 +69,8 @@ export namespace AI {
|
||||
npu: NPU[];
|
||||
xpuDriverVersion: string;
|
||||
xpu: XpuInfo['xpu'];
|
||||
environment?: GPUEnvironment;
|
||||
summaries?: GPUSummary[];
|
||||
}
|
||||
export interface GPU {
|
||||
sharedMemory?: boolean;
|
||||
|
||||
@@ -47,8 +47,11 @@ export const loadModelGPUDevices = () => {
|
||||
return http.get<{ devices: AI.ModelGPUDevice[]; warnings: string[] }>('/ai/model/gpu/devices');
|
||||
};
|
||||
|
||||
export const loadGPUInfo = () => {
|
||||
return http.get<AI.Info>(`/ai/gpu/load`);
|
||||
export const loadGPUInfo = (refresh = false, currentNode?: string) => {
|
||||
return http.get<AI.Info>(`/ai/gpu/load`, refresh ? { refresh: true } : {}, {
|
||||
timeout: TimeoutEnum.T_40S,
|
||||
headers: currentNode ? { CurrentNode: currentNode } : undefined,
|
||||
});
|
||||
};
|
||||
export const getGPUOptions = (currentNode?: string) => {
|
||||
return http.get<AI.MonitorGPUOptions>(
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
<el-radio-group v-model="activeName" @change="handleChange">
|
||||
<el-radio-button
|
||||
class="router_card_button"
|
||||
:class="{ 'opacity-50': button.disabled }"
|
||||
:label="button.label"
|
||||
:value="button.label"
|
||||
:disabled="button.disabled"
|
||||
v-for="(button, index) in buttonArray"
|
||||
size="large"
|
||||
:key="index"
|
||||
@@ -94,7 +96,10 @@ const expiresAlertKey = computed(() => (isEnterprise.value ? 'xpack.expiresEnter
|
||||
|
||||
const handleChange = async (label: string) => {
|
||||
const btn = buttonArray.value.find((btn) => btn.label === label);
|
||||
if (!btn) return;
|
||||
if (!btn || btn.disabled) {
|
||||
syncActiveName();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (btn.path) await routerToPathWithQuery(btn.path, { uncached: 'true' });
|
||||
else if (btn.name) await routerToNameWithQuery(btn.name, { uncached: 'true' });
|
||||
|
||||
@@ -1743,8 +1743,8 @@ const message = {
|
||||
running: 'Running requests',
|
||||
waiting: 'Waiting requests',
|
||||
cacheUsage: 'KV cache usage',
|
||||
promptThroughput: 'Input token throughput',
|
||||
generationThroughput: 'Output token throughput',
|
||||
promptThroughput: 'Input throughput',
|
||||
generationThroughput: 'Output throughput',
|
||||
requestThroughput: 'Completed requests',
|
||||
timeToFirstToken: 'Mean time to first token',
|
||||
timePerOutputToken: 'Mean inter-token latency',
|
||||
@@ -1764,6 +1764,69 @@ const message = {
|
||||
timePerOutputTokenChart: 'Inter-token latency',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'Host GPU',
|
||||
containerGPU: 'Container GPU support',
|
||||
monitorAvailable: 'Monitoring available',
|
||||
monitorPartial: 'Partial monitoring',
|
||||
notReady: 'Not ready',
|
||||
ready: 'Ready',
|
||||
checkedAt: 'Checked at',
|
||||
checkDetailsHelp: 'Review the check details, verify the environment, and check again.',
|
||||
driverActionTitle: 'Check the host GPU driver first',
|
||||
driverActionHelp:
|
||||
'Install or repair the affected device driver before continuing with the container environment checks.',
|
||||
driverGuide: 'View driver installation guide',
|
||||
toolkitActionTitle: 'Container GPU support is not ready',
|
||||
toolkitActionHelp: 'Install or repair NVIDIA Container Toolkit, then check the Docker configuration.',
|
||||
toolkitGuide: 'View Toolkit installation guide',
|
||||
dockerActionTitle: 'Docker NVIDIA GPU support is not ready',
|
||||
dockerActionHelp: 'Check the NVIDIA runtime configuration in Docker, then check again.',
|
||||
monitorUnaffected: 'Host GPU monitoring is unaffected by this issue.',
|
||||
title: 'Environment checks',
|
||||
passed: 'Environment checks passed',
|
||||
issues: 'Detected {count} environment issues. Follow the guidance to check them.',
|
||||
recheck: 'Check again',
|
||||
installGuide: 'View installation guide',
|
||||
goContainerSettings: 'Open Container Settings',
|
||||
details: 'Check details',
|
||||
vendor: 'Vendor',
|
||||
gpuCount: 'GPU count',
|
||||
cardCount: 'Card count',
|
||||
notDetected: 'No supported GPU/NPU/XPU devices were detected on the current node.',
|
||||
unknown: 'Could not confirm device status. Review the check details and try again.',
|
||||
loadFailed: 'Could not read device information. Please try again.',
|
||||
notApplicable: 'Not applicable',
|
||||
cudaHelper:
|
||||
'This is the CUDA version supported by the driver, not the CUDA Toolkit version installed on the host.',
|
||||
partialMemory: 'Some memory data is unavailable',
|
||||
sharedMemory: 'Shared system memory: {memory}',
|
||||
driver: 'Driver and device management tools',
|
||||
nvidiaDriver: 'NVIDIA Driver',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker NVIDIA GPU configuration',
|
||||
statusPassed: 'Normal',
|
||||
statusMissing: 'Not detected',
|
||||
statusUnconfigured: 'Configuration required',
|
||||
statusFailed: 'Check failed',
|
||||
statusUnknown: 'Unknown',
|
||||
driverMissing:
|
||||
'The {vendor} driver was not detected. Install or check the driver (detection tool: {tool}).',
|
||||
driverFailed: 'Could not read device information using {tool}. Check the driver status.',
|
||||
driverUnknown: 'Could not confirm the device driver status. Check {tool}.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit was not detected. Install and configure it before using NVIDIA GPUs in containers.',
|
||||
toolkitFailed: 'Could not check NVIDIA Container Toolkit. Review the failure details.',
|
||||
dockerConfigMissing:
|
||||
'No runtimes.nvidia entry was detected in the default Docker configuration file. Complete the configuration using the documentation.',
|
||||
dockerConfigInvalid:
|
||||
'The NVIDIA runtime configuration in Docker is invalid. Check runtimes.nvidia.path in daemon.json.',
|
||||
dockerConfigPending:
|
||||
'The default configuration file contains NVIDIA runtime configuration, but the current Docker daemon has not loaded it. Confirm the configuration file, restart Docker, and check again.',
|
||||
dockerConfigUnreadable: 'Could not read the Docker configuration file. Review the check details.',
|
||||
dockerUnconfigured: 'Docker NVIDIA GPU configuration is incomplete.',
|
||||
dockerFailed: 'Could not check the Docker NVIDIA GPU configuration. Review the failure details.',
|
||||
},
|
||||
systemMemory: 'Shared system memory',
|
||||
systemMemoryUsed: 'System memory used',
|
||||
systemMemoryTotal: 'Total system memory',
|
||||
@@ -1823,6 +1886,8 @@ const message = {
|
||||
pcieWidth: 'PCIe width (current / maximum)',
|
||||
gpu: 'GPU Management',
|
||||
monitoringTitle: 'GPU Monitoring',
|
||||
currentHelper:
|
||||
'View real-time status and resource usage of GPU/NPU/XPU devices on the current node. The overview summarizes all devices; detailed metrics are shown per device.',
|
||||
gpuHelper: 'No supported GPU/XPU/NPU management command was detected. Please check and try again!',
|
||||
process: 'Process Information',
|
||||
processCount: 'Process Count',
|
||||
|
||||
@@ -1754,8 +1754,8 @@ const message = {
|
||||
running: 'Solicitudes en ejecución',
|
||||
waiting: 'Solicitudes en espera',
|
||||
cacheUsage: 'Uso de caché KV',
|
||||
promptThroughput: 'Rendimiento de tokens de entrada',
|
||||
generationThroughput: 'Rendimiento de tokens de salida',
|
||||
promptThroughput: 'Rendimiento de entrada',
|
||||
generationThroughput: 'Rendimiento de salida',
|
||||
requestThroughput: 'Solicitudes completadas',
|
||||
timeToFirstToken: 'Latencia media del primer token',
|
||||
timePerOutputToken: 'Latencia media entre tokens',
|
||||
@@ -1776,6 +1776,74 @@ const message = {
|
||||
timePerOutputTokenChart: 'Latencia entre tokens',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU del host',
|
||||
containerGPU: 'Compatibilidad GPU en contenedores',
|
||||
monitorAvailable: 'Supervisión disponible',
|
||||
monitorPartial: 'Supervisión parcial',
|
||||
notReady: 'No está listo',
|
||||
ready: 'Listo',
|
||||
checkedAt: 'Última comprobación',
|
||||
checkDetailsHelp: 'Revisa los detalles, verifica el entorno y vuelve a comprobarlo.',
|
||||
driverActionTitle: 'Comprueba primero el controlador GPU del host',
|
||||
driverActionHelp:
|
||||
'Instala o repara el controlador del dispositivo afectado antes de continuar con las comprobaciones del entorno de contenedores.',
|
||||
driverGuide: 'Ver guía de instalación del controlador',
|
||||
toolkitActionTitle: 'La compatibilidad GPU en contenedores no está lista',
|
||||
toolkitActionHelp:
|
||||
'Instala o repara NVIDIA Container Toolkit y después comprueba la configuración de Docker.',
|
||||
toolkitGuide: 'Ver guía de instalación de Toolkit',
|
||||
dockerActionTitle: 'La compatibilidad NVIDIA GPU de Docker no está lista',
|
||||
dockerActionHelp:
|
||||
'Comprueba la configuración del runtime NVIDIA en Docker y vuelve a realizar la comprobación.',
|
||||
monitorUnaffected: 'Este problema no afecta a la supervisión de la GPU del host.',
|
||||
title: 'Comprobaciones del entorno',
|
||||
passed: 'Comprobaciones del entorno superadas',
|
||||
issues: 'Problemas del entorno detectados: {count}. Siga las indicaciones para revisarlos.',
|
||||
recheck: 'Comprobar de nuevo',
|
||||
installGuide: 'Ver guía de instalación',
|
||||
goContainerSettings: 'Abrir configuración de contenedores',
|
||||
details: 'Detalles de la comprobación',
|
||||
vendor: 'Fabricante',
|
||||
gpuCount: 'Cantidad de GPU',
|
||||
cardCount: 'Número de tarjetas',
|
||||
notDetected: 'No se detectaron dispositivos GPU/NPU/XPU compatibles en el nodo actual.',
|
||||
unknown: 'No se pudo confirmar el estado del dispositivo. Revise los detalles y vuelva a comprobarlo.',
|
||||
loadFailed: 'No se pudo leer la información del dispositivo. Inténtelo de nuevo.',
|
||||
notApplicable: 'No aplicable',
|
||||
cudaHelper:
|
||||
'Esta es la versión de CUDA compatible con el controlador, no la versión de CUDA Toolkit instalada en el host.',
|
||||
partialMemory: 'Algunos datos de memoria no están disponibles',
|
||||
sharedMemory: 'Memoria del sistema compartida: {memory}',
|
||||
driver: 'Controlador y herramientas de gestión de dispositivos',
|
||||
nvidiaDriver: 'Controlador NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Configuración de GPU NVIDIA en Docker',
|
||||
statusPassed: 'Normal',
|
||||
statusMissing: 'No detectado',
|
||||
statusUnconfigured: 'Configuración pendiente',
|
||||
statusFailed: 'Error de comprobación',
|
||||
statusUnknown: 'Desconocido',
|
||||
driverMissing:
|
||||
'No se detectó el controlador de {vendor}. Instale o compruebe el controlador (herramienta de detección: {tool}).',
|
||||
driverFailed:
|
||||
'No se pudo leer la información del dispositivo mediante {tool}. Compruebe el estado del controlador.',
|
||||
driverUnknown: 'No se pudo confirmar el estado del controlador del dispositivo. Compruebe {tool}.',
|
||||
toolkitMissing:
|
||||
'No se detectó NVIDIA Container Toolkit. Instálelo y configúrelo antes de usar GPU NVIDIA en contenedores.',
|
||||
toolkitFailed: 'No se pudo comprobar NVIDIA Container Toolkit. Revise los detalles del error.',
|
||||
dockerConfigMissing:
|
||||
'No se detectó la entrada runtimes.nvidia en el archivo de configuración predeterminado de Docker. Complete la configuración siguiendo la documentación.',
|
||||
dockerConfigInvalid:
|
||||
'La configuración del entorno de ejecución de NVIDIA en Docker no es válida. Compruebe runtimes.nvidia.path en daemon.json.',
|
||||
dockerConfigPending:
|
||||
'El archivo de configuración predeterminado contiene la configuración del entorno de ejecución de NVIDIA, pero el servicio Docker actual aún no la ha cargado. Confirme el archivo de configuración, reinicie Docker y vuelva a comprobarlo.',
|
||||
dockerConfigUnreadable:
|
||||
'No se pudo leer el archivo de configuración de Docker. Revise los detalles de la comprobación.',
|
||||
dockerUnconfigured: 'La configuración de GPU NVIDIA en Docker está incompleta.',
|
||||
dockerFailed:
|
||||
'No se pudo comprobar la configuración de GPU NVIDIA en Docker. Revise los detalles del error.',
|
||||
},
|
||||
systemMemory: 'Memoria compartida del sistema',
|
||||
systemMemoryUsed: 'Memoria del sistema utilizada',
|
||||
systemMemoryTotal: 'Memoria total del sistema',
|
||||
@@ -1836,6 +1904,8 @@ const message = {
|
||||
pcieWidth: 'Ancho PCIe (actual / máximo)',
|
||||
gpu: 'Gestión de GPU',
|
||||
monitoringTitle: 'Monitoreo de GPU',
|
||||
currentHelper:
|
||||
'Consulte el estado en tiempo real y el uso de recursos de los dispositivos GPU/NPU/XPU del nodo actual. El resumen superior incluye todos los dispositivos; las métricas detalladas se muestran por dispositivo.',
|
||||
gpuHelper:
|
||||
'No se detectó ningún comando de administración de GPU/XPU/NPU compatible. ¡Compruebe e inténtelo de nuevo!',
|
||||
process: 'Información del Proceso',
|
||||
|
||||
@@ -1719,8 +1719,8 @@ const message = {
|
||||
running: 'درخواستهای در حال اجرا',
|
||||
waiting: 'درخواستهای در انتظار',
|
||||
cacheUsage: 'مصرف حافظه نهان KV',
|
||||
promptThroughput: 'گذردهی توکن ورودی',
|
||||
generationThroughput: 'گذردهی توکن خروجی',
|
||||
promptThroughput: 'گذردهی ورودی',
|
||||
generationThroughput: 'گذردهی خروجی',
|
||||
requestThroughput: 'نرخ درخواستهای تکمیلشده',
|
||||
timeToFirstToken: 'میانگین تأخیر توکن اول',
|
||||
timePerOutputToken: 'میانگین تأخیر بین توکنها',
|
||||
@@ -1740,6 +1740,67 @@ const message = {
|
||||
timePerOutputTokenChart: 'تأخیر بین توکنها',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU میزبان',
|
||||
containerGPU: 'پشتیبانی GPU در کانتینر',
|
||||
monitorAvailable: 'پایش در دسترس است',
|
||||
monitorPartial: 'پایش جزئی',
|
||||
notReady: 'آماده نیست',
|
||||
ready: 'آماده',
|
||||
checkedAt: 'زمان بررسی',
|
||||
checkDetailsHelp: 'جزئیات بررسی را ببینید، وضعیت محیط را تأیید کنید و دوباره بررسی کنید.',
|
||||
driverActionTitle: 'ابتدا درایور GPU میزبان را بررسی کنید',
|
||||
driverActionHelp: 'پیش از ادامه بررسی محیط کانتینر، درایور دستگاه دارای مشکل را نصب یا تعمیر کنید.',
|
||||
driverGuide: 'مشاهده راهنمای نصب درایور',
|
||||
toolkitActionTitle: 'پشتیبانی GPU در کانتینر آماده نیست',
|
||||
toolkitActionHelp:
|
||||
'ابتدا NVIDIA Container Toolkit را نصب یا تعمیر کنید، سپس پیکربندی Docker را بررسی کنید.',
|
||||
toolkitGuide: 'مشاهده راهنمای نصب Toolkit',
|
||||
dockerActionTitle: 'پشتیبانی NVIDIA GPU در Docker آماده نیست',
|
||||
dockerActionHelp: 'پیکربندی محیط اجرای NVIDIA در Docker را بررسی کنید و سپس دوباره بررسی کنید.',
|
||||
monitorUnaffected: 'این مشکل بر پایش GPU میزبان تأثیری ندارد.',
|
||||
title: 'بررسی محیط',
|
||||
passed: 'بررسیهای محیط با موفقیت انجام شد',
|
||||
issues: '{count} مشکل در محیط شناسایی شد. برای بررسی آنها راهنما را دنبال کنید.',
|
||||
recheck: 'بررسی دوباره',
|
||||
installGuide: 'مشاهده راهنمای نصب',
|
||||
goContainerSettings: 'باز کردن تنظیمات کانتینر',
|
||||
details: 'جزئیات بررسی',
|
||||
vendor: 'سازنده',
|
||||
gpuCount: 'تعداد GPU',
|
||||
cardCount: 'تعداد کارتها',
|
||||
notDetected: 'هیچ دستگاه GPU/NPU/XPU پشتیبانیشدهای در گره فعلی شناسایی نشد.',
|
||||
unknown: 'وضعیت دستگاه قابل تأیید نیست. جزئیات بررسی را ببینید و دوباره تلاش کنید.',
|
||||
loadFailed: 'خواندن اطلاعات دستگاه ممکن نیست. دوباره تلاش کنید.',
|
||||
notApplicable: 'قابل اعمال نیست',
|
||||
cudaHelper: 'این نسخه CUDA پشتیبانیشده توسط درایور است، نه نسخه CUDA Toolkit نصبشده روی میزبان.',
|
||||
partialMemory: 'بخشی از دادههای حافظه در دسترس نیست',
|
||||
sharedMemory: 'حافظه مشترک سیستم: {memory}',
|
||||
driver: 'درایور و ابزارهای مدیریت دستگاه',
|
||||
nvidiaDriver: 'درایور NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'پیکربندی GPU انویدیا در Docker',
|
||||
statusPassed: 'عادی',
|
||||
statusMissing: 'شناسایی نشد',
|
||||
statusUnconfigured: 'نیازمند پیکربندی',
|
||||
statusFailed: 'بررسی ناموفق',
|
||||
statusUnknown: 'نامشخص',
|
||||
driverMissing: 'درایور {vendor} شناسایی نشد. درایور را نصب یا بررسی کنید (ابزار شناسایی: {tool}).',
|
||||
driverFailed: 'خواندن اطلاعات دستگاه با {tool} ممکن نیست. وضعیت درایور را بررسی کنید.',
|
||||
driverUnknown: 'وضعیت درایور دستگاه قابل تأیید نیست. {tool} را بررسی کنید.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit شناسایی نشد. پیش از استفاده از GPU انویدیا در کانتینرها، نصب و پیکربندی آن را کامل کنید.',
|
||||
toolkitFailed: 'بررسی NVIDIA Container Toolkit ممکن نیست. جزئیات خطا را ببینید.',
|
||||
dockerConfigMissing:
|
||||
'گزینه runtimes.nvidia در فایل پیکربندی پیشفرض Docker شناسایی نشد. پیکربندی را طبق مستندات کامل کنید.',
|
||||
dockerConfigInvalid:
|
||||
'پیکربندی محیط اجرای NVIDIA در Docker نامعتبر است. مقدار runtimes.nvidia.path را در daemon.json بررسی کنید.',
|
||||
dockerConfigPending:
|
||||
'فایل پیکربندی پیشفرض شامل پیکربندی محیط اجرای NVIDIA است، اما سرویس فعلی Docker هنوز آن را بارگذاری نکرده است. فایل پیکربندی را تأیید کنید، Docker را دوباره راهاندازی کنید و سپس دوباره بررسی کنید.',
|
||||
dockerConfigUnreadable: 'خواندن فایل پیکربندی Docker ممکن نیست. جزئیات بررسی را ببینید.',
|
||||
dockerUnconfigured: 'پیکربندی GPU انویدیا در Docker کامل نشده است.',
|
||||
dockerFailed: 'بررسی پیکربندی GPU انویدیا در Docker ممکن نیست. جزئیات خطا را ببینید.',
|
||||
},
|
||||
systemMemory: 'حافظهٔ مشترک سیستم',
|
||||
systemMemoryUsed: 'حافظهٔ مصرفشدهٔ سیستم',
|
||||
systemMemoryTotal: 'کل حافظهٔ سیستم',
|
||||
@@ -1798,6 +1859,8 @@ const message = {
|
||||
pcieWidth: 'عرض PCIe (فعلی / حداکثر)',
|
||||
gpu: 'مدیریت GPU',
|
||||
monitoringTitle: 'نظارت بر GPU',
|
||||
currentHelper:
|
||||
'وضعیت لحظهای و میزان استفاده از منابع دستگاههای GPU/NPU/XPU در گره فعلی را مشاهده کنید. نمای کلی در بالا، خلاصه همه دستگاهها را نشان میدهد؛ شاخصهای دقیق برای هر دستگاه جداگانه نمایش داده میشوند.',
|
||||
gpuHelper: 'هیچ دستور مدیریت GPU/XPU/NPU پشتیبانیشدهای شناسایی نشد. لطفاً بررسی و دوباره تلاش کنید!',
|
||||
process: 'اطلاعات فرآیند',
|
||||
processCount: 'تعداد فرآیندها',
|
||||
|
||||
@@ -1726,8 +1726,8 @@ const message = {
|
||||
running: '実行中のリクエスト',
|
||||
waiting: '待機中のリクエスト',
|
||||
cacheUsage: 'KVキャッシュ使用率',
|
||||
promptThroughput: '入力トークンスループット',
|
||||
generationThroughput: '出力トークンスループット',
|
||||
promptThroughput: '入力スループット',
|
||||
generationThroughput: '出力スループット',
|
||||
requestThroughput: '完了リクエスト数/秒',
|
||||
timeToFirstToken: '平均初回トークン遅延',
|
||||
timePerOutputToken: '平均トークン間遅延',
|
||||
@@ -1747,6 +1747,70 @@ const message = {
|
||||
timePerOutputTokenChart: 'トークン間遅延',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'ホスト GPU',
|
||||
containerGPU: 'コンテナーの GPU 対応',
|
||||
monitorAvailable: '監視可能',
|
||||
monitorPartial: '一部監視可能',
|
||||
notReady: '未準備',
|
||||
ready: '準備完了',
|
||||
checkedAt: '確認日時',
|
||||
checkDetailsHelp: '確認の詳細を参照し、環境の状態を確認してから再チェックしてください。',
|
||||
driverActionTitle: 'まずホスト GPU ドライバーを確認してください',
|
||||
driverActionHelp:
|
||||
'問題のあるデバイスのドライバーをインストールまたは修復してから、コンテナー環境の確認を続けてください。',
|
||||
driverGuide: 'ドライバーのインストール手順',
|
||||
toolkitActionTitle: 'コンテナーの GPU 環境が未準備です',
|
||||
toolkitActionHelp:
|
||||
'NVIDIA Container Toolkit をインストールまたは修復してから、Docker の設定を確認してください。',
|
||||
toolkitGuide: 'Toolkit のインストール手順',
|
||||
dockerActionTitle: 'Docker の NVIDIA GPU 環境が未準備です',
|
||||
dockerActionHelp: 'Docker の NVIDIA ランタイム設定を確認してから、再チェックしてください。',
|
||||
monitorUnaffected: 'この問題はホスト GPU の監視に影響しません。',
|
||||
title: '環境チェック',
|
||||
passed: '環境チェックに合格しました',
|
||||
issues: '環境の問題が {count} 件見つかりました。案内に従って確認してください。',
|
||||
recheck: '再チェック',
|
||||
installGuide: 'インストールガイドを見る',
|
||||
goContainerSettings: 'コンテナー設定を開く',
|
||||
details: 'チェックの詳細',
|
||||
vendor: 'メーカー',
|
||||
gpuCount: 'GPU 数',
|
||||
cardCount: 'カード数',
|
||||
notDetected: '現在のノードで対応する GPU/NPU/XPU デバイスが検出されませんでした。',
|
||||
unknown: 'デバイスの状態を確認できません。チェックの詳細を確認してから再実行してください。',
|
||||
loadFailed: 'デバイス情報を読み取れません。再試行してください。',
|
||||
notApplicable: '対象外',
|
||||
cudaHelper:
|
||||
'これはドライバーが対応する CUDA バージョンであり、ホストにインストールされた CUDA Toolkit のバージョンではありません。',
|
||||
partialMemory: '一部のメモリデータを取得できません',
|
||||
sharedMemory: '共有システムメモリ:{memory}',
|
||||
driver: 'ドライバーとデバイス管理ツール',
|
||||
nvidiaDriver: 'NVIDIA ドライバー',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker の NVIDIA GPU 設定',
|
||||
statusPassed: '正常',
|
||||
statusMissing: '未検出',
|
||||
statusUnconfigured: '設定が必要',
|
||||
statusFailed: 'チェック失敗',
|
||||
statusUnknown: '不明',
|
||||
driverMissing:
|
||||
'{vendor} ドライバーが検出されませんでした。ドライバーをインストールするか、状態を確認してください(検出ツール:{tool})。',
|
||||
driverFailed: '{tool} でデバイス情報を読み取れません。ドライバーの状態を確認してください。',
|
||||
driverUnknown: 'デバイスのドライバーの状態を確認できません。{tool} を確認してください。',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit が検出されませんでした。コンテナーで NVIDIA GPU を使用する前にインストールと設定を完了してください。',
|
||||
toolkitFailed: 'NVIDIA Container Toolkit をチェックできません。失敗の詳細を確認してください。',
|
||||
dockerConfigMissing:
|
||||
'Docker の既定の設定ファイルに runtimes.nvidia が検出されませんでした。ドキュメントに従って設定を完了してください。',
|
||||
dockerConfigInvalid:
|
||||
'Docker の NVIDIA ランタイム設定が正しくありません。daemon.json の runtimes.nvidia.path を確認してください。',
|
||||
dockerConfigPending:
|
||||
'既定の設定ファイルに NVIDIA ランタイム設定がありますが、現在の Docker にはまだ読み込まれていません。設定ファイルを確認し、Docker を再起動してから再チェックしてください。',
|
||||
dockerConfigUnreadable: 'Docker の設定ファイルを読み取れません。チェックの詳細を確認してください。',
|
||||
dockerUnconfigured: 'Docker の NVIDIA GPU 設定が完了していません。',
|
||||
dockerFailed: 'Docker の NVIDIA GPU 設定をチェックできません。失敗の詳細を確認してください。',
|
||||
},
|
||||
systemMemory: '共有システムメモリ',
|
||||
systemMemoryUsed: 'システムメモリ使用量',
|
||||
systemMemoryTotal: 'システムメモリ合計',
|
||||
@@ -1804,6 +1868,8 @@ const message = {
|
||||
pcieWidth: 'PCIe 幅(現在 / 最大)',
|
||||
gpu: 'GPU 管理',
|
||||
monitoringTitle: 'GPU 監視',
|
||||
currentHelper:
|
||||
'現在のノードにある GPU/NPU/XPU デバイスのリアルタイムの稼働状態とリソース使用状況を確認できます。上部には全デバイスの概要を表示し、詳細な指標はデバイスごとに表示します。',
|
||||
gpuHelper: '対応する GPU/XPU/NPU 管理コマンドが検出されませんでした。確認して再試行してください!',
|
||||
process: 'プロセス情報',
|
||||
type: 'タイプ',
|
||||
|
||||
@@ -1707,8 +1707,8 @@ const message = {
|
||||
running: '실행 중인 요청',
|
||||
waiting: '대기 중인 요청',
|
||||
cacheUsage: 'KV 캐시 사용률',
|
||||
promptThroughput: '입력 토큰 처리량',
|
||||
generationThroughput: '출력 토큰 처리량',
|
||||
promptThroughput: '입력 처리량',
|
||||
generationThroughput: '출력 처리량',
|
||||
requestThroughput: '완료 요청 속도',
|
||||
timeToFirstToken: '평균 첫 토큰 지연',
|
||||
timePerOutputToken: '평균 토큰 간 지연',
|
||||
@@ -1728,6 +1728,67 @@ const message = {
|
||||
timePerOutputTokenChart: '토큰 간 지연',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: '호스트 GPU',
|
||||
containerGPU: '컨테이너 GPU 지원',
|
||||
monitorAvailable: '모니터링 가능',
|
||||
monitorPartial: '일부 모니터링 가능',
|
||||
notReady: '준비되지 않음',
|
||||
ready: '준비됨',
|
||||
checkedAt: '확인 시간',
|
||||
checkDetailsHelp: '확인 세부 정보를 보고 환경 상태를 확인한 후 다시 검사하세요.',
|
||||
driverActionTitle: '먼저 호스트 GPU 드라이버를 확인하세요',
|
||||
driverActionHelp: '문제가 있는 장치의 드라이버를 설치하거나 복구한 후 컨테이너 환경 검사를 계속하세요.',
|
||||
driverGuide: '드라이버 설치 안내 보기',
|
||||
toolkitActionTitle: '컨테이너 GPU 지원이 준비되지 않았습니다',
|
||||
toolkitActionHelp: 'NVIDIA Container Toolkit을 설치하거나 복구한 후 Docker 구성을 확인하세요.',
|
||||
toolkitGuide: 'Toolkit 설치 안내 보기',
|
||||
dockerActionTitle: 'Docker의 NVIDIA GPU 지원이 준비되지 않았습니다',
|
||||
dockerActionHelp: 'Docker의 NVIDIA 런타임 구성을 확인한 후 다시 검사하세요.',
|
||||
monitorUnaffected: '이 문제는 호스트 GPU 모니터링에 영향을 주지 않습니다.',
|
||||
title: '환경 점검',
|
||||
passed: '환경 점검을 통과했습니다',
|
||||
issues: '환경 문제 {count}개가 발견되었습니다. 안내에 따라 확인하세요.',
|
||||
recheck: '다시 점검',
|
||||
installGuide: '설치 가이드 보기',
|
||||
goContainerSettings: '컨테이너 설정 열기',
|
||||
details: '점검 세부 정보',
|
||||
vendor: '제조사',
|
||||
gpuCount: 'GPU 수',
|
||||
cardCount: '카드 수',
|
||||
notDetected: '현재 노드에서 지원되는 GPU/NPU/XPU 장치가 감지되지 않았습니다.',
|
||||
unknown: '장치 상태를 확인할 수 없습니다. 점검 세부 정보를 확인한 후 다시 시도하세요.',
|
||||
loadFailed: '장치 정보를 읽을 수 없습니다. 다시 시도하세요.',
|
||||
notApplicable: '해당 없음',
|
||||
cudaHelper: '이 버전은 드라이버가 지원하는 CUDA 버전이며 호스트에 설치된 CUDA Toolkit 버전이 아닙니다.',
|
||||
partialMemory: '일부 메모리 데이터를 가져오지 못했습니다',
|
||||
sharedMemory: '공유 시스템 메모리: {memory}',
|
||||
driver: '드라이버 및 장치 관리 도구',
|
||||
nvidiaDriver: 'NVIDIA 드라이버',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker NVIDIA GPU 구성',
|
||||
statusPassed: '정상',
|
||||
statusMissing: '감지되지 않음',
|
||||
statusUnconfigured: '구성 필요',
|
||||
statusFailed: '점검 실패',
|
||||
statusUnknown: '알 수 없음',
|
||||
driverMissing:
|
||||
'{vendor} 드라이버가 감지되지 않았습니다. 드라이버를 설치하거나 확인하세요(감지 도구: {tool}).',
|
||||
driverFailed: '{tool}를 통해 장치 정보를 읽을 수 없습니다. 드라이버 상태를 확인하세요.',
|
||||
driverUnknown: '장치 드라이버 상태를 확인할 수 없습니다. {tool}를 확인하세요.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit이 감지되지 않았습니다. 컨테이너에서 NVIDIA GPU를 사용하기 전에 설치와 구성을 완료하세요.',
|
||||
toolkitFailed: 'NVIDIA Container Toolkit을 점검할 수 없습니다. 실패 세부 정보를 확인하세요.',
|
||||
dockerConfigMissing:
|
||||
'Docker 기본 구성 파일에서 runtimes.nvidia 항목이 감지되지 않았습니다. 문서에 따라 구성을 완료하세요.',
|
||||
dockerConfigInvalid:
|
||||
'Docker의 NVIDIA 런타임 구성이 올바르지 않습니다. daemon.json의 runtimes.nvidia.path를 확인하세요.',
|
||||
dockerConfigPending:
|
||||
'기본 구성 파일에 NVIDIA 런타임 구성이 있지만 현재 Docker에서 아직 로드하지 않았습니다. 구성 파일을 확인하고 Docker를 다시 시작한 후 다시 점검하세요.',
|
||||
dockerConfigUnreadable: 'Docker 구성 파일을 읽을 수 없습니다. 점검 세부 정보를 확인하세요.',
|
||||
dockerUnconfigured: 'Docker NVIDIA GPU 구성이 완료되지 않았습니다.',
|
||||
dockerFailed: 'Docker NVIDIA GPU 구성을 점검할 수 없습니다. 실패 세부 정보를 확인하세요.',
|
||||
},
|
||||
systemMemory: '공유 시스템 메모리',
|
||||
systemMemoryUsed: '사용 중인 시스템 메모리',
|
||||
systemMemoryTotal: '전체 시스템 메모리',
|
||||
@@ -1785,6 +1846,8 @@ const message = {
|
||||
pcieWidth: 'PCIe 너비 (현재 / 최대)',
|
||||
gpu: 'GPU 관리',
|
||||
monitoringTitle: 'GPU 모니터링',
|
||||
currentHelper:
|
||||
'현재 노드의 GPU/NPU/XPU 장치에 대한 실시간 상태와 리소스 사용량을 확인합니다. 상단에는 모든 장치의 요약이 표시되며, 상세 지표는 장치별로 표시됩니다.',
|
||||
gpuHelper: '지원되는 GPU/XPU/NPU 관리 명령을 감지하지 못했습니다. 확인하고 다시 시도하세요!',
|
||||
process: '프로세스 정보',
|
||||
type: '유형',
|
||||
|
||||
@@ -1696,8 +1696,8 @@ const message = {
|
||||
running: 'ຄຳຮ້ອງຂໍທີ່ກຳລັງເຮັດວຽກ',
|
||||
waiting: 'ຄຳຮ້ອງຂໍທີ່ກຳລັງລໍຖ້າ',
|
||||
cacheUsage: 'ການໃຊ້ງານແຄດ KV',
|
||||
promptThroughput: 'ອັດຕາ Token ຂາເຂົ້າ',
|
||||
generationThroughput: 'ອັດຕາ Token ຂາອອກ',
|
||||
promptThroughput: 'ອັດຕາຂາເຂົ້າ',
|
||||
generationThroughput: 'ອັດຕາຂາອອກ',
|
||||
requestThroughput: 'ອັດຕາຄຳຮ້ອງຂໍສຳເລັດ',
|
||||
timeToFirstToken: 'ເວລາລໍຖ້າສະເລ່ຍຂອງ Token ທຳອິດ',
|
||||
timePerOutputToken: 'ເວລາລໍຖ້າສະເລ່ຍລະຫວ່າງ Token',
|
||||
@@ -1717,6 +1717,66 @@ const message = {
|
||||
timePerOutputTokenChart: 'ເວລາລໍຖ້າລະຫວ່າງ Token',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU ຂອງໂຮສ',
|
||||
containerGPU: 'ການຮອງຮັບ GPU ໃນຄອນເທນເນີ',
|
||||
monitorAvailable: 'ສາມາດຕິດຕາມໄດ້',
|
||||
monitorPartial: 'ຕິດຕາມໄດ້ບາງສ່ວນ',
|
||||
notReady: 'ຍັງບໍ່ພ້ອມ',
|
||||
ready: 'ພ້ອມແລ້ວ',
|
||||
checkedAt: 'ເວລາກວດສອບ',
|
||||
checkDetailsHelp: 'ເບິ່ງລາຍລະອຽດການກວດສອບ, ຢືນຢັນສະຖານະສະພາບແວດລ້ອມ ແລ້ວກວດສອບອີກຄັ້ງ.',
|
||||
driverActionTitle: 'ກວດສອບໄດຣເວີ GPU ຂອງໂຮສກ່ອນ',
|
||||
driverActionHelp: 'ຕິດຕັ້ງ ຫຼື ສ້ອມແປງໄດຣເວີຂອງອຸປະກອນທີ່ມີບັນຫາ ກ່ອນກວດສອບສະພາບແວດລ້ອມຄອນເທນເນີຕໍ່.',
|
||||
driverGuide: 'ເບິ່ງຄູ່ມືຕິດຕັ້ງໄດຣເວີ',
|
||||
toolkitActionTitle: 'ການຮອງຮັບ GPU ໃນຄອນເທນເນີຍັງບໍ່ພ້ອມ',
|
||||
toolkitActionHelp: 'ຕິດຕັ້ງ ຫຼື ສ້ອມແປງ NVIDIA Container Toolkit ກ່ອນ ແລ້ວກວດສອບການຕັ້ງຄ່າ Docker.',
|
||||
toolkitGuide: 'ເບິ່ງຄູ່ມືຕິດຕັ້ງ Toolkit',
|
||||
dockerActionTitle: 'ການຮອງຮັບ NVIDIA GPU ຂອງ Docker ຍັງບໍ່ພ້ອມ',
|
||||
dockerActionHelp: 'ກວດສອບການຕັ້ງຄ່າ NVIDIA runtime ໃນ Docker ແລ້ວກວດສອບອີກຄັ້ງ.',
|
||||
monitorUnaffected: 'ບັນຫານີ້ບໍ່ກະທົບຕໍ່ການຕິດຕາມ GPU ຂອງໂຮສ.',
|
||||
title: 'ກວດສອບສະພາບແວດລ້ອມ',
|
||||
passed: 'ຜ່ານການກວດສອບສະພາບແວດລ້ອມແລ້ວ',
|
||||
issues: 'ພົບບັນຫາສະພາບແວດລ້ອມ {count} ລາຍການ. ກະລຸນາກວດສອບຕາມຄຳແນະນຳ.',
|
||||
recheck: 'ກວດສອບອີກຄັ້ງ',
|
||||
installGuide: 'ເບິ່ງຄູ່ມືການຕິດຕັ້ງ',
|
||||
goContainerSettings: 'ເປີດການຕັ້ງຄ່າຄອນເທນເນີ',
|
||||
details: 'ລາຍລະອຽດການກວດສອບ',
|
||||
vendor: 'ຜູ້ຜະລິດ',
|
||||
gpuCount: 'ຈຳນວນ GPU',
|
||||
cardCount: 'ຈຳນວນບັດ',
|
||||
notDetected: 'ບໍ່ພົບອຸປະກອນ GPU/NPU/XPU ທີ່ຮອງຮັບໃນໂນດປັດຈຸບັນ.',
|
||||
unknown: 'ບໍ່ສາມາດຢືນຢັນສະຖານະອຸປະກອນໄດ້. ກະລຸນາເບິ່ງລາຍລະອຽດແລ້ວກວດສອບອີກຄັ້ງ.',
|
||||
loadFailed: 'ບໍ່ສາມາດອ່ານຂໍ້ມູນອຸປະກອນໄດ້. ກະລຸນາລອງໃໝ່.',
|
||||
notApplicable: 'ບໍ່ກ່ຽວຂ້ອງ',
|
||||
cudaHelper: 'ນີ້ແມ່ນເວີຊັນ CUDA ທີ່ໄດຣເວີຮອງຮັບ ບໍ່ແມ່ນເວີຊັນ CUDA Toolkit ທີ່ຕິດຕັ້ງໃນໂຮສ.',
|
||||
partialMemory: 'ບໍ່ສາມາດດຶງຂໍ້ມູນຄວາມຈຳບາງສ່ວນໄດ້',
|
||||
sharedMemory: 'ຄວາມຈຳລະບົບຮ່ວມກັນ: {memory}',
|
||||
driver: 'ໄດຣເວີ ແລະ ເຄື່ອງມືຈັດການອຸປະກອນ',
|
||||
nvidiaDriver: 'ໄດຣເວີ NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'ການຕັ້ງຄ່າ NVIDIA GPU ໃນ Docker',
|
||||
statusPassed: 'ປົກກະຕິ',
|
||||
statusMissing: 'ບໍ່ພົບ',
|
||||
statusUnconfigured: 'ຕ້ອງຕັ້ງຄ່າ',
|
||||
statusFailed: 'ການກວດສອບລົ້ມເຫຼວ',
|
||||
statusUnknown: 'ບໍ່ຮູ້',
|
||||
driverMissing: 'ບໍ່ພົບໄດຣເວີ {vendor}. ກະລຸນາຕິດຕັ້ງ ຫຼື ກວດສອບໄດຣເວີ (ເຄື່ອງມືກວດສອບ: {tool}).',
|
||||
driverFailed: 'ບໍ່ສາມາດອ່ານຂໍ້ມູນອຸປະກອນຜ່ານ {tool} ໄດ້. ກະລຸນາກວດສອບສະຖານະໄດຣເວີ.',
|
||||
driverUnknown: 'ບໍ່ສາມາດຢືນຢັນສະຖານະໄດຣເວີອຸປະກອນໄດ້. ກະລຸນາກວດສອບ {tool}.',
|
||||
toolkitMissing:
|
||||
'ບໍ່ພົບ NVIDIA Container Toolkit. ກະລຸນາຕິດຕັ້ງ ແລະ ຕັ້ງຄ່າກ່ອນໃຊ້ NVIDIA GPU ໃນຄອນເທນເນີ.',
|
||||
toolkitFailed: 'ບໍ່ສາມາດກວດສອບ NVIDIA Container Toolkit ໄດ້. ກະລຸນາເບິ່ງລາຍລະອຽດຂໍ້ຜິດພາດ.',
|
||||
dockerConfigMissing:
|
||||
'ບໍ່ພົບ runtimes.nvidia ໃນໄຟລ໌ການຕັ້ງຄ່າເລີ່ມຕົ້ນຂອງ Docker. ກະລຸນາຕັ້ງຄ່າໃຫ້ສຳເລັດຕາມເອກະສານ.',
|
||||
dockerConfigInvalid:
|
||||
'ການຕັ້ງຄ່າ NVIDIA runtime ໃນ Docker ບໍ່ຖືກຕ້ອງ. ກະລຸນາກວດສອບ runtimes.nvidia.path ໃນ daemon.json.',
|
||||
dockerConfigPending:
|
||||
'ໄຟລ໌ການຕັ້ງຄ່າເລີ່ມຕົ້ນມີການຕັ້ງຄ່າ NVIDIA runtime ແລ້ວ ແຕ່ບໍລິການ Docker ປັດຈຸບັນຍັງບໍ່ໄດ້ໂຫຼດ. ກະລຸນາຢືນຢັນໄຟລ໌ການຕັ້ງຄ່າ, ເລີ່ມ Docker ໃໝ່ ແລ້ວກວດສອບອີກຄັ້ງ.',
|
||||
dockerConfigUnreadable: 'ບໍ່ສາມາດອ່ານໄຟລ໌ການຕັ້ງຄ່າ Docker ໄດ້. ກະລຸນາເບິ່ງລາຍລະອຽດການກວດສອບ.',
|
||||
dockerUnconfigured: 'ການຕັ້ງຄ່າ NVIDIA GPU ໃນ Docker ຍັງບໍ່ສຳເລັດ.',
|
||||
dockerFailed: 'ບໍ່ສາມາດກວດສອບການຕັ້ງຄ່າ NVIDIA GPU ໃນ Docker ໄດ້. ກະລຸນາເບິ່ງລາຍລະອຽດຂໍ້ຜິດພາດ.',
|
||||
},
|
||||
systemMemory: 'ໜ່ວຍຄວາມຈຳລະບົບທີ່ໃຊ້ຮ່ວມກັນ',
|
||||
systemMemoryUsed: 'ໜ່ວຍຄວາມຈຳລະບົບທີ່ໃຊ້ແລ້ວ',
|
||||
systemMemoryTotal: 'ໜ່ວຍຄວາມຈຳລະບົບທັງໝົດ',
|
||||
@@ -1774,6 +1834,8 @@ const message = {
|
||||
pcieWidth: 'ຄວາມກວ້າງ PCIe (ປັດຈຸບັນ / ສູງສຸດ)',
|
||||
gpu: 'ການຈັດການ GPU',
|
||||
monitoringTitle: 'ຕິດຕາມ GPU',
|
||||
currentHelper:
|
||||
'ເບິ່ງສະຖານະການເຮັດວຽກ ແລະ ການໃຊ້ຊັບພະຍາກອນແບບເວລາຈິງຂອງອຸປະກອນ GPU/NPU/XPU ໃນໂນດປັດຈຸບັນ. ພາບລວມດ້ານເທິງສະຫຼຸບຂໍ້ມູນຂອງທຸກອຸປະກອນ ແລະ ສະແດງຕົວຊີ້ວັດລະອຽດແຍກຕາມອຸປະກອນ.',
|
||||
gpuHelper: 'ກວດບໍ່ພົບຄຳສັ່ງຈັດການ GPU/XPU/NPU ທີ່ຮອງຮັບ. ກະລຸນາກວດສອບ ແລະ ລອງໃໝ່!',
|
||||
process: 'ຂໍ້ມູນໂປຣເຊສ',
|
||||
processCount: 'ຈຳນວນໂປຣເຊສ',
|
||||
|
||||
@@ -1757,8 +1757,8 @@ const message = {
|
||||
running: 'Permintaan berjalan',
|
||||
waiting: 'Permintaan menunggu',
|
||||
cacheUsage: 'Penggunaan cache KV',
|
||||
promptThroughput: 'Daya pemprosesan token input',
|
||||
generationThroughput: 'Daya pemprosesan token output',
|
||||
promptThroughput: 'Daya pemprosesan input',
|
||||
generationThroughput: 'Daya pemprosesan output',
|
||||
requestThroughput: 'Kadar permintaan selesai',
|
||||
timeToFirstToken: 'Purata kependaman token pertama',
|
||||
timePerOutputToken: 'Purata kependaman antara token',
|
||||
@@ -1778,6 +1778,68 @@ const message = {
|
||||
timePerOutputTokenChart: 'Kependaman antara token',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU hos',
|
||||
containerGPU: 'Sokongan GPU kontena',
|
||||
monitorAvailable: 'Pemantauan tersedia',
|
||||
monitorPartial: 'Pemantauan separa',
|
||||
notReady: 'Belum sedia',
|
||||
ready: 'Sedia',
|
||||
checkedAt: 'Masa pemeriksaan',
|
||||
checkDetailsHelp: 'Semak butiran pemeriksaan, sahkan keadaan persekitaran dan periksa semula.',
|
||||
driverActionTitle: 'Periksa pemacu GPU hos terlebih dahulu',
|
||||
driverActionHelp:
|
||||
'Pasang atau baiki pemacu peranti yang bermasalah sebelum meneruskan pemeriksaan persekitaran kontena.',
|
||||
driverGuide: 'Lihat panduan pemasangan pemacu',
|
||||
toolkitActionTitle: 'Sokongan GPU kontena belum sedia',
|
||||
toolkitActionHelp: 'Pasang atau baiki NVIDIA Container Toolkit, kemudian periksa konfigurasi Docker.',
|
||||
toolkitGuide: 'Lihat panduan pemasangan Toolkit',
|
||||
dockerActionTitle: 'Sokongan NVIDIA GPU Docker belum sedia',
|
||||
dockerActionHelp: 'Periksa konfigurasi runtime NVIDIA dalam Docker, kemudian periksa semula.',
|
||||
monitorUnaffected: 'Isu ini tidak menjejaskan pemantauan GPU hos.',
|
||||
title: 'Semakan persekitaran',
|
||||
passed: 'Semakan persekitaran berjaya',
|
||||
issues: 'Masalah persekitaran dikesan: {count}. Ikuti panduan untuk menyemaknya.',
|
||||
recheck: 'Semak semula',
|
||||
installGuide: 'Lihat panduan pemasangan',
|
||||
goContainerSettings: 'Buka tetapan bekas',
|
||||
details: 'Butiran semakan',
|
||||
vendor: 'Pengeluar',
|
||||
gpuCount: 'Bilangan GPU',
|
||||
cardCount: 'Bilangan kad',
|
||||
notDetected: 'Tiada peranti GPU/NPU/XPU yang disokong dikesan pada nod semasa.',
|
||||
unknown: 'Status peranti tidak dapat dipastikan. Lihat butiran semakan dan cuba lagi.',
|
||||
loadFailed: 'Maklumat peranti tidak dapat dibaca. Sila cuba lagi.',
|
||||
notApplicable: 'Tidak berkenaan',
|
||||
cudaHelper:
|
||||
'Ini ialah versi CUDA yang disokong oleh pemacu, bukan versi CUDA Toolkit yang dipasang pada hos.',
|
||||
partialMemory: 'Sebahagian data memori tidak tersedia',
|
||||
sharedMemory: 'Memori sistem dikongsi: {memory}',
|
||||
driver: 'Pemacu dan alat pengurusan peranti',
|
||||
nvidiaDriver: 'Pemacu NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Konfigurasi NVIDIA GPU Docker',
|
||||
statusPassed: 'Normal',
|
||||
statusMissing: 'Tidak dikesan',
|
||||
statusUnconfigured: 'Konfigurasi diperlukan',
|
||||
statusFailed: 'Semakan gagal',
|
||||
statusUnknown: 'Tidak diketahui',
|
||||
driverMissing: 'Pemacu {vendor} tidak dikesan. Pasang atau semak pemacu (alat pengesanan: {tool}).',
|
||||
driverFailed: 'Maklumat peranti tidak dapat dibaca menggunakan {tool}. Semak status pemacu.',
|
||||
driverUnknown: 'Status pemacu peranti tidak dapat dipastikan. Semak {tool}.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit tidak dikesan. Pasang dan konfigurasikannya sebelum menggunakan NVIDIA GPU dalam bekas.',
|
||||
toolkitFailed: 'NVIDIA Container Toolkit tidak dapat disemak. Lihat butiran kegagalan.',
|
||||
dockerConfigMissing:
|
||||
'Entri runtimes.nvidia tidak dikesan dalam fail konfigurasi lalai Docker. Lengkapkan konfigurasi mengikut dokumentasi.',
|
||||
dockerConfigInvalid:
|
||||
'Konfigurasi masa jalan NVIDIA dalam Docker tidak sah. Semak runtimes.nvidia.path dalam daemon.json.',
|
||||
dockerConfigPending:
|
||||
'Fail konfigurasi lalai mengandungi konfigurasi masa jalan NVIDIA, tetapi perkhidmatan Docker semasa belum memuatkannya. Sahkan fail konfigurasi, mulakan semula Docker dan semak sekali lagi.',
|
||||
dockerConfigUnreadable: 'Fail konfigurasi Docker tidak dapat dibaca. Lihat butiran semakan.',
|
||||
dockerUnconfigured: 'Konfigurasi NVIDIA GPU Docker belum lengkap.',
|
||||
dockerFailed: 'Konfigurasi NVIDIA GPU Docker tidak dapat disemak. Lihat butiran kegagalan.',
|
||||
},
|
||||
systemMemory: 'Memori sistem dikongsi',
|
||||
systemMemoryUsed: 'Memori sistem digunakan',
|
||||
systemMemoryTotal: 'Jumlah memori sistem',
|
||||
@@ -1838,6 +1900,8 @@ const message = {
|
||||
pcieWidth: 'Lebar PCIe (semasa / maksimum)',
|
||||
gpu: 'Pengurusan GPU',
|
||||
monitoringTitle: 'Pemantauan GPU',
|
||||
currentHelper:
|
||||
'Lihat status masa nyata dan penggunaan sumber peranti GPU/NPU/XPU pada nod semasa. Ringkasan di bahagian atas merangkumi semua peranti; metrik terperinci dipaparkan mengikut peranti.',
|
||||
gpuHelper: 'Tiada arahan pengurusan GPU/XPU/NPU yang disokong dikesan. Sila periksa dan cuba lagi!',
|
||||
process: 'Maklumat Proses',
|
||||
type: 'Jenis',
|
||||
|
||||
@@ -1754,8 +1754,8 @@ const message = {
|
||||
running: 'Solicitações em execução',
|
||||
waiting: 'Solicitações em espera',
|
||||
cacheUsage: 'Uso do cache KV',
|
||||
promptThroughput: 'Taxa de tokens de entrada',
|
||||
generationThroughput: 'Taxa de tokens de saída',
|
||||
promptThroughput: 'Taxa de entrada',
|
||||
generationThroughput: 'Taxa de saída',
|
||||
requestThroughput: 'Solicitações concluídas',
|
||||
timeToFirstToken: 'Latência média do primeiro token',
|
||||
timePerOutputToken: 'Latência média entre tokens',
|
||||
@@ -1776,6 +1776,75 @@ const message = {
|
||||
timePerOutputTokenChart: 'Latência entre tokens',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU do host',
|
||||
containerGPU: 'Suporte a GPU em contêineres',
|
||||
monitorAvailable: 'Monitoramento disponível',
|
||||
monitorPartial: 'Monitoramento parcial',
|
||||
notReady: 'Não está pronto',
|
||||
ready: 'Pronto',
|
||||
checkedAt: 'Verificado em',
|
||||
checkDetailsHelp: 'Confira os detalhes, verifique o ambiente e execute a verificação novamente.',
|
||||
driverActionTitle: 'Verifique primeiro o driver da GPU do host',
|
||||
driverActionHelp:
|
||||
'Instale ou repare o driver do dispositivo afetado antes de continuar a verificação do ambiente de contêineres.',
|
||||
driverGuide: 'Ver guia de instalação do driver',
|
||||
toolkitActionTitle: 'O suporte a GPU em contêineres não está pronto',
|
||||
toolkitActionHelp:
|
||||
'Instale ou repare o NVIDIA Container Toolkit e depois verifique a configuração do Docker.',
|
||||
toolkitGuide: 'Ver guia de instalação do Toolkit',
|
||||
dockerActionTitle: 'O suporte a NVIDIA GPU no Docker não está pronto',
|
||||
dockerActionHelp:
|
||||
'Verifique a configuração do runtime NVIDIA no Docker e execute a verificação novamente.',
|
||||
monitorUnaffected: 'Este problema não afeta o monitoramento da GPU do host.',
|
||||
title: 'Verificações do ambiente',
|
||||
passed: 'Verificações do ambiente concluídas com sucesso',
|
||||
issues: 'Problemas de ambiente detectados: {count}. Siga as orientações para verificá-los.',
|
||||
recheck: 'Verificar novamente',
|
||||
installGuide: 'Ver guia de instalação',
|
||||
goContainerSettings: 'Abrir configurações de contêineres',
|
||||
details: 'Detalhes da verificação',
|
||||
vendor: 'Fabricante',
|
||||
gpuCount: 'Quantidade de GPUs',
|
||||
cardCount: 'Quantidade de placas',
|
||||
notDetected: 'Nenhum dispositivo GPU/NPU/XPU compatível foi detectado no nó atual.',
|
||||
unknown:
|
||||
'Não foi possível confirmar o estado do dispositivo. Consulte os detalhes e verifique novamente.',
|
||||
loadFailed: 'Não foi possível ler as informações do dispositivo. Tente novamente.',
|
||||
notApplicable: 'Não se aplica',
|
||||
cudaHelper:
|
||||
'Esta é a versão do CUDA compatível com o driver, não a versão do CUDA Toolkit instalada no host.',
|
||||
partialMemory: 'Alguns dados de memória estão indisponíveis',
|
||||
sharedMemory: 'Memória compartilhada do sistema: {memory}',
|
||||
driver: 'Driver e ferramentas de gerenciamento de dispositivos',
|
||||
nvidiaDriver: 'Driver NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Configuração de GPU NVIDIA no Docker',
|
||||
statusPassed: 'Normal',
|
||||
statusMissing: 'Não detectado',
|
||||
statusUnconfigured: 'Configuração pendente',
|
||||
statusFailed: 'Falha na verificação',
|
||||
statusUnknown: 'Desconhecido',
|
||||
driverMissing:
|
||||
'O driver {vendor} não foi detectado. Instale ou verifique o driver (ferramenta de detecção: {tool}).',
|
||||
driverFailed:
|
||||
'Não foi possível ler as informações do dispositivo usando {tool}. Verifique o estado do driver.',
|
||||
driverUnknown: 'Não foi possível confirmar o estado do driver do dispositivo. Verifique {tool}.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit não foi detectado. Instale e configure a ferramenta antes de usar GPUs NVIDIA em contêineres.',
|
||||
toolkitFailed: 'Não foi possível verificar o NVIDIA Container Toolkit. Consulte os detalhes da falha.',
|
||||
dockerConfigMissing:
|
||||
'Nenhuma entrada runtimes.nvidia foi detectada no arquivo de configuração padrão do Docker. Conclua a configuração seguindo a documentação.',
|
||||
dockerConfigInvalid:
|
||||
'A configuração do ambiente de execução NVIDIA no Docker é inválida. Verifique runtimes.nvidia.path no daemon.json.',
|
||||
dockerConfigPending:
|
||||
'O arquivo de configuração padrão contém a configuração do ambiente de execução NVIDIA, mas o serviço Docker atual ainda não a carregou. Confirme o arquivo de configuração, reinicie o Docker e verifique novamente.',
|
||||
dockerConfigUnreadable:
|
||||
'Não foi possível ler o arquivo de configuração do Docker. Consulte os detalhes da verificação.',
|
||||
dockerUnconfigured: 'A configuração de GPU NVIDIA no Docker está incompleta.',
|
||||
dockerFailed:
|
||||
'Não foi possível verificar a configuração de GPU NVIDIA no Docker. Consulte os detalhes da falha.',
|
||||
},
|
||||
systemMemory: 'Memória compartilhada do sistema',
|
||||
systemMemoryUsed: 'Memória do sistema em uso',
|
||||
systemMemoryTotal: 'Memória total do sistema',
|
||||
@@ -1836,6 +1905,8 @@ const message = {
|
||||
pcieWidth: 'Largura PCIe (atual / máxima)',
|
||||
gpu: 'Gerenciamento de GPU',
|
||||
monitoringTitle: 'Monitoramento de GPU',
|
||||
currentHelper:
|
||||
'Veja o estado em tempo real e o uso de recursos dos dispositivos GPU/NPU/XPU no nó atual. O resumo superior inclui todos os dispositivos; as métricas detalhadas são exibidas por dispositivo.',
|
||||
gpuHelper:
|
||||
'Nenhum comando de gerenciamento de GPU/XPU/NPU compatível foi detectado. Verifique e tente novamente!',
|
||||
process: 'Informações do Processo',
|
||||
|
||||
@@ -1747,8 +1747,8 @@ const message = {
|
||||
running: 'Выполняемые запросы',
|
||||
waiting: 'Ожидающие запросы',
|
||||
cacheUsage: 'Использование KV-кэша',
|
||||
promptThroughput: 'Скорость входных токенов',
|
||||
generationThroughput: 'Скорость выходных токенов',
|
||||
promptThroughput: 'Скорость ввода',
|
||||
generationThroughput: 'Скорость вывода',
|
||||
requestThroughput: 'Завершённые запросы',
|
||||
timeToFirstToken: 'Среднее время до первого токена',
|
||||
timePerOutputToken: 'Средняя задержка между токенами',
|
||||
@@ -1768,6 +1768,73 @@ const message = {
|
||||
timePerOutputTokenChart: 'Задержка между токенами',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'GPU хоста',
|
||||
containerGPU: 'Поддержка GPU в контейнерах',
|
||||
monitorAvailable: 'Мониторинг доступен',
|
||||
monitorPartial: 'Частичный мониторинг',
|
||||
notReady: 'Не готово',
|
||||
ready: 'Готово',
|
||||
checkedAt: 'Время проверки',
|
||||
checkDetailsHelp: 'Изучите результаты проверки, проверьте состояние среды и повторите проверку.',
|
||||
driverActionTitle: 'Сначала проверьте драйвер GPU хоста',
|
||||
driverActionHelp:
|
||||
'Установите или восстановите драйвер проблемного устройства, затем продолжите проверку среды контейнеров.',
|
||||
driverGuide: 'Инструкция по установке драйвера',
|
||||
toolkitActionTitle: 'Поддержка GPU в контейнерах не готова',
|
||||
toolkitActionHelp:
|
||||
'Установите или восстановите NVIDIA Container Toolkit, затем проверьте настройки Docker.',
|
||||
toolkitGuide: 'Инструкция по установке Toolkit',
|
||||
dockerActionTitle: 'Поддержка NVIDIA GPU в Docker не готова',
|
||||
dockerActionHelp: 'Проверьте настройки среды выполнения NVIDIA в Docker и повторите проверку.',
|
||||
monitorUnaffected: 'Эта проблема не влияет на мониторинг GPU хоста.',
|
||||
title: 'Проверка окружения',
|
||||
passed: 'Проверки окружения пройдены',
|
||||
issues: 'Обнаружено проблем окружения: {count}. Проверьте их согласно подсказкам.',
|
||||
recheck: 'Проверить снова',
|
||||
installGuide: 'Руководство по установке',
|
||||
goContainerSettings: 'Открыть настройки контейнеров',
|
||||
details: 'Подробности проверки',
|
||||
vendor: 'Производитель',
|
||||
gpuCount: 'Количество GPU',
|
||||
cardCount: 'Количество карт',
|
||||
notDetected: 'На текущем узле не обнаружены поддерживаемые устройства GPU/NPU/XPU.',
|
||||
unknown:
|
||||
'Не удалось определить состояние устройства. Просмотрите подробности проверки и повторите попытку.',
|
||||
loadFailed: 'Не удалось прочитать сведения об устройстве. Повторите попытку.',
|
||||
notApplicable: 'Не применимо',
|
||||
cudaHelper:
|
||||
'Это версия CUDA, поддерживаемая драйвером, а не версия CUDA Toolkit, установленная на хосте.',
|
||||
partialMemory: 'Часть данных о памяти недоступна',
|
||||
sharedMemory: 'Общая системная память: {memory}',
|
||||
driver: 'Драйвер и средства управления устройствами',
|
||||
nvidiaDriver: 'Драйвер NVIDIA',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Настройка NVIDIA GPU в Docker',
|
||||
statusPassed: 'Норма',
|
||||
statusMissing: 'Не обнаружено',
|
||||
statusUnconfigured: 'Требуется настройка',
|
||||
statusFailed: 'Ошибка проверки',
|
||||
statusUnknown: 'Неизвестно',
|
||||
driverMissing:
|
||||
'Драйвер {vendor} не обнаружен. Установите или проверьте драйвер (средство обнаружения: {tool}).',
|
||||
driverFailed:
|
||||
'Не удалось прочитать сведения об устройстве с помощью {tool}. Проверьте состояние драйвера.',
|
||||
driverUnknown: 'Не удалось определить состояние драйвера устройства. Проверьте {tool}.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit не обнаружен. Установите и настройте его перед использованием NVIDIA GPU в контейнерах.',
|
||||
toolkitFailed: 'Не удалось проверить NVIDIA Container Toolkit. Просмотрите сведения об ошибке.',
|
||||
dockerConfigMissing:
|
||||
'Запись runtimes.nvidia не обнаружена в файле конфигурации Docker по умолчанию. Завершите настройку согласно документации.',
|
||||
dockerConfigInvalid:
|
||||
'Конфигурация среды выполнения NVIDIA в Docker некорректна. Проверьте runtimes.nvidia.path в daemon.json.',
|
||||
dockerConfigPending:
|
||||
'Файл конфигурации по умолчанию содержит настройки среды выполнения NVIDIA, но текущая служба Docker ещё не загрузила их. Проверьте файл конфигурации, перезапустите Docker и повторите проверку.',
|
||||
dockerConfigUnreadable:
|
||||
'Не удалось прочитать файл конфигурации Docker. Просмотрите подробности проверки.',
|
||||
dockerUnconfigured: 'Настройка NVIDIA GPU в Docker не завершена.',
|
||||
dockerFailed: 'Не удалось проверить настройку NVIDIA GPU в Docker. Просмотрите сведения об ошибке.',
|
||||
},
|
||||
systemMemory: 'Общая системная память',
|
||||
systemMemoryUsed: 'Использовано системной памяти',
|
||||
systemMemoryTotal: 'Всего системной памяти',
|
||||
@@ -1828,6 +1895,8 @@ const message = {
|
||||
pcieWidth: 'Ширина PCIe (текущая / максимальная)',
|
||||
gpu: 'Управление GPU',
|
||||
monitoringTitle: 'Мониторинг GPU',
|
||||
currentHelper:
|
||||
'Просматривайте состояние и использование ресурсов устройств GPU/NPU/XPU текущего узла в реальном времени. Вверху показана сводка по всем устройствам, а подробные показатели отображаются для каждого устройства отдельно.',
|
||||
gpuHelper: 'Поддерживаемая команда управления GPU/XPU/NPU не обнаружена. Проверьте и повторите попытку!',
|
||||
process: 'Информация о Процессе',
|
||||
type: 'Тип',
|
||||
|
||||
@@ -1750,8 +1750,8 @@ const message = {
|
||||
running: 'Çalışan istekler',
|
||||
waiting: 'Bekleyen istekler',
|
||||
cacheUsage: 'KV önbellek kullanımı',
|
||||
promptThroughput: 'Girdi token hızı',
|
||||
generationThroughput: 'Çıktı token hızı',
|
||||
promptThroughput: 'Girdi hızı',
|
||||
generationThroughput: 'Çıktı hızı',
|
||||
requestThroughput: 'Tamamlanan istek hızı',
|
||||
timeToFirstToken: 'Ortalama ilk token gecikmesi',
|
||||
timePerOutputToken: 'Ortalama token arası gecikme',
|
||||
@@ -1772,6 +1772,71 @@ const message = {
|
||||
timePerOutputTokenChart: 'Token arası gecikme',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: 'Ana makine GPU’su',
|
||||
containerGPU: 'Konteyner GPU desteği',
|
||||
monitorAvailable: 'İzleme kullanılabilir',
|
||||
monitorPartial: 'Kısmi izleme',
|
||||
notReady: 'Hazır değil',
|
||||
ready: 'Hazır',
|
||||
checkedAt: 'Kontrol zamanı',
|
||||
checkDetailsHelp: 'Kontrol ayrıntılarını inceleyin, ortam durumunu doğrulayın ve yeniden kontrol edin.',
|
||||
driverActionTitle: 'Önce ana makine GPU sürücüsünü kontrol edin',
|
||||
driverActionHelp:
|
||||
'Konteyner ortamını kontrol etmeye devam etmeden önce sorunlu aygıtın sürücüsünü kurun veya onarın.',
|
||||
driverGuide: 'Sürücü kurulum kılavuzunu görüntüle',
|
||||
toolkitActionTitle: 'Konteyner GPU desteği hazır değil',
|
||||
toolkitActionHelp:
|
||||
'Önce NVIDIA Container Toolkit’i kurun veya onarın, ardından Docker yapılandırmasını kontrol edin.',
|
||||
toolkitGuide: 'Toolkit kurulum kılavuzunu görüntüle',
|
||||
dockerActionTitle: 'Docker NVIDIA GPU desteği hazır değil',
|
||||
dockerActionHelp:
|
||||
'Docker içindeki NVIDIA çalışma zamanı yapılandırmasını kontrol edip yeniden deneyin.',
|
||||
monitorUnaffected: 'Bu sorun ana makine GPU izlemesini etkilemez.',
|
||||
title: 'Ortam denetimleri',
|
||||
passed: 'Ortam denetimleri başarılı',
|
||||
issues: '{count} ortam sorunu algılandı. Denetlemek için yönergeleri izleyin.',
|
||||
recheck: 'Yeniden denetle',
|
||||
installGuide: 'Kurulum kılavuzunu görüntüle',
|
||||
goContainerSettings: 'Kapsayıcı ayarlarını aç',
|
||||
details: 'Denetim ayrıntıları',
|
||||
vendor: 'Üretici',
|
||||
gpuCount: 'GPU sayısı',
|
||||
cardCount: 'Kart sayısı',
|
||||
notDetected: 'Geçerli düğümde desteklenen GPU/NPU/XPU aygıtı algılanmadı.',
|
||||
unknown: 'Aygıt durumu doğrulanamadı. Denetim ayrıntılarını inceleyip yeniden deneyin.',
|
||||
loadFailed: 'Aygıt bilgileri okunamadı. Lütfen yeniden deneyin.',
|
||||
notApplicable: 'Uygulanamaz',
|
||||
cudaHelper:
|
||||
'Bu, sürücünün desteklediği CUDA sürümüdür; ana makinede kurulu CUDA Toolkit sürümü değildir.',
|
||||
partialMemory: 'Bazı bellek verileri alınamadı',
|
||||
sharedMemory: 'Paylaşılan sistem belleği: {memory}',
|
||||
driver: 'Sürücü ve aygıt yönetim araçları',
|
||||
nvidiaDriver: 'NVIDIA sürücüsü',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker NVIDIA GPU yapılandırması',
|
||||
statusPassed: 'Normal',
|
||||
statusMissing: 'Algılanmadı',
|
||||
statusUnconfigured: 'Yapılandırma gerekli',
|
||||
statusFailed: 'Denetim başarısız',
|
||||
statusUnknown: 'Bilinmiyor',
|
||||
driverMissing:
|
||||
'{vendor} sürücüsü algılanmadı. Sürücüyü kurun veya denetleyin (algılama aracı: {tool}).',
|
||||
driverFailed: 'Aygıt bilgileri {tool} ile okunamadı. Sürücü durumunu denetleyin.',
|
||||
driverUnknown: 'Aygıt sürücüsünün durumu doğrulanamadı. {tool} aracını denetleyin.',
|
||||
toolkitMissing:
|
||||
'NVIDIA Container Toolkit algılanmadı. Kapsayıcılarda NVIDIA GPU kullanmadan önce kurulum ve yapılandırmayı tamamlayın.',
|
||||
toolkitFailed: 'NVIDIA Container Toolkit denetlenemedi. Hata ayrıntılarını inceleyin.',
|
||||
dockerConfigMissing:
|
||||
'Varsayılan Docker yapılandırma dosyasında runtimes.nvidia girdisi algılanmadı. Yapılandırmayı belgelere göre tamamlayın.',
|
||||
dockerConfigInvalid:
|
||||
'Docker NVIDIA çalışma zamanı yapılandırması geçersiz. daemon.json dosyasındaki runtimes.nvidia.path değerini denetleyin.',
|
||||
dockerConfigPending:
|
||||
'Varsayılan yapılandırma dosyasında NVIDIA çalışma zamanı yapılandırması var, ancak mevcut Docker hizmeti bunu henüz yüklemedi. Yapılandırma dosyasını doğrulayın, Docker hizmetini yeniden başlatıp tekrar denetleyin.',
|
||||
dockerConfigUnreadable: 'Docker yapılandırma dosyası okunamadı. Denetim ayrıntılarını inceleyin.',
|
||||
dockerUnconfigured: 'Docker NVIDIA GPU yapılandırması tamamlanmadı.',
|
||||
dockerFailed: 'Docker NVIDIA GPU yapılandırması denetlenemedi. Hata ayrıntılarını inceleyin.',
|
||||
},
|
||||
systemMemory: 'Paylaşılan sistem belleği',
|
||||
systemMemoryUsed: 'Kullanılan sistem belleği',
|
||||
systemMemoryTotal: 'Toplam sistem belleği',
|
||||
@@ -1831,6 +1896,8 @@ const message = {
|
||||
pcieWidth: 'PCIe genişliği (geçerli / en yüksek)',
|
||||
gpu: 'GPU Yönetimi',
|
||||
monitoringTitle: 'GPU İzleme',
|
||||
currentHelper:
|
||||
'Geçerli düğümdeki GPU/NPU/XPU aygıtlarının anlık durumunu ve kaynak kullanımını görüntüleyin. Üstteki özet tüm aygıtları kapsar; ayrıntılı ölçümler aygıt bazında gösterilir.',
|
||||
gpuHelper: 'Desteklenen bir GPU/XPU/NPU yönetim komutu algılanmadı. Lütfen kontrol edip tekrar deneyin!',
|
||||
process: 'İşlem Bilgisi',
|
||||
type: 'Tür',
|
||||
|
||||
@@ -1636,8 +1636,8 @@ const message = {
|
||||
running: '執行中請求',
|
||||
waiting: '等待中請求',
|
||||
cacheUsage: 'KV Cache 使用率',
|
||||
promptThroughput: '輸入 Token 吞吐',
|
||||
generationThroughput: '輸出 Token 吞吐',
|
||||
promptThroughput: '輸入吞吐',
|
||||
generationThroughput: '輸出吞吐',
|
||||
requestThroughput: '完成請求速率',
|
||||
timeToFirstToken: '平均首 Token 延遲',
|
||||
timePerOutputToken: '平均 Token 間延遲',
|
||||
@@ -1656,6 +1656,64 @@ const message = {
|
||||
timePerOutputTokenChart: 'Token 間延遲',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: '主機 GPU',
|
||||
containerGPU: '容器 GPU 支援',
|
||||
monitorAvailable: '可監控',
|
||||
monitorPartial: '部分可監控',
|
||||
notReady: '尚未就緒',
|
||||
ready: '已就緒',
|
||||
checkedAt: '檢測時間',
|
||||
checkDetailsHelp: '請查看檢測詳情,確認環境狀態後重新檢測。',
|
||||
driverActionTitle: '優先檢查主機 GPU 驅動程式',
|
||||
driverActionHelp: '請先安裝或修復異常裝置的驅動程式,驅動程式就緒後再繼續檢查容器環境。',
|
||||
driverGuide: '查看驅動程式安裝指引',
|
||||
toolkitActionTitle: '容器 GPU 支援尚未就緒',
|
||||
toolkitActionHelp: '請先安裝或修復 NVIDIA Container Toolkit,再檢查 Docker 設定。',
|
||||
toolkitGuide: '查看 Toolkit 安裝指引',
|
||||
dockerActionTitle: 'Docker 的 NVIDIA GPU 支援尚未就緒',
|
||||
dockerActionHelp: '請檢查 Docker 的 NVIDIA 執行環境設定,完成後重新檢測。',
|
||||
monitorUnaffected: '主機 GPU 監控不受此問題影響。',
|
||||
title: '環境檢查',
|
||||
passed: '環境檢查通過',
|
||||
issues: '偵測到 {count} 項環境問題,請依照提示檢查。',
|
||||
recheck: '重新偵測',
|
||||
installGuide: '查看安裝文件',
|
||||
goContainerSettings: '前往容器設定',
|
||||
details: '偵測詳情',
|
||||
vendor: '廠商',
|
||||
gpuCount: 'GPU 數量',
|
||||
cardCount: '卡數量',
|
||||
notDetected: '目前節點未偵測到支援的 GPU/NPU/XPU 裝置。',
|
||||
unknown: '無法確認裝置狀態,請查看偵測詳情後重新偵測。',
|
||||
loadFailed: '無法讀取裝置資訊,請重試。',
|
||||
notApplicable: '不適用',
|
||||
cudaHelper: '此版本表示驅動程式支援的 CUDA 版本,不代表主機已安裝的 CUDA Toolkit。',
|
||||
partialMemory: '部分顯示記憶體資料未取得',
|
||||
sharedMemory: '共用系統記憶體:{memory}',
|
||||
driver: '驅動程式與裝置管理工具',
|
||||
nvidiaDriver: 'NVIDIA 驅動',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker NVIDIA GPU 設定',
|
||||
statusPassed: '正常',
|
||||
statusMissing: '未偵測到',
|
||||
statusUnconfigured: '待設定',
|
||||
statusFailed: '偵測失敗',
|
||||
statusUnknown: '未知',
|
||||
driverMissing: '未偵測到 {vendor} 驅動程式,請安裝或檢查驅動程式(偵測工具:{tool})。',
|
||||
driverFailed: '無法透過 {tool} 讀取裝置資訊,請檢查驅動程式狀態。',
|
||||
driverUnknown: '無法確認裝置驅動程式狀態,請檢查 {tool}。',
|
||||
toolkitMissing: '未偵測到 NVIDIA Container Toolkit,容器使用 NVIDIA GPU 前需完成安裝與設定。',
|
||||
toolkitFailed: '無法偵測 NVIDIA Container Toolkit,請查看失敗原因。',
|
||||
dockerConfigMissing: 'Docker 預設設定檔中未偵測到 runtimes.nvidia,請依照文件完成設定。',
|
||||
dockerConfigInvalid:
|
||||
'Docker 的 NVIDIA 執行階段設定有誤,請檢查 daemon.json 中的 runtimes.nvidia.path。',
|
||||
dockerConfigPending:
|
||||
'預設設定檔中已存在 NVIDIA 執行階段設定,但目前 Docker 尚未載入,請確認設定檔並重新啟動 Docker 後重新偵測。',
|
||||
dockerConfigUnreadable: '無法讀取 Docker 設定檔,請查看偵測詳情。',
|
||||
dockerUnconfigured: '尚未完成 Docker 的 NVIDIA GPU 設定。',
|
||||
dockerFailed: '無法偵測 Docker 的 NVIDIA GPU 設定,請查看失敗原因。',
|
||||
},
|
||||
systemMemory: '系統共享記憶體',
|
||||
systemMemoryUsed: '系統已用記憶體',
|
||||
systemMemoryTotal: '系統總記憶體',
|
||||
@@ -1713,6 +1771,8 @@ const message = {
|
||||
pcieWidth: 'PCIe 寬度(目前 / 最大)',
|
||||
gpu: 'GPU 管理',
|
||||
monitoringTitle: 'GPU 監控',
|
||||
currentHelper:
|
||||
'查看目前節點 GPU/NPU/XPU 裝置的即時運作狀態與資源使用情況。頂部彙總所有裝置,詳細指標依裝置顯示。',
|
||||
gpuHelper: '目前系統未偵測到支援的 GPU/XPU/NPU 管理指令,請檢查後重試',
|
||||
process: '行程資訊',
|
||||
type: '類型',
|
||||
|
||||
@@ -1649,8 +1649,8 @@ const message = {
|
||||
running: '运行中请求',
|
||||
waiting: '等待中请求',
|
||||
cacheUsage: 'KV Cache 使用率',
|
||||
promptThroughput: '输入 Token 吞吐',
|
||||
generationThroughput: '输出 Token 吞吐',
|
||||
promptThroughput: '输入吞吐',
|
||||
generationThroughput: '输出吞吐',
|
||||
requestThroughput: '完成请求速率',
|
||||
timeToFirstToken: '平均首 Token 延迟',
|
||||
timePerOutputToken: '平均 Token 间延迟',
|
||||
@@ -1669,6 +1669,63 @@ const message = {
|
||||
timePerOutputTokenChart: 'Token 间延迟',
|
||||
},
|
||||
gpu: {
|
||||
environment: {
|
||||
hostGPU: '宿主机 GPU',
|
||||
containerGPU: '容器 GPU 支持',
|
||||
monitorAvailable: '可监控',
|
||||
monitorPartial: '部分可监控',
|
||||
notReady: '未就绪',
|
||||
ready: '已就绪',
|
||||
checkedAt: '检测时间',
|
||||
checkDetailsHelp: '请查看检测详情,确认环境状态后重新检测。',
|
||||
driverActionTitle: '优先检查宿主机 GPU 驱动',
|
||||
driverActionHelp: '请先安装或修复异常设备的驱动,驱动就绪后再继续检查容器环境。',
|
||||
driverGuide: '查看驱动安装指引',
|
||||
toolkitActionTitle: '容器 GPU 支持未就绪',
|
||||
toolkitActionHelp: '请先安装或修复 NVIDIA Container Toolkit,再检查 Docker 配置。',
|
||||
toolkitGuide: '查看 Toolkit 安装指引',
|
||||
dockerActionTitle: 'Docker 的 NVIDIA GPU 支持未就绪',
|
||||
dockerActionHelp: '请检查 Docker 的 NVIDIA 运行时配置,完成后重新检测。',
|
||||
monitorUnaffected: '宿主机 GPU 监控不受此问题影响。',
|
||||
title: '环境检查',
|
||||
passed: '环境检查通过',
|
||||
issues: '检测到 {count} 项环境问题,请根据提示检查。',
|
||||
recheck: '重新检测',
|
||||
installGuide: '查看安装文档',
|
||||
goContainerSettings: '前往容器配置',
|
||||
details: '检测详情',
|
||||
vendor: '厂商',
|
||||
gpuCount: 'GPU 数量',
|
||||
cardCount: '卡数量',
|
||||
notDetected: '当前节点未检测到支持的 GPU/NPU/XPU 设备。',
|
||||
unknown: '无法确认设备状态,请查看检测详情后重新检测。',
|
||||
loadFailed: '无法读取设备信息,请重试。',
|
||||
notApplicable: '不适用',
|
||||
cudaHelper: '此版本表示驱动支持的 CUDA 版本,不代表宿主机已安装的 CUDA Toolkit。',
|
||||
partialMemory: '部分显存数据未获取',
|
||||
sharedMemory: '共享系统内存:{memory}',
|
||||
driver: '驱动与设备管理工具',
|
||||
nvidiaDriver: 'NVIDIA 驱动',
|
||||
toolkit: 'NVIDIA Container Toolkit',
|
||||
docker: 'Docker NVIDIA GPU 配置',
|
||||
statusPassed: '正常',
|
||||
statusMissing: '未检测到',
|
||||
statusUnconfigured: '待配置',
|
||||
statusFailed: '检测失败',
|
||||
statusUnknown: '未知',
|
||||
driverMissing: '未检测到 {vendor} 驱动,请安装或检查驱动(检测工具:{tool})。',
|
||||
driverFailed: '无法通过 {tool} 读取设备信息,请检查驱动状态。',
|
||||
driverUnknown: '无法确认设备驱动状态,请检查 {tool}。',
|
||||
toolkitMissing: '未检测到 NVIDIA Container Toolkit,容器使用 NVIDIA GPU 前需完成安装与配置。',
|
||||
toolkitFailed: '无法检测 NVIDIA Container Toolkit,请查看失败原因。',
|
||||
dockerConfigMissing: 'Docker 默认配置文件中未检测到 runtimes.nvidia,请根据文档完成配置。',
|
||||
dockerConfigInvalid: 'Docker 的 NVIDIA 运行时配置有误,请检查 daemon.json 中的 runtimes.nvidia.path。',
|
||||
dockerConfigPending:
|
||||
'默认配置文件中已存在 NVIDIA 运行时配置,但当前 Docker 尚未加载,请确认配置文件并重启 Docker 后重新检测。',
|
||||
dockerConfigUnreadable: '无法读取 Docker 配置文件,请查看检测详情。',
|
||||
dockerUnconfigured: '尚未完成 Docker 的 NVIDIA GPU 配置。',
|
||||
dockerFailed: '无法检测 Docker 的 NVIDIA GPU 配置,请查看失败原因。',
|
||||
},
|
||||
systemMemory: '系统共享内存',
|
||||
systemMemoryUsed: '系统已用内存',
|
||||
systemMemoryTotal: '系统总内存',
|
||||
@@ -1726,6 +1783,8 @@ const message = {
|
||||
pcieWidth: 'PCIe 宽度(当前 / 最大)',
|
||||
gpu: 'GPU 管理',
|
||||
monitoringTitle: 'GPU 监控',
|
||||
currentHelper:
|
||||
'查看当前节点 GPU/NPU/XPU 设备的实时运行状态与资源使用情况。顶部汇总全部设备,详细指标按设备展示。',
|
||||
gpuHelper: '当前系统未检测到支持的 GPU/XPU/NPU 管理指令,请检查后重试!',
|
||||
process: '进程信息',
|
||||
processCount: '进程数',
|
||||
|
||||
Vendored
+1
@@ -28,5 +28,6 @@ declare interface RouterButton {
|
||||
path?: string;
|
||||
name?: string;
|
||||
count?: number;
|
||||
disabled?: boolean;
|
||||
permission?: string | string[];
|
||||
}
|
||||
|
||||
@@ -1,32 +1,216 @@
|
||||
<template>
|
||||
<div>
|
||||
<RouterMenu />
|
||||
<RouterMenu :history-disabled="historyDisabled" />
|
||||
<div>
|
||||
<LayoutContent v-loading="loading" :title="$t('aiTools.gpu.monitoringTitle')" v-if="hasAccelerators">
|
||||
<LayoutContent v-loading="loading" :title="$t('aiTools.gpu.monitoringTitle')">
|
||||
<template #leftToolBar>
|
||||
<h3 class="environment-heading">
|
||||
{{ $t(showEnvironment ? 'aiTools.gpu.environment.title' : 'aiTools.gpu.monitoringTitle') }}
|
||||
</h3>
|
||||
</template>
|
||||
<template #rightToolBar>
|
||||
<TableSetting title="gpu-refresh" @search="refresh()" />
|
||||
<TableRefresh @search="refresh()" />
|
||||
<TableSetting title="gpu-refresh" @search="search()" />
|
||||
<el-tooltip :content="$t('aiTools.gpu.environment.recheck')">
|
||||
<TableRefresh :disabled="loading" @search="refresh()" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #main>
|
||||
<div class="device-overview">
|
||||
<el-alert
|
||||
v-if="loadFailed"
|
||||
class="common-prompt"
|
||||
:title="$t('aiTools.gpu.environment.loadFailed')"
|
||||
type="error"
|
||||
:closable="false"
|
||||
show-icon
|
||||
>
|
||||
<el-button type="primary" link :disabled="loading" @click="refresh()">
|
||||
{{ $t('aiTools.gpu.environment.recheck') }}
|
||||
</el-button>
|
||||
</el-alert>
|
||||
<section v-else-if="showEnvironment" class="environment-status">
|
||||
<div class="environment-row">
|
||||
<div class="environment-identity">
|
||||
<el-icon :size="22"><Monitor /></el-icon>
|
||||
<div>
|
||||
<strong>{{ $t('aiTools.gpu.environment.hostGPU') }}</strong>
|
||||
<div class="environment-description">
|
||||
<template v-if="driverChecks.length">
|
||||
<span v-for="check in driverChecks" :key="check.vendor">
|
||||
{{ checkTitle(check) }} · {{ checkStatus(check) }}
|
||||
{{ check.version }}
|
||||
</span>
|
||||
</template>
|
||||
<span v-else>{{ hasAccelerators ? deviceCountText : emptyDescription }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tag :type="hostEnvironmentStatus.type">
|
||||
{{ $t('aiTools.gpu.environment.' + hostEnvironmentStatus.label) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div v-if="containerChecks.length" class="environment-row">
|
||||
<div class="environment-identity">
|
||||
<el-icon :size="22"><Box /></el-icon>
|
||||
<div>
|
||||
<strong>{{ $t('aiTools.gpu.environment.containerGPU') }}</strong>
|
||||
<div class="environment-description">
|
||||
<span v-for="check in containerChecks" :key="check.item">
|
||||
{{ checkTitle(check) }} · {{ checkStatus(check) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tag :type="containerEnvironmentStatus.type">
|
||||
{{ $t('aiTools.gpu.environment.' + containerEnvironmentStatus.label) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div v-if="environmentGuidance" class="environment-guidance">
|
||||
<div>
|
||||
<strong>{{ $t('aiTools.gpu.environment.' + environmentGuidance.title) }}</strong>
|
||||
<p>
|
||||
<template v-if="environmentGuidance.item !== 'driver' && hasAccelerators">
|
||||
{{ $t('aiTools.gpu.environment.monitorUnaffected') }}
|
||||
</template>
|
||||
{{ $t('aiTools.gpu.environment.' + environmentGuidance.description) }}
|
||||
</p>
|
||||
</div>
|
||||
<el-button
|
||||
v-if="environmentGuidance.action === 'docker'"
|
||||
type="primary"
|
||||
@click="routerToName('ContainerSetting')"
|
||||
>
|
||||
{{ $t('aiTools.gpu.environment.goContainerSettings') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="environmentGuidance.action === 'details'"
|
||||
type="primary"
|
||||
@click="environmentDetails = ['environment']"
|
||||
>
|
||||
{{ $t('aiTools.gpu.environment.details') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
tag="a"
|
||||
type="primary"
|
||||
href="https://docs.fit2cloud.com/1panel/faq/gpu-driver"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $t('aiTools.gpu.environment.' + environmentGuidance.action) }}
|
||||
</el-button>
|
||||
</div>
|
||||
</section>
|
||||
<el-collapse
|
||||
v-if="!loadFailed && (environmentChecks.length || gpuInfo.warnings?.length)"
|
||||
v-model="environmentDetails"
|
||||
class="environment-details"
|
||||
>
|
||||
<el-collapse-item :title="$t('aiTools.gpu.environment.details')" name="environment">
|
||||
<div v-for="check in environmentChecks" :key="`${check.vendor}-${check.item}`" class="mb-2">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span>{{ checkTitle(check) }}</span>
|
||||
<el-tag :type="checkTagType(check)" size="small">
|
||||
{{ checkStatus(check) }}
|
||||
</el-tag>
|
||||
<span v-if="check.version">{{ check.version }}</span>
|
||||
</div>
|
||||
<p v-if="check.status !== 'passed'" class="environment-check-description">
|
||||
{{ checkDescription(check) }}
|
||||
</p>
|
||||
<pre v-if="check.reason" class="whitespace-pre-wrap break-words mt-1">{{
|
||||
check.reason
|
||||
}}</pre>
|
||||
</div>
|
||||
<div v-for="warning in gpuInfo.warnings || []" :key="warning" class="break-words">
|
||||
{{ warning }}
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<div
|
||||
v-if="showEnvironment && !loadFailed && gpuInfo.environment?.checkedAt"
|
||||
class="input-help mb-4"
|
||||
>
|
||||
{{ $t('aiTools.gpu.environment.checkedAt') }}:
|
||||
{{ new Date(gpuInfo.environment.checkedAt).toLocaleString() }}
|
||||
</div>
|
||||
<div v-for="summary in overviewRows" :key="summary.vendor" class="device-overview mb-2">
|
||||
<div class="overview-item">
|
||||
<span>{{ $t('aiTools.gpu.environment.vendor') }}</span>
|
||||
<strong>{{ vendorTitle(summary.vendor) }}</strong>
|
||||
</div>
|
||||
<div class="overview-item">
|
||||
<span>{{ $t('aiTools.gpu.driverVersion') }}</span>
|
||||
<strong>{{ gpuInfo.driverVersion }}</strong>
|
||||
<strong>{{ displayValue(summary.driverVersion) }}</strong>
|
||||
</div>
|
||||
<div v-if="gpuInfo.cudaVersion" class="overview-item">
|
||||
<div class="overview-item">
|
||||
<span>{{ $t('aiTools.gpu.cudaVersion') }}</span>
|
||||
<strong>{{ gpuInfo.cudaVersion }}</strong>
|
||||
<el-tooltip
|
||||
v-if="summary.vendor === 'nvidia' || summary.cudaVersion"
|
||||
:content="$t('aiTools.gpu.environment.cudaHelper')"
|
||||
>
|
||||
<strong>{{ displayValue(summary.cudaVersion) }}</strong>
|
||||
</el-tooltip>
|
||||
<strong v-else>{{ $t('aiTools.gpu.environment.notApplicable') }}</strong>
|
||||
</div>
|
||||
<div v-if="gpuInfo.collectedAt" class="overview-item">
|
||||
<span>{{ $t('aiTools.gpu.collectedAt') }}</span>
|
||||
<strong>{{ new Date(gpuInfo.collectedAt).toLocaleString() }}</strong>
|
||||
<div class="overview-item">
|
||||
<span>
|
||||
{{
|
||||
$t(
|
||||
summary.vendor === 'intel' || summary.vendor === 'xpu'
|
||||
? 'aiTools.gpu.environment.gpuCount'
|
||||
: 'aiTools.gpu.environment.cardCount',
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<strong>{{ summary.cardCountText }}</strong>
|
||||
</div>
|
||||
<div class="overview-count">{{ deviceCountText }}</div>
|
||||
<div class="overview-item">
|
||||
<span>
|
||||
{{
|
||||
$t(
|
||||
summary.sharedMemoryOnly
|
||||
? 'aiTools.gpu.systemMemory'
|
||||
: 'aiTools.gpu.memoryTotal',
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:disabled="!summary.sharedMemoryOnly && !summary.memoryPartial"
|
||||
:content="summaryMemoryTooltip(summary)"
|
||||
>
|
||||
<strong>
|
||||
{{
|
||||
formatSummaryMemory(
|
||||
summary.sharedMemoryOnly ? summary.sharedMemoryTotal : summary.memoryTotal,
|
||||
)
|
||||
}}
|
||||
</strong>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="!summary.sharedMemoryOnly && summary.sharedMemoryTotal !== null"
|
||||
:content="$t('aiTools.gpu.systemMemoryHelper')"
|
||||
>
|
||||
<span class="whitespace-normal">
|
||||
{{
|
||||
$t('aiTools.gpu.environment.sharedMemory', {
|
||||
memory: formatSummaryMemory(summary.sharedMemoryTotal),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="gpu-group-list">
|
||||
</div>
|
||||
<div v-if="hasAccelerators && gpuInfo.collectedAt" class="input-help">
|
||||
{{ $t('aiTools.gpu.collectedAt') }}:
|
||||
{{ new Date(gpuInfo.collectedAt).toLocaleString() }}
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!hasAccelerators && !loading && !loadFailed && !showEnvironment"
|
||||
:description="emptyDescription"
|
||||
/>
|
||||
<div v-if="hasAccelerators" class="gpu-group-list">
|
||||
<section v-for="group in gpuGroups" :key="group.key" class="gpu-group">
|
||||
<div class="group-header">
|
||||
<div v-if="group.title" class="group-header">
|
||||
<div class="group-identity">
|
||||
<strong>{{ group.title }}</strong>
|
||||
</div>
|
||||
@@ -79,7 +263,12 @@
|
||||
>
|
||||
{{ $t('commons.button.view') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="openHistory(item)">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
:disabled="historyDisabled"
|
||||
@click="openHistory(item)"
|
||||
>
|
||||
{{ $t('aiTools.gpu.history') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -168,10 +357,6 @@
|
||||
</div>
|
||||
</section>
|
||||
<section v-if="xpuInfo.xpu.length" class="gpu-group">
|
||||
<div class="group-header">
|
||||
<div class="group-identity"><strong>XPU</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="device-card-grid">
|
||||
<el-card
|
||||
v-for="item in xpuInfo.xpu"
|
||||
@@ -208,7 +393,12 @@
|
||||
>
|
||||
{{ $t('commons.button.view') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="openHistory(item)">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
:disabled="historyDisabled"
|
||||
@click="openHistory(item)"
|
||||
>
|
||||
{{ $t('aiTools.gpu.history') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -321,42 +511,34 @@
|
||||
/>
|
||||
</template>
|
||||
</DialogPro>
|
||||
<LayoutContent :title="$t('aiTools.gpu.monitoringTitle')" :divider="true" v-if="!hasAccelerators && !loading">
|
||||
<template #rightToolBar>
|
||||
<TableRefresh @search="refresh()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<div class="app-warn">
|
||||
<div class="flx-center">
|
||||
<span>{{ $t('aiTools.gpu.gpuHelper') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<img src="@/assets/images/no_app.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</LayoutContent>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { computed, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Box, InfoFilled, Monitor } from '@element-plus/icons-vue';
|
||||
import { loadGPUInfo } from '@/api/modules/ai';
|
||||
import RouterMenu from '@/views/ai/gpu/index.vue';
|
||||
import { AI } from '@/api/interface/ai';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
import { routerToName } from '@/utils/router';
|
||||
import i18n from '@/lang';
|
||||
import { MsgWarning } from '@/utils/message';
|
||||
import { computeSizeForDocker } from '@/utils/size';
|
||||
import DeviceDetails, { type DetailSection } from './components/DeviceDetails.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const loading = ref();
|
||||
const route = useRoute();
|
||||
const pagePath = route.path;
|
||||
const { currentNode } = useGlobalStore();
|
||||
const loading = ref(false);
|
||||
const loadFailed = ref(false);
|
||||
const environmentDetails = ref<string[]>([]);
|
||||
const processDrawerVisible = ref(false);
|
||||
const processDeviceKey = ref('');
|
||||
const detailDeviceKey = ref('');
|
||||
const processXPUId = ref<number | null>(null);
|
||||
const gpuInfo = ref<AI.Info>({
|
||||
const emptyGPUInfo = (): AI.Info => ({
|
||||
cudaVersion: '',
|
||||
driverVersion: '',
|
||||
type: 'nvidia',
|
||||
@@ -365,6 +547,7 @@ const gpuInfo = ref<AI.Info>({
|
||||
xpuDriverVersion: '',
|
||||
xpu: [],
|
||||
});
|
||||
const gpuInfo = ref<AI.Info>(emptyGPUInfo());
|
||||
const xpuInfo = ref<AI.XpuInfo>({
|
||||
driverVersion: '',
|
||||
type: 'xpu',
|
||||
@@ -396,7 +579,7 @@ const gpuGroups = computed<GPUGroup[]>(() => {
|
||||
if (!groups.has(key)) {
|
||||
groups.set(key, {
|
||||
key,
|
||||
title: item.type === 'ascend' ? `NPU ${item.npuIndex}` : item.type.toUpperCase(),
|
||||
title: item.type === 'ascend' ? `NPU ${item.npuIndex}` : '',
|
||||
devices: [],
|
||||
});
|
||||
}
|
||||
@@ -464,6 +647,235 @@ const hasAccelerators = computed(() => {
|
||||
return gpuGroups.value.length > 0 || xpuInfo.value.xpu.length > 0;
|
||||
});
|
||||
|
||||
const vendorTitle = (vendor: string): string => {
|
||||
const titles: Record<string, string> = {
|
||||
nvidia: 'NVIDIA',
|
||||
intel: 'Intel',
|
||||
xpu: 'Intel',
|
||||
ascend: 'Huawei Ascend',
|
||||
amd: 'AMD',
|
||||
};
|
||||
if (vendor === 'mixed') {
|
||||
const vendors = new Set(gpuInfo.value.gpu.map((device) => device.type as string));
|
||||
if (gpuInfo.value.npu.length) vendors.add('ascend');
|
||||
if (xpuInfo.value.xpu.length) vendors.add('intel');
|
||||
return Array.from(vendors, vendorTitle).join(' / ') || '—';
|
||||
}
|
||||
return titles[vendor] || vendor || '—';
|
||||
};
|
||||
|
||||
const displayValue = (value: string | undefined) => {
|
||||
return isAvailable(value) ? value : '—';
|
||||
};
|
||||
|
||||
const formatSummaryMemory = (value: number | null) => {
|
||||
return value === null || !Number.isFinite(value) ? '—' : computeSizeForDocker(value);
|
||||
};
|
||||
|
||||
const overviewRows = computed(() => {
|
||||
if (gpuInfo.value.summaries?.length) {
|
||||
return gpuInfo.value.summaries
|
||||
.filter(
|
||||
(summary) =>
|
||||
summary.cardCount > 0 ||
|
||||
isAvailable(summary.driverVersion) ||
|
||||
summary.memoryTotal !== null ||
|
||||
summary.sharedMemoryTotal !== null,
|
||||
)
|
||||
.map((summary) => {
|
||||
const devices = gpuInfo.value.gpu.filter((device) => device.type === summary.vendor);
|
||||
const sharedMemoryTotal =
|
||||
devices.length && !devices.some((device) => device.sharedMemory) ? null : summary.sharedMemoryTotal;
|
||||
return {
|
||||
...summary,
|
||||
sharedMemoryTotal,
|
||||
cardCountText: summary.cardCount === null ? '—' : String(summary.cardCount),
|
||||
sharedMemoryOnly:
|
||||
summary.memoryTotal === null &&
|
||||
sharedMemoryTotal !== null &&
|
||||
devices.every((device) => device.sharedMemory),
|
||||
};
|
||||
});
|
||||
}
|
||||
if (!hasAccelerators.value) return [];
|
||||
const memoryDevices = [
|
||||
...[...gpuInfo.value.gpu, ...gpuInfo.value.npu].map((device) => ({
|
||||
id: deviceKey(device),
|
||||
total: device.memTotal,
|
||||
shared: device.type !== 'ascend' && Boolean(device.sharedMemory),
|
||||
})),
|
||||
...xpuInfo.value.xpu.map((device) => ({
|
||||
id: `xpu-${device.basic.deviceID}`,
|
||||
total: device.basic.memory,
|
||||
shared: false,
|
||||
})),
|
||||
];
|
||||
let memoryTotal: number | null = null;
|
||||
let sharedMemoryTotal: number | null = null;
|
||||
let memoryPartial = false;
|
||||
const seen = new Set<string>();
|
||||
for (const device of memoryDevices) {
|
||||
if (seen.has(device.id)) continue;
|
||||
seen.add(device.id);
|
||||
const total = memoryMiB(device.total || '');
|
||||
if (total === null || !Number.isFinite(total) || total < 0) {
|
||||
memoryPartial = true;
|
||||
continue;
|
||||
}
|
||||
const bytes = total * 1024 * 1024;
|
||||
if (device.shared) {
|
||||
sharedMemoryTotal = Math.max(sharedMemoryTotal ?? 0, bytes);
|
||||
} else {
|
||||
memoryTotal = (memoryTotal ?? 0) + bytes;
|
||||
}
|
||||
}
|
||||
return [
|
||||
{
|
||||
vendor: gpuInfo.value.type,
|
||||
driverVersion: gpuInfo.value.driverVersion,
|
||||
cudaVersion: gpuInfo.value.cudaVersion,
|
||||
cardCountText: deviceCountText.value,
|
||||
memoryTotal,
|
||||
sharedMemoryTotal,
|
||||
sharedMemoryOnly: sharedMemoryTotal !== null && memoryDevices.every((device) => device.shared),
|
||||
memoryPartial,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const environmentChecks = computed(() => gpuInfo.value.environment?.checks || []);
|
||||
const historyDisabled = computed(
|
||||
() =>
|
||||
(loading.value && !gpuInfo.value.environment && !hasAccelerators.value) ||
|
||||
environmentChecks.value.some(
|
||||
(check) => check.item === 'driver' && check.status !== 'passed' && (check.vendor || !hasAccelerators.value),
|
||||
),
|
||||
);
|
||||
const driverChecks = computed(() => environmentChecks.value.filter((check) => check.item === 'driver'));
|
||||
const containerChecks = computed(() => environmentChecks.value.filter((check) => check.item !== 'driver'));
|
||||
const showEnvironment = computed(
|
||||
() =>
|
||||
gpuInfo.value.environment &&
|
||||
(gpuInfo.value.environment.hardwareStatus !== 'not_detected' || environmentChecks.value.length > 0),
|
||||
);
|
||||
const hostEnvironmentStatus = computed<{ type: 'success' | 'warning' | 'info'; label: string }>(() => {
|
||||
const hasDriverIssue = driverChecks.value.some((check) => check.status !== 'passed');
|
||||
if (hasAccelerators.value && (!hasDriverIssue || driverChecks.value.some((check) => check.status === 'passed'))) {
|
||||
return hasDriverIssue
|
||||
? { type: 'warning', label: 'monitorPartial' }
|
||||
: { type: 'success', label: 'monitorAvailable' };
|
||||
}
|
||||
if (driverChecks.value.some((check) => ['missing', 'unconfigured', 'failed'].includes(check.status))) {
|
||||
return { type: 'warning', label: 'notReady' };
|
||||
}
|
||||
return { type: 'info', label: 'statusUnknown' };
|
||||
});
|
||||
const containerEnvironmentStatus = computed<{ type: 'success' | 'warning' | 'info'; label: string }>(() => {
|
||||
const nvidiaDriver = driverChecks.value.find((check) => check.vendor === 'nvidia');
|
||||
if (nvidiaDriver && nvidiaDriver.status !== 'passed') {
|
||||
return nvidiaDriver.status === 'unknown'
|
||||
? { type: 'info', label: 'statusUnknown' }
|
||||
: { type: 'warning', label: 'notReady' };
|
||||
}
|
||||
if (containerChecks.value.every((check) => check.status === 'passed')) {
|
||||
return { type: 'success', label: 'ready' };
|
||||
}
|
||||
if (containerChecks.value.some((check) => ['missing', 'unconfigured', 'failed'].includes(check.status))) {
|
||||
return { type: 'warning', label: 'notReady' };
|
||||
}
|
||||
return { type: 'info', label: 'statusUnknown' };
|
||||
});
|
||||
const environmentGuidance = computed(() => {
|
||||
const issue =
|
||||
driverChecks.value.find((check) => check.status !== 'passed') ||
|
||||
containerChecks.value.find((check) => check.item === 'toolkit' && check.status !== 'passed') ||
|
||||
containerChecks.value.find((check) => check.status !== 'passed');
|
||||
if (!issue) return null;
|
||||
if (issue.status === 'unknown' || (issue.item === 'driver' && !issue.vendor)) {
|
||||
return { item: issue.item, title: 'unknown', description: 'checkDetailsHelp', action: 'details' };
|
||||
}
|
||||
if (issue.item === 'driver') {
|
||||
return { item: issue.item, title: 'driverActionTitle', description: 'driverActionHelp', action: 'driverGuide' };
|
||||
}
|
||||
if (issue.item === 'toolkit') {
|
||||
return {
|
||||
item: issue.item,
|
||||
title: 'toolkitActionTitle',
|
||||
description: 'toolkitActionHelp',
|
||||
action: 'toolkitGuide',
|
||||
};
|
||||
}
|
||||
return { item: issue.item, title: 'dockerActionTitle', description: 'dockerActionHelp', action: 'docker' };
|
||||
});
|
||||
const emptyDescription = computed(() => {
|
||||
if (!gpuInfo.value.environment) return i18n.global.t('aiTools.gpu.gpuHelper');
|
||||
return gpuInfo.value.environment.hardwareStatus === 'not_detected'
|
||||
? i18n.global.t('aiTools.gpu.environment.notDetected')
|
||||
: i18n.global.t('aiTools.gpu.environment.unknown');
|
||||
});
|
||||
const checkStatus = (check: AI.GPUEnvironmentCheck) => {
|
||||
const status = check.status[0].toUpperCase() + check.status.slice(1);
|
||||
return i18n.global.t(`aiTools.gpu.environment.status${status}`);
|
||||
};
|
||||
const checkTagType = (check: AI.GPUEnvironmentCheck) => {
|
||||
if (check.status === 'passed') return 'success';
|
||||
return check.status === 'failed' ? 'danger' : 'warning';
|
||||
};
|
||||
const checkTitle = (check: AI.GPUEnvironmentCheck) => {
|
||||
if (check.vendor === 'nvidia' && check.item === 'driver') {
|
||||
return i18n.global.t('aiTools.gpu.environment.nvidiaDriver');
|
||||
}
|
||||
const title = i18n.global.t(`aiTools.gpu.environment.${check.item}`);
|
||||
return check.vendor && check.item === 'driver' ? `${vendorTitle(check.vendor)} · ${title}` : title;
|
||||
};
|
||||
const checkDescription = (check: AI.GPUEnvironmentCheck) => {
|
||||
const managementTools: Record<string, string> = {
|
||||
nvidia: 'nvidia-smi',
|
||||
intel: 'xpu-smi',
|
||||
ascend: 'npu-smi',
|
||||
amd: 'amd-smi',
|
||||
};
|
||||
const tool = managementTools[check.vendor];
|
||||
let key: string;
|
||||
if (check.item === 'driver') {
|
||||
if (!tool) return i18n.global.t('aiTools.gpu.environment.unknown');
|
||||
key =
|
||||
check.status === 'missing' || check.status === 'unconfigured'
|
||||
? 'driverMissing'
|
||||
: check.status === 'failed'
|
||||
? 'driverFailed'
|
||||
: 'driverUnknown';
|
||||
} else if (check.item === 'toolkit') {
|
||||
key = check.status === 'missing' || check.status === 'unconfigured' ? 'toolkitMissing' : 'toolkitFailed';
|
||||
} else {
|
||||
const configKeys = [
|
||||
'dockerConfigMissing',
|
||||
'dockerConfigInvalid',
|
||||
'dockerConfigPending',
|
||||
'dockerConfigUnreadable',
|
||||
];
|
||||
const code = check.code || '';
|
||||
key = configKeys.includes(code)
|
||||
? code
|
||||
: check.status === 'missing' || check.status === 'unconfigured'
|
||||
? 'dockerUnconfigured'
|
||||
: 'dockerFailed';
|
||||
}
|
||||
const description = i18n.global.t(`aiTools.gpu.environment.${key}`, {
|
||||
tool: tool || '',
|
||||
vendor: vendorTitle(check.vendor),
|
||||
});
|
||||
return check.item === 'driver' && key !== 'driverMissing' ? `${checkTitle(check)}: ${description}` : description;
|
||||
};
|
||||
|
||||
const summaryMemoryTooltip = (summary: { sharedMemoryOnly: boolean; memoryPartial: boolean }) =>
|
||||
[
|
||||
summary.sharedMemoryOnly && i18n.global.t('aiTools.gpu.systemMemoryHelper'),
|
||||
summary.memoryPartial && i18n.global.t('aiTools.gpu.environment.partialMemory'),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
const normalizeAcceleratorInfo = (data: AI.Info): AI.Info => {
|
||||
const devices = (data.gpu || []) as AcceleratorDevice[];
|
||||
const legacyNPUs = devices
|
||||
@@ -495,22 +907,37 @@ const applyAcceleratorInfo = (data: AI.Info) => {
|
||||
};
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let requestID = 0;
|
||||
const search = async (refreshEnvironment = false) => {
|
||||
if (route.path !== pagePath) return;
|
||||
if (loading.value) return;
|
||||
const id = ++requestID;
|
||||
const node = currentNode.value;
|
||||
loading.value = true;
|
||||
loadFailed.value = false;
|
||||
try {
|
||||
const res = await loadGPUInfo();
|
||||
const res = await loadGPUInfo(refreshEnvironment, node);
|
||||
if (id !== requestID || node !== currentNode.value) return;
|
||||
applyAcceleratorInfo(res.data);
|
||||
if (res.data.warnings?.length) {
|
||||
MsgWarning(res.data.warnings.join('; '));
|
||||
}
|
||||
} catch {
|
||||
if (id === requestID && node === currentNode.value) loadFailed.value = true;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
if (id === requestID) loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const refresh = search;
|
||||
const refresh = () => search(true);
|
||||
|
||||
watch(currentNode, () => {
|
||||
environmentDetails.value = [];
|
||||
requestID++;
|
||||
loading.value = false;
|
||||
loadFailed.value = false;
|
||||
applyAcceleratorInfo(emptyGPUInfo());
|
||||
detailDeviceKey.value = '';
|
||||
processDrawerVisible.value = false;
|
||||
search(true);
|
||||
});
|
||||
|
||||
const visibleSections = (sections: DetailSection[]) => {
|
||||
return sections
|
||||
@@ -765,6 +1192,7 @@ const stableDeviceID = (vendor: string, identifier: string | undefined, fallback
|
||||
};
|
||||
|
||||
const openHistory = (item: AcceleratorDevice | AI.XpuInfo['xpu'][number]) => {
|
||||
if (historyDisabled.value) return;
|
||||
let deviceID: string;
|
||||
if ('basic' in item) {
|
||||
deviceID = stableDeviceID(
|
||||
@@ -919,9 +1347,104 @@ const loadEcc = (val: string) => {
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
onActivated(() => {
|
||||
search();
|
||||
});
|
||||
const invalidateRequest = () => {
|
||||
requestID++;
|
||||
loading.value = false;
|
||||
};
|
||||
onDeactivated(invalidateRequest);
|
||||
onBeforeUnmount(invalidateRequest);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.environment-heading {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.environment-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 16px 0;
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
|
||||
> .el-tag {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
.environment-identity {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
|
||||
> .el-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--el-text-color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.environment-description {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 16px;
|
||||
margin-top: 5px;
|
||||
color: var(--el-text-color-regular);
|
||||
font-size: 12px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.environment-guidance {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
margin: 12px 0 16px;
|
||||
border-radius: 6px;
|
||||
background: var(--el-color-warning-light-9);
|
||||
|
||||
strong {
|
||||
color: var(--el-color-warning-dark-2);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 6px 0 0;
|
||||
color: var(--el-text-color-regular);
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
> .el-button {
|
||||
flex-shrink: 0;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
min-height: 32px;
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.environment-details {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.environment-check-description {
|
||||
margin: 6px 0;
|
||||
color: var(--el-text-color-regular);
|
||||
line-height: 1.7;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.environment-guidance {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.device-overview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -954,16 +1477,6 @@ onMounted(() => {
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
.overview-count {
|
||||
margin-left: 16px;
|
||||
padding-left: 16px;
|
||||
border-left: 1px solid var(--el-border-color-lighter);
|
||||
color: var(--el-color-primary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.gpu-group-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -1168,9 +1681,6 @@ onMounted(() => {
|
||||
gap: 8px 0;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
.overview-count {
|
||||
width: auto;
|
||||
}
|
||||
.device-metrics {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<RouterMenu />
|
||||
<template v-if="supported">
|
||||
<template v-if="supported && options.length">
|
||||
<el-card class="history-toolbar">
|
||||
<div class="flex flex-wrap gap-3 items-center">
|
||||
<el-select style="max-width: 100%" class="p-w-400" v-model="selectedDevice" @change="search">
|
||||
@@ -26,7 +26,10 @@
|
||||
:clearable="false"
|
||||
@change="changeTimeRange"
|
||||
/>
|
||||
<TableRefresh @search="refresh" />
|
||||
<TableSetting title="gpu-refresh" @search="refresh" />
|
||||
<el-tooltip :content="$t('aiTools.gpu.environment.recheck')">
|
||||
<TableRefresh :disabled="loading" @search="refresh" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="history?.sampleCount && history.bucketSeconds > 0" class="history-summary">
|
||||
@@ -67,26 +70,23 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<LayoutContent v-else-if="!loading" :title="$t('aiTools.gpu.monitoringTitle')" :divider="true">
|
||||
<LayoutContent v-else :title="$t('aiTools.gpu.monitoringTitle')">
|
||||
<template #rightToolBar>
|
||||
<TableRefresh @search="refresh" />
|
||||
<TableSetting title="gpu-refresh" @search="refresh" />
|
||||
<el-tooltip :content="$t('aiTools.gpu.environment.recheck')">
|
||||
<TableRefresh :disabled="loading" @search="refresh" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #main>
|
||||
<el-alert
|
||||
v-if="failed"
|
||||
class="common-prompt"
|
||||
:title="$t('aiTools.gpu.historyLoadFailed')"
|
||||
type="error"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<div v-else class="app-warn">
|
||||
<div class="flx-center">
|
||||
<span>{{ $t('aiTools.gpu.gpuHelper') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<img src="@/assets/images/no_app.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else-if="!loading" :description="$t('aiTools.gpu.environment.notDetected')" />
|
||||
</template>
|
||||
</LayoutContent>
|
||||
</div>
|
||||
@@ -371,6 +371,7 @@ const loadOptions = async () => {
|
||||
}
|
||||
};
|
||||
const refresh = () => {
|
||||
if (loading.value) return;
|
||||
if (followNow) timeRangeGlobal.value = [timeRangeGlobal.value[0], new Date()];
|
||||
void loadOptions();
|
||||
};
|
||||
|
||||
@@ -9,8 +9,16 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import i18n from '@/lang';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const buttons = [
|
||||
const props = defineProps({
|
||||
historyDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const buttons = computed(() => [
|
||||
{
|
||||
label: i18n.global.t('aiTools.gpu.current'),
|
||||
path: '/ai/gpu/current',
|
||||
@@ -18,6 +26,7 @@ const buttons = [
|
||||
{
|
||||
label: i18n.global.t('aiTools.gpu.history'),
|
||||
path: '/ai/gpu/history',
|
||||
disabled: props.historyDisabled,
|
||||
},
|
||||
];
|
||||
]);
|
||||
</script>
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
>
|
||||
<el-radio-button value="network">{{ $t('home.network') }}</el-radio-button>
|
||||
<el-radio-button value="io">{{ $t('home.io') }}</el-radio-button>
|
||||
<el-radio-button v-if="hasVllm" value="vllm">vLLM</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-select
|
||||
v-if="chartOption === 'network'"
|
||||
@@ -128,6 +129,26 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-if="chartOption === 'vllm'"
|
||||
v-model="vllmInstallID"
|
||||
class="p-w-200 float-right"
|
||||
:placeholder="$t('aiTools.model.deployments')"
|
||||
@visible-change="(visible) => visible && loadVllmOptions()"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in vllmOptions"
|
||||
:key="item.appInstallId"
|
||||
:label="item.name + (item.servedModelName ? ' · ' + item.servedModelName : '')"
|
||||
:value="item.appInstallId"
|
||||
:disabled="item.status !== 'Running'"
|
||||
>
|
||||
<span>
|
||||
{{ item.name }}{{ item.servedModelName ? ' · ' + item.servedModelName : '' }}
|
||||
</span>
|
||||
<Status class="ml-2" :status="item.status" />
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="monitor-chart-content">
|
||||
@@ -169,6 +190,47 @@
|
||||
:dataZoom="true"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="chartOption === 'vllm'">
|
||||
<div class="monitor-tags" :style="monitorTagsStyle">
|
||||
<el-tag>
|
||||
{{ $t('aiTools.vllmMonitor.promptThroughput') }}:
|
||||
{{ formatVllmMetric(vllmCurrent?.promptThroughput) }} tokens/s
|
||||
</el-tag>
|
||||
<el-tag>
|
||||
{{ $t('aiTools.vllmMonitor.generationThroughput') }}:
|
||||
{{ formatVllmMetric(vllmCurrent?.generationThroughput) }} tokens/s
|
||||
</el-tag>
|
||||
<el-tag>
|
||||
{{ $t('aiTools.vllmMonitor.processing') }}:
|
||||
{{ formatVllmMetric(vllmCurrent?.running) }}
|
||||
</el-tag>
|
||||
<el-tag>
|
||||
{{ $t('aiTools.vllmMonitor.queued') }}:
|
||||
{{ formatVllmMetric(vllmCurrent?.waiting) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="mobile-monitor-chart">
|
||||
<v-charts
|
||||
height="383px"
|
||||
id="vllmChart"
|
||||
type="line"
|
||||
:option="vllmChartOption"
|
||||
:dataZoom="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="vllm-monitor-footer">
|
||||
<span>{{ vllmMonitorMessage }}</span>
|
||||
<el-button
|
||||
v-if="selectedVllm"
|
||||
link
|
||||
type="primary"
|
||||
@click="vllmMonitorRef?.acceptParams(selectedVllm)"
|
||||
>
|
||||
{{ $t('commons.button.view') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<VllmMonitor v-if="selectedVllm" ref="vllmMonitorRef" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</CardWithHeader>
|
||||
@@ -443,7 +505,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onBeforeUnmount, ref, reactive, computed, nextTick } from 'vue';
|
||||
import { onMounted, onBeforeUnmount, ref, reactive, computed, nextTick, watch, defineAsyncComponent } from 'vue';
|
||||
import SystemStatus from '@/views/home/status/index.vue';
|
||||
import AppLauncher from '@/views/home/app/index.vue';
|
||||
import VCharts from '@/components/v-charts/index.vue';
|
||||
@@ -478,6 +540,9 @@ import {
|
||||
} from '@/utils/dashboardCache';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { useCan } from '@/composables/useMenuManagePermission';
|
||||
import { readPages } from '@/utils/pagination';
|
||||
import { loadExtensionComponent } from '@/extensions/optional';
|
||||
import type { ReqPage, ResPage, ResultData } from '@/api/interface';
|
||||
const router = useRouter();
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
const {
|
||||
@@ -489,8 +554,146 @@ const {
|
||||
hasNewVersion,
|
||||
isAdminOrNodeAdmin,
|
||||
isXpackOrEE,
|
||||
isProductPro,
|
||||
currentNode,
|
||||
} = useGlobalStore();
|
||||
|
||||
interface VllmDeployment {
|
||||
appInstallId: number;
|
||||
name: string;
|
||||
servedModelName: string;
|
||||
status: string;
|
||||
}
|
||||
interface VllmSnapshot {
|
||||
appInstallID: number;
|
||||
createdAt: string;
|
||||
status: string;
|
||||
intervalSeconds: number;
|
||||
promptThroughput: number | null;
|
||||
generationThroughput: number | null;
|
||||
running: number | null;
|
||||
waiting: number | null;
|
||||
metrics?: Record<string, Record<string, number>>;
|
||||
}
|
||||
const vllmModules = import.meta.glob<{
|
||||
pageVllm: (req: ReqPage & { info: string }) => Promise<ResultData<ResPage<VllmDeployment>>>;
|
||||
loadVllmCurrent: (id: number, signal: AbortSignal) => Promise<ResultData<VllmSnapshot>>;
|
||||
}>('@/xpack/api/modules/vllm.ts', { eager: true });
|
||||
const vllmMetricsModules = import.meta.glob<{
|
||||
calculateCurrentMetrics: (snapshot: VllmSnapshot, previous?: VllmSnapshot) => VllmSnapshot;
|
||||
}>('@/xpack/views/vllm/monitor/current.ts', { eager: true });
|
||||
const vllmAPI = Object.values(vllmModules)[0];
|
||||
const vllmMetrics = Object.values(vllmMetricsModules)[0];
|
||||
const VllmMonitor = defineAsyncComponent(() => loadExtensionComponent('/vllm/monitor/index.vue'));
|
||||
const vllmMonitorRef = ref();
|
||||
const canViewVllm = useCan('ai_model_view');
|
||||
const vllmOptions = ref<VllmDeployment[]>([]);
|
||||
const vllmInstallID = ref<number>();
|
||||
const vllmCurrent = ref<VllmSnapshot>();
|
||||
const vllmLoadFailed = ref(false);
|
||||
const vllmPoints = ref<Array<{ time: string; prompt: number | null; generation: number | null }>>([]);
|
||||
let vllmTimer: ReturnType<typeof setTimeout>;
|
||||
let vllmController: AbortController;
|
||||
let vllmOptionsVersion = 0;
|
||||
const hasVllm = computed(() => isProductPro.value && canViewVllm.value && vllmOptions.value.length > 0);
|
||||
const selectedVllm = computed(() => vllmOptions.value.find((item) => item.appInstallId === vllmInstallID.value));
|
||||
const formatVllmMetric = (value?: number | null) =>
|
||||
value == null || !Number.isFinite(value) ? '--' : Number(value.toFixed(2)).toString();
|
||||
const vllmMonitorMessage = computed(() => {
|
||||
if (!selectedVllm.value) return i18n.global.t('aiTools.model.readinessNotRunning');
|
||||
if (vllmLoadFailed.value) return i18n.global.t('aiTools.vllmMonitor.loadFailed');
|
||||
if (vllmCurrent.value?.status === 'unavailable') return i18n.global.t('aiTools.vllmMonitor.unavailable');
|
||||
if (vllmCurrent.value?.status === 'no_data') return i18n.global.t('aiTools.vllmMonitor.noMetrics');
|
||||
if (!vllmCurrent.value?.intervalSeconds) return i18n.global.t('commons.table.statusWaiting');
|
||||
return `${i18n.global.t('aiTools.vllmMonitor.sampleWindow')}: ${formatVllmMetric(vllmCurrent.value.intervalSeconds)} s`;
|
||||
});
|
||||
const vllmChartOption = computed(() => ({
|
||||
xData: loadMonitorChartTime(vllmPoints.value.map((point) => point.time)),
|
||||
yData: [
|
||||
{
|
||||
name: i18n.global.t('aiTools.vllmMonitor.promptThroughput'),
|
||||
data: loadMonitorChartData(vllmPoints.value.map((point) => point.prompt)),
|
||||
},
|
||||
{
|
||||
name: i18n.global.t('aiTools.vllmMonitor.generationThroughput'),
|
||||
data: loadMonitorChartData(vllmPoints.value.map((point) => point.generation)),
|
||||
},
|
||||
],
|
||||
grid: monitorChartGrid,
|
||||
legend: monitorChartLegend,
|
||||
formatStr: 'tokens/s',
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '( tokens/s )',
|
||||
min: 0,
|
||||
max: ({ max }: { max: number }) => (max > 0 ? undefined : 1),
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
valueFormatter: (value: number | null) => `${formatVllmMetric(value)} tokens/s`,
|
||||
},
|
||||
}));
|
||||
|
||||
const loadVllmOptions = async () => {
|
||||
if (!isProductPro.value || !canViewVllm.value || !vllmAPI || !vllmMetrics) return;
|
||||
const version = ++vllmOptionsVersion;
|
||||
const node = currentNode.value;
|
||||
try {
|
||||
const items = await readPages((page) => {
|
||||
if (version !== vllmOptionsVersion || node !== currentNode.value) throw new Error('node changed');
|
||||
return vllmAPI.pageVllm({ ...page, info: '' });
|
||||
});
|
||||
if (version !== vllmOptionsVersion || node !== currentNode.value) return;
|
||||
vllmOptions.value = items;
|
||||
if (!items.some((item) => item.appInstallId === vllmInstallID.value && item.status === 'Running')) {
|
||||
vllmInstallID.value = items.find((item) => item.status === 'Running')?.appInstallId;
|
||||
}
|
||||
if (!items.length && chartOption.value === 'vllm') chartOption.value = 'network';
|
||||
} catch {
|
||||
if (version === vllmOptionsVersion) vllmLoadFailed.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const stopVllmMonitor = (resetData = true) => {
|
||||
clearTimeout(vllmTimer);
|
||||
vllmController?.abort();
|
||||
if (resetData) {
|
||||
vllmCurrent.value = undefined;
|
||||
vllmPoints.value = [];
|
||||
vllmLoadFailed.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const refreshVllmMonitor = async () => {
|
||||
const controller = new AbortController();
|
||||
vllmController = controller;
|
||||
try {
|
||||
const { data } = await vllmAPI.loadVllmCurrent(vllmInstallID.value, controller.signal);
|
||||
if (controller.signal.aborted) return;
|
||||
const wasUnavailable = vllmCurrent.value?.status === 'unavailable';
|
||||
vllmCurrent.value = vllmMetrics.calculateCurrentMetrics(data, vllmCurrent.value);
|
||||
vllmLoadFailed.value = false;
|
||||
vllmPoints.value.push({
|
||||
time: dateFormatForSecond(new Date(data.createdAt)),
|
||||
prompt: vllmCurrent.value.promptThroughput,
|
||||
generation: vllmCurrent.value.generationThroughput,
|
||||
});
|
||||
if (data.status === 'unavailable' && !wasUnavailable) void loadVllmOptions();
|
||||
} catch {
|
||||
if (controller.signal.aborted) return;
|
||||
vllmCurrent.value = undefined;
|
||||
vllmLoadFailed.value = true;
|
||||
vllmPoints.value.push({ time: dateFormatForSecond(new Date()), prompt: null, generation: null });
|
||||
} finally {
|
||||
if (!controller.signal.aborted) {
|
||||
vllmPoints.value = vllmPoints.value.slice(-20);
|
||||
vllmTimer = setTimeout(refreshVllmMonitor, 3000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const DASHBOARD_CACHE_TTL = {
|
||||
safeStatus: 10 * 60 * 1000,
|
||||
netOptions: 60 * 60 * 1000,
|
||||
@@ -505,7 +708,7 @@ const monitorTagsStyle = {
|
||||
const monitorChartEmptyLength = 20;
|
||||
const loadMonitorEmptyData = () => Array.from({ length: monitorChartEmptyLength }, () => null);
|
||||
const loadMonitorEmptyTime = () => Array.from({ length: monitorChartEmptyLength }, () => '');
|
||||
const loadMonitorChartData = (data: Array<number>) => (data.length === 0 ? loadMonitorEmptyData() : data);
|
||||
const loadMonitorChartData = (data: Array<number | null>) => (data.length === 0 ? loadMonitorEmptyData() : data);
|
||||
const loadMonitorChartTime = (data: Array<string>) => (data.length === 0 ? loadMonitorEmptyTime() : data);
|
||||
const loadIOChartOption = () => ({
|
||||
xData: loadMonitorChartTime(timeIODatas.value),
|
||||
@@ -718,6 +921,7 @@ const updateCurrentInfo = (data: Dashboard.CurrentInfo) => {
|
||||
|
||||
const changeOption = async () => {
|
||||
isInit.value = true;
|
||||
if (chartOption.value === 'vllm') void loadVllmOptions();
|
||||
loadData();
|
||||
};
|
||||
|
||||
@@ -851,7 +1055,7 @@ const refreshDashboard = async () => {
|
||||
clearDashboardCache();
|
||||
onLoadBaseInfo(false, '');
|
||||
hasRefreshedOptionsOnHover.value = false;
|
||||
await Promise.allSettled([onLoadNetworkOptions(true), onLoadIOOptions(true), loadSettingInfo()]);
|
||||
await Promise.allSettled([onLoadNetworkOptions(true), onLoadIOOptions(true), loadSettingInfo(), loadVllmOptions()]);
|
||||
MsgSuccess(i18n.global.t('commons.msg.refreshSuccess'));
|
||||
};
|
||||
|
||||
@@ -1028,7 +1232,7 @@ const saveMemo = async () => {
|
||||
const loadData = async () => {
|
||||
if (chartOption.value === 'io') {
|
||||
chartsOption.value['ioChart'] = loadIOChartOption();
|
||||
} else {
|
||||
} else if (chartOption.value === 'network') {
|
||||
chartsOption.value['networkChart'] = loadNetworkChartOption();
|
||||
}
|
||||
};
|
||||
@@ -1097,12 +1301,14 @@ const loadSource = (row: any) => {
|
||||
const onFocus = () => {
|
||||
isActive.value = true;
|
||||
skipNextCurrentInfoDelta.value = true;
|
||||
void loadVllmOptions();
|
||||
};
|
||||
const onBlur = () => {
|
||||
isActive.value = false;
|
||||
};
|
||||
|
||||
const refreshOptionsOnHover = async () => {
|
||||
void loadVllmOptions();
|
||||
if (hasRefreshedOptionsOnHover.value) return;
|
||||
if (!netOptionsFromCache.value && !ioOptionsFromCache.value) return;
|
||||
hasRefreshedOptionsOnHover.value = true;
|
||||
@@ -1155,7 +1361,29 @@ onMounted(() => {
|
||||
loadMemo();
|
||||
});
|
||||
|
||||
watch(
|
||||
[currentNode, isProductPro, canViewVllm],
|
||||
() => {
|
||||
vllmOptionsVersion++;
|
||||
stopVllmMonitor();
|
||||
vllmOptions.value = [];
|
||||
vllmInstallID.value = undefined;
|
||||
if (chartOption.value === 'vllm') chartOption.value = 'network';
|
||||
void loadVllmOptions();
|
||||
},
|
||||
{ immediate: true, flush: 'sync' },
|
||||
);
|
||||
|
||||
watch([chartOption, vllmInstallID, isActive], ([, installID], [, previousInstallID]) => {
|
||||
stopVllmMonitor(installID !== previousInstallID);
|
||||
if (chartOption.value === 'vllm' && hasVllm.value && vllmInstallID.value && isActive.value) {
|
||||
void refreshVllmMonitor();
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
vllmOptionsVersion++;
|
||||
stopVllmMonitor();
|
||||
window.removeEventListener('focus', onFocus);
|
||||
window.removeEventListener('blur', onBlur);
|
||||
isCurrentActive.value = false;
|
||||
@@ -1189,6 +1417,16 @@ onBeforeUnmount(() => {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.vllm-monitor-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 0 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
.dashboard-entrance-alert {
|
||||
padding-right: 40px;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@keyup.enter="search"
|
||||
@clear="search"
|
||||
/>
|
||||
<el-button :disabled="loading" @click="search">{{ $t('commons.button.confirm') }}</el-button>
|
||||
<el-button :disabled="loading" @click="search">{{ $t('commons.button.search') }}</el-button>
|
||||
</div>
|
||||
<div class="directory-row directory-header">
|
||||
<span>{{ $t('file.path') }}</span>
|
||||
|
||||
Reference in New Issue
Block a user