Compare commits

...
Author SHA1 Message Date
ssongliu 718ebeb203 fix: Modify help information about Ollama pull (#7935) 2025-02-20 15:21:50 +08:00
ssongliu 4101bf691d style: Fix the issue of inconsistent menu spacing. (#7932) 2025-02-20 13:45:48 +08:00
蘭 a97deb3dca feat: API timestamp verification (#7927)
* feat: API timestamp verification

* feat: API timestamp verification
2025-02-20 13:29:26 +08:00
zhengkunwang 10203d5c0c fix: Resolve the issue of local application label loss (#7926) 2025-02-20 13:29:04 +08:00
maninhill a357d6697d chore: Update README.md 2025-02-19 22:58:06 +08:00
ssongliu 555b0aa999 fix: Optimize status display. (#7920) 2025-02-19 22:54:34 +08:00
蘭 6dd0dbe2c3 feat: Improve international language (#7918) 2025-02-19 13:35:39 +00:00
zhengkunwang c31bbae768 feat: Optimized the display when no certificate is present. (#7917) 2025-02-19 11:03:39 +00:00
ssongliu 2bb0f15973 fix: Fix the loading method of slow logs in MySQL and MariaDB (#7915)
Refs #6353
2025-02-19 09:48:36 +00:00
zhengkunwang be229551e3 feat: AI tool Added quick jump functionality (#7913) 2025-02-19 08:26:31 +00:00
蘭 6283eb4c69 feat: Add language translation and icons (#7912) 2025-02-19 08:14:32 +00:00
ssongliu c329fb6599 feat: Support for terminal operation with the Ollama model (#7907) 2025-02-19 14:07:05 +08:00
zhengkunwang223 c3685f6b74 feat: Adjusted the position of the quick jump button. 2025-02-18 20:25:31 +08:00
maninhill f4f5a36475 chore: Update README.md 2025-02-18 20:25:04 +08:00
zhengkunwang ea1261b48e feat: Added partial prompt messages (#7900) 2025-02-18 10:08:52 +00:00
wanghe-fit2cloud 0c68f16a66 feat: Modify some translations 2025-02-18 17:09:13 +08:00
ssongliu 33e5c9230f fix: Optimized ollama model status display (#7899) 2025-02-18 17:06:20 +08:00
zhengkunwang 96eefab36f feat: Added underscore support for website default documents (#7898) 2025-02-18 17:06:10 +08:00
zhengkunwang b0b6bf458f feat: Added display of ollama proxy address (#7897) 2025-02-18 15:00:33 +08:00
zhengkunwang f3d85d1309 fix: Fixed the issue where local application descriptions were not di… (#7896)
Refs https://github.com/1Panel-dev/1Panel/issues/7886
2025-02-18 06:17:11 +00:00
ssongliu 39385ea0a0 fix: Adjust the synchronization method for the Ollama model (#7895) 2025-02-18 06:09:10 +00:00
zhengkunwang e492c6573c feat: Modified the logic for AI Tool (#7894) 2025-02-18 05:59:10 +00:00
wanghe-fit2cloud 10a7fb3be2 feat: Update the official website URL for the international version 2025-02-18 10:31:38 +08:00
王贺 8bc7cfade3 Update README.md (#7891) 2025-02-17 22:26:29 +08:00
ssongliu ea044d6c32 fix: change the AI routing interface (#7887) 2025-02-17 15:33:57 +08:00
zhengkunwang f6ee3dc75b feat: Added streaming transmission configuration (#7875) 2025-02-15 12:59:38 +00:00
ssongliu 367a74503f fix: Fix the problem of duplicate content display in the model list (#7872) 2025-02-14 09:10:05 +00:00
蘭 53b1a7af4c feat: Copy and move files with the same name file processing (#7871) 2025-02-14 06:28:06 +00:00
zhengkunwang 078d7fbe1e feat: Add AI-enhanced configuration (#7870) 2025-02-14 06:26:05 +00:00
ssongliu c709e48ceb feat: support load ollama model details (#7867) 2025-02-13 14:56:24 +00:00
endymx 0741f60896 fix(iptables): 复杂环境下转发删除端口错误 (#7868) 2025-02-13 22:56:09 +08:00
ssongliu af8eef4a91 feat: Support Ollama model management (#7866) 2025-02-13 15:28:29 +08:00
zhengkunwang f233ef7069 feat: Adding GPU acceleration configuration to some applications (#7865) 2025-02-13 07:02:08 +00:00
蘭 1c199bd3d7 style: Optimize app store style and layout (#7858)
Refs #7846
2025-02-12 21:56:52 +08:00
ssongliu 036c973fec fix: Fix the security entry verification error issue. (#7854)
Refs #7853
2025-02-11 10:13:49 +00:00
蘭 8bb225d272 feat: Check for duplicate files before uploading (#7849)
Refs #5893
2025-02-11 10:11:48 +00:00
131 changed files with 6799 additions and 682 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ PR are always welcome, even if they only contain small fixes like typos or a few
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
This [development guideline](https://docs.1panel.hk/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
This [development guideline](https://docs.1panel.pro/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
+7 -8
View File
@@ -1,8 +1,7 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool<br>Best VPS control panel</b></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool</b><br>Best VPS control panel<br>新一代的 Linux 服务器运维管理面板</p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
<a href="https://www.producthunt.com/posts/1panel?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-1panel" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=639696&theme=light" alt="1Panel - Top&#0045;Rated&#0032;web&#0045;based&#0032;Linux&#0032;server&#0032;management&#0032;tool | Product Hunt" style="width: 180px; height: auto;" /></a>
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 240px; height: auto;" /></a>
</p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
@@ -45,16 +44,16 @@
Execute the script below and follow the prompts to install 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Please refer to our [documentation](https://docs.1panel.hk/quick_start/) for more details.
Please refer to our [documentation](https://docs.1panel.pro/quick_start/) for more details.
中国用户请使用这个 [安装脚本](https://1panel.cn/docs/installation/online_installation/),其应用数量比国际版本更丰富。
## Screenshot
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Star History
@@ -62,7 +61,7 @@ Please refer to our [documentation](https://docs.1panel.hk/quick_start/) for mor
## Pro Edition
Compared to the OSS Edition, 1Panel Pro Edition provides users with a wealth of enhanced features and technical support services. Enhanced features include WAF enhancement, website tamper protection, website monitoring, GPU monitoring, custom logo and theme color, etc. [Click to view the detailed introduction of the Pro Edition](https://1panel.hk/pricing).
Compared to the OSS Edition, 1Panel Pro Edition provides users with a wealth of enhanced features and technical support services. Enhanced features include WAF enhancement, website tamper protection, website monitoring, GPU monitoring, custom logo and theme color, etc. [Click to view the detailed introduction of the Pro Edition](https://1panel.pro/pricing).
## Security Information
+257
View File
@@ -0,0 +1,257 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu/common"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/xpu"
"github.com/gin-gonic/gin"
)
// @Tags AI
// @Summary Create Ollama model
// @Accept json
// @Param request body dto.OllamaModelName true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加 Ollama 模型 [name]","formatEN":"add Ollama model [name]"}
func (b *BaseApi) CreateOllamaModel(c *gin.Context) {
var req dto.OllamaModelName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.Create(req.Name); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags AI
// @Summary Rereate Ollama model
// @Accept json
// @Param request body dto.OllamaModelName true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/recreate [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"添加 Ollama 模型重试 [name]","formatEN":"re-add Ollama model [name]"}
func (b *BaseApi) RecreateOllamaModel(c *gin.Context) {
var req dto.OllamaModelName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.Recreate(req.Name); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags AI
// @Summary Close Ollama model conn
// @Accept json
// @Param request body dto.OllamaModelName true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/close [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"关闭 Ollama 模型连接 [name]","formatEN":"close conn for Ollama model [name]"}
func (b *BaseApi) CloseOllamaModel(c *gin.Context) {
var req dto.OllamaModelName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.Close(req.Name); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags AI
// @Summary Sync Ollama model list
// @Success 200 {array} dto.OllamaModelDropList
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/sync [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步 Ollama 模型列表","formatEN":"sync Ollama model list"}
func (b *BaseApi) SyncOllamaModel(c *gin.Context) {
list, err := AIToolService.Sync()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags AI
// @Summary Page Ollama models
// @Accept json
// @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/search [post]
func (b *BaseApi) SearchOllamaModel(c *gin.Context) {
var req dto.SearchWithPage
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
total, list, err := AIToolService.Search(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
// @Tags AI
// @Summary Page Ollama models
// @Accept json
// @Param request body dto.OllamaModelName true "request"
// @Success 200 {string} details
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/load [post]
func (b *BaseApi) LoadOllamaModelDetail(c *gin.Context) {
var req dto.OllamaModelName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
detail, err := AIToolService.LoadDetail(req.Name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, detail)
}
// @Tags AI
// @Summary Delete Ollama model
// @Accept json
// @Param request body dto.ForceDelete true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/ollama/model/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"ollama_models","output_column":"name","output_value":"names"}],"formatZH":"删除 Ollama 模型 [names]","formatEN":"remove Ollama model [names]"}
func (b *BaseApi) DeleteOllamaModel(c *gin.Context) {
var req dto.ForceDelete
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.Delete(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags AI
// @Summary Load gpu / xpu info
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/gpu/load [get]
func (b *BaseApi) LoadGpuInfo(c *gin.Context) {
ok, client := gpu.New()
if ok {
info, err := client.LoadGpuInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
return
}
xpuOK, xpuClient := xpu.New()
if xpuOK {
info, err := xpuClient.LoadGpuInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
return
}
helper.SuccessWithData(c, &common.GpuInfo{})
}
// @Tags AI
// @Summary Bind domain
// @Accept json
// @Param request body dto.OllamaBindDomain true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/domain/bind [post]
func (b *BaseApi) BindDomain(c *gin.Context) {
var req dto.OllamaBindDomain
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.BindDomain(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags AI
// @Summary Get bind domain
// @Accept json
// @Param request body dto.OllamaBindDomainReq true "request"
// @Success 200 {object} dto.OllamaBindDomainRes
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /ai/domain/get [post]
func (b *BaseApi) GetBindDomain(c *gin.Context) {
var req dto.OllamaBindDomainReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
res, err := AIToolService.GetBindDomain(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// Tags AI
// Summary Update bind domain
// Accept json
// Param request body dto.OllamaBindDomain true "request"
// Success 200
// Security ApiKeyAuth
// Security Timestamp
// Router /ai/domain/update [post]
func (b *BaseApi) UpdateBindDomain(c *gin.Context) {
var req dto.OllamaBindDomain
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := AIToolService.UpdateBindDomain(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
+2
View File
@@ -15,6 +15,8 @@ var (
appService = service.NewIAppService()
appInstallService = service.NewIAppInstalledService()
AIToolService = service.NewIAIToolService()
containerService = service.NewIContainerService()
composeTemplateService = service.NewIComposeTemplateService()
imageRepoService = service.NewIImageRepoService()
+17
View File
@@ -417,6 +417,23 @@ func (b *BaseApi) CheckFile(c *gin.Context) {
helper.SuccessWithData(c, true)
}
// @Tags File
// @Summary Batch check file exist
// @Accept json
// @Param request body request.FilePathsCheck true "request"
// @Success 200 {array} response.ExistFileInfo
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /files/batch/check [post]
func (b *BaseApi) BatchCheckFiles(c *gin.Context) {
var req request.FilePathsCheck
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
fileList := fileService.BatchCheckFiles(req)
helper.SuccessWithData(c, fileList)
}
// @Tags File
// @Summary Change file name
// @Accept json
+2 -2
View File
@@ -56,8 +56,8 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
return
}
if req.Key == "SecurityEntrance" {
if checkEntrancePattern(req.Value) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("regexp match string with %s failed", req.Value))
if !checkEntrancePattern(req.Value) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("the format of the security entrance %s is incorrect.", req.Value))
return
}
}
+65
View File
@@ -10,6 +10,7 @@ import (
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
@@ -146,6 +147,70 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
}
}
func (b *BaseApi) OllamaWsSsh(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
global.LOG.Errorf("gin context http handler failed, err: %v", err)
return
}
defer wsConn.Close()
if global.CONF.System.IsDemo {
if wshandleError(wsConn, errors.New(" demo server, prohibit this operation!")) {
return
}
}
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param cols in request")) {
return
}
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
return
}
name := c.Query("name")
if cmd.CheckIllegal(name) {
if wshandleError(wsConn, errors.New(" The command contains illegal characters.")) {
return
}
}
container, err := service.LoadContainerName()
if wshandleError(wsConn, errors.WithMessage(err, " load container name for ollama failed")) {
return
}
commands := []string{"ollama", "run", name}
pidMap := loadMapFromDockerTop(container)
fmt.Println("pidMap")
for k, v := range pidMap {
fmt.Println(k, v)
}
itemCmds := append([]string{"exec", "-it", container}, commands...)
slave, err := terminal.NewCommand(itemCmds)
if wshandleError(wsConn, err) {
return
}
defer killBash(container, strings.Join(commands, " "), pidMap)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
if wshandleError(wsConn, err) {
return
}
quitChan := make(chan bool, 3)
tty.Start(quitChan)
go slave.Wait(quitChan)
<-quitChan
global.LOG.Info("websocket finished")
if wshandleError(wsConn, err) {
return
}
}
func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
+44
View File
@@ -0,0 +1,44 @@
package dto
import "time"
type OllamaModelInfo struct {
ID uint `json:"id"`
Name string `json:"name"`
Size string `json:"size"`
From string `json:"from"`
LogFileExist bool `json:"logFileExist"`
Status string `json:"status"`
Message string `json:"message"`
CreatedAt time.Time `json:"createdAt"`
}
type OllamaModelDropList struct {
ID uint `json:"id"`
Name string `json:"name"`
}
type OllamaModelName struct {
Name string `json:"name"`
}
type OllamaBindDomain struct {
Domain string `json:"domain" validate:"required"`
AppInstallID uint `json:"appInstallID" validate:"required"`
SSLID uint `json:"sslID"`
WebsiteID uint `json:"websiteID"`
IPList string `json:"ipList"`
}
type OllamaBindDomainReq struct {
AppInstallID uint `json:"appInstallID" validate:"required"`
}
type OllamaBindDomainRes struct {
Domain string `json:"domain"`
SSLID uint `json:"sslID"`
AllowIPs []string `json:"allowIPs"`
WebsiteID uint `json:"websiteID"`
ConnUrl string `json:"connUrl"`
}
+3 -2
View File
@@ -78,8 +78,8 @@ type AppProperty struct {
Name string `json:"name"`
Type string `json:"type"`
Tags []string `json:"tags"`
ShortDescZh string `json:"shortDescZh"`
ShortDescEn string `json:"shortDescEn"`
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
Description Locale `json:"description"`
Key string `json:"key"`
Required []string `json:"Required"`
@@ -90,6 +90,7 @@ type AppProperty struct {
Github string `json:"github"`
Document string `json:"document"`
Version float64 `json:"version"`
GpuSupport bool `json:"gpuSupport"`
}
type AppConfigVersion struct {
+5
View File
@@ -52,3 +52,8 @@ type OperationWithNameAndType struct {
Name string `json:"name"`
Type string `json:"type" validate:"required"`
}
type ForceDelete struct {
IDs []uint `json:"ids"`
ForceDelete bool `json:"forceDelete"`
}
+1
View File
@@ -33,6 +33,7 @@ type AppContainerConfig struct {
DockerCompose string `json:"dockerCompose"`
HostMode bool `json:"hostMode"`
PullImage bool `json:"pullImage"`
GpuConfig bool `json:"gpuConfig"`
}
type AppInstalledSearch struct {
+4
View File
@@ -79,6 +79,10 @@ type FilePathCheck struct {
Path string `json:"path" validate:"required"`
}
type FilePathsCheck struct {
Paths []string `json:"paths" validate:"required"`
}
type FileWget struct {
Url string `json:"url" validate:"required"`
Path string `json:"path" validate:"required"`
+10 -7
View File
@@ -41,6 +41,7 @@ type AppItem struct {
Versions []string `json:"versions"`
Limit int `json:"limit"`
Tags []TagDTO `json:"tags"`
GpuSupport bool `json:"gpuSupport"`
}
type TagDTO struct {
@@ -66,10 +67,11 @@ type AppInstalledCheck struct {
type AppDetailDTO struct {
model.AppDetail
Enable bool `json:"enable"`
Params interface{} `json:"params"`
Image string `json:"image"`
HostMode bool `json:"hostMode"`
Enable bool `json:"enable"`
Params interface{} `json:"params"`
Image string `json:"image"`
HostMode bool `json:"hostMode"`
GpuSupport bool `json:"gpuSupport"`
}
type IgnoredApp struct {
@@ -90,9 +92,10 @@ type AppInstalledDTO struct {
}
type AppDetail struct {
Website string `json:"website"`
Document string `json:"document"`
Github string `json:"github"`
Website string `json:"website"`
Document string `json:"document"`
Github string `json:"github"`
GpuSupport bool `json:"gpuSupport"`
}
type AppInstallDTO struct {
+8
View File
@@ -2,6 +2,7 @@ package response
import (
"github.com/1Panel-dev/1Panel/backend/utils/files"
"time"
)
type FileInfo struct {
@@ -46,3 +47,10 @@ type FileLineContent struct {
type FileExist struct {
Exist bool `json:"exist"`
}
type ExistFileInfo struct {
Name string `json:"name"`
Path string `json:"path"`
Size float64 `json:"size"`
ModTime time.Time `json:"modTime"`
}
+11
View File
@@ -0,0 +1,11 @@
package model
type OllamaModel struct {
BaseModel
Name string `json:"name"`
Size string `json:"size"`
From string `json:"from"`
Status string `json:"status"`
Message string `json:"message"`
}
+1
View File
@@ -20,6 +20,7 @@ type App struct {
Type string `json:"type" gorm:"type:varchar(64);not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
Required string `json:"required" gorm:"type:varchar(64);"`
GpuSupport bool `json:"gpuSupport"`
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
Limit int `json:"limit" gorm:"type:Integer;not null"`
Website string `json:"website" gorm:"type:varchar(64);not null"`
+69
View File
@@ -0,0 +1,69 @@
package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
)
type AiRepo struct{}
type IAiRepo interface {
Get(opts ...DBOption) (model.OllamaModel, error)
List(opts ...DBOption) ([]model.OllamaModel, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.OllamaModel, error)
Create(cronjob *model.OllamaModel) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
}
func NewIAiRepo() IAiRepo {
return &AiRepo{}
}
func (u *AiRepo) Get(opts ...DBOption) (model.OllamaModel, error) {
var item model.OllamaModel
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&item).Error
return item, err
}
func (u *AiRepo) List(opts ...DBOption) ([]model.OllamaModel, error) {
var list []model.OllamaModel
db := global.DB.Model(&model.OllamaModel{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&list).Error
return list, err
}
func (u *AiRepo) Page(page, size int, opts ...DBOption) (int64, []model.OllamaModel, error) {
var list []model.OllamaModel
db := global.DB.Model(&model.OllamaModel{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&list).Error
return count, list, err
}
func (u *AiRepo) Create(item *model.OllamaModel) error {
return global.DB.Create(item).Error
}
func (u *AiRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.OllamaModel{}).Where("id = ?", id).Updates(vars).Error
}
func (u *AiRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.OllamaModel{}).Error
}
+395
View File
@@ -0,0 +1,395 @@
package service
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"path"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
type AIToolService struct{}
type IAIToolService interface {
Search(search dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error)
Create(name string) error
Close(name string) error
Recreate(name string) error
Delete(req dto.ForceDelete) error
Sync() ([]dto.OllamaModelDropList, error)
LoadDetail(name string) (string, error)
BindDomain(req dto.OllamaBindDomain) error
GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error)
UpdateBindDomain(req dto.OllamaBindDomain) error
}
func NewIAIToolService() IAIToolService {
return &AIToolService{}
}
func (u *AIToolService) Search(req dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error) {
var options []repo.DBOption
if len(req.Info) != 0 {
options = append(options, commonRepo.WithLikeName(req.Info))
}
total, list, err := aiRepo.Page(req.Page, req.PageSize, options...)
if err != nil {
return 0, nil, err
}
var dtoLists []dto.OllamaModelInfo
for _, itemModel := range list {
var item dto.OllamaModelInfo
if err := copier.Copy(&item, &itemModel); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
logPath := path.Join(global.CONF.System.DataDir, "log", "AITools", itemModel.Name)
if _, err := os.Stat(logPath); err == nil {
item.LogFileExist = true
}
dtoLists = append(dtoLists, item)
}
return int64(total), dtoLists, err
}
func (u *AIToolService) LoadDetail(name string) (string, error) {
if cmd.CheckIllegal(name) {
return "", buserr.New(constant.ErrCmdIllegal)
}
containerName, err := LoadContainerName()
if err != nil {
return "", err
}
stdout, err := cmd.Execf("docker exec %s ollama show %s", containerName, name)
if err != nil {
return "", err
}
return stdout, err
}
func (u *AIToolService) Create(name string) error {
if cmd.CheckIllegal(name) {
return buserr.New(constant.ErrCmdIllegal)
}
modelInfo, _ := aiRepo.Get(commonRepo.WithByName(name))
if modelInfo.ID != 0 {
return constant.ErrRecordExist
}
containerName, err := LoadContainerName()
if err != nil {
return err
}
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", name)
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
return err
}
}
info := model.OllamaModel{
Name: name,
From: "local",
Status: constant.StatusWaiting,
}
if err := aiRepo.Create(&info); err != nil {
return err
}
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
go pullOllamaModel(file, containerName, info)
return nil
}
func (u *AIToolService) Close(name string) error {
if cmd.CheckIllegal(name) {
return buserr.New(constant.ErrCmdIllegal)
}
containerName, err := LoadContainerName()
if err != nil {
return err
}
stdout, err := cmd.Execf("docker exec %s ollama stop %s", containerName, name)
if err != nil {
return fmt.Errorf("handle ollama stop %s failed, stdout: %s, err: %v", name, stdout, err)
}
return nil
}
func (u *AIToolService) Recreate(name string) error {
if cmd.CheckIllegal(name) {
return buserr.New(constant.ErrCmdIllegal)
}
modelInfo, _ := aiRepo.Get(commonRepo.WithByName(name))
if modelInfo.ID == 0 {
return constant.ErrRecordNotFound
}
containerName, err := LoadContainerName()
if err != nil {
return err
}
if err := aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusWaiting, "from": "local"}); err != nil {
return err
}
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", name)
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
return err
}
}
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
go pullOllamaModel(file, containerName, modelInfo)
return nil
}
func (u *AIToolService) Delete(req dto.ForceDelete) error {
ollamaList, _ := aiRepo.List(commonRepo.WithIdsIn(req.IDs))
if len(ollamaList) == 0 {
return constant.ErrRecordNotFound
}
containerName, err := LoadContainerName()
if err != nil && !req.ForceDelete {
return err
}
for _, item := range ollamaList {
if item.Status != constant.StatusDeleted {
stdout, err := cmd.Execf("docker exec %s ollama rm %s", containerName, item.Name)
if err != nil && !req.ForceDelete {
return fmt.Errorf("handle ollama rm %s failed, stdout: %s, err: %v", item.Name, stdout, err)
}
}
_ = aiRepo.Delete(commonRepo.WithByID(item.ID))
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", item.Name)
_ = os.Remove(logItem)
}
return nil
}
func (u *AIToolService) Sync() ([]dto.OllamaModelDropList, error) {
containerName, err := LoadContainerName()
if err != nil {
return nil, err
}
stdout, err := cmd.Execf("docker exec %s ollama list", containerName)
if err != nil {
return nil, err
}
var list []model.OllamaModel
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 5 {
continue
}
if parts[0] == "NAME" {
continue
}
list = append(list, model.OllamaModel{Name: parts[0], Size: parts[2] + " " + parts[3]})
}
listInDB, _ := aiRepo.List()
var dropList []dto.OllamaModelDropList
for _, itemModel := range listInDB {
isExit := false
for i := 0; i < len(list); i++ {
if list[i].Name == itemModel.Name {
_ = aiRepo.Update(itemModel.ID, map[string]interface{}{"status": constant.StatusSuccess, "message": "", "size": list[i].Size})
list = append(list[:i], list[(i+1):]...)
isExit = true
break
}
}
if !isExit && itemModel.Status != constant.StatusWaiting {
_ = aiRepo.Update(itemModel.ID, map[string]interface{}{"status": constant.StatusDeleted, "message": "not exist", "size": ""})
dropList = append(dropList, dto.OllamaModelDropList{ID: itemModel.ID, Name: itemModel.Name})
continue
}
}
for _, item := range list {
item.Status = constant.StatusSuccess
item.From = "remote"
_ = aiRepo.Create(&item)
}
return dropList, nil
}
func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error {
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
if nginxInstall.ID == 0 {
return buserr.New("ErrOpenrestyInstall")
}
var (
ipList []string
err error
)
if len(req.IPList) > 0 {
ipList, err = common.HandleIPList(req.IPList)
if err != nil {
return err
}
}
createWebsiteReq := request.WebsiteCreate{
PrimaryDomain: req.Domain,
Alias: strings.ToLower(req.Domain),
Type: constant.Deployment,
AppType: constant.InstalledApp,
AppInstallID: req.AppInstallID,
}
websiteService := NewIWebsiteService()
if err := websiteService.CreateWebsite(createWebsiteReq); err != nil {
return err
}
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(strings.ToLower(req.Domain)))
if err != nil {
return err
}
if len(ipList) > 0 {
if err = ConfigAllowIPs(ipList, website); err != nil {
return err
}
}
if req.SSLID > 0 {
sslReq := request.WebsiteHTTPSOp{
WebsiteID: website.ID,
Enable: true,
Type: "existed",
WebsiteSSLID: req.SSLID,
HttpConfig: "HTTPSOnly",
}
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
return err
}
}
if err = ConfigAIProxy(website); err != nil {
return err
}
return nil
}
func (u *AIToolService) GetBindDomain(req dto.OllamaBindDomainReq) (*dto.OllamaBindDomainRes, error) {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.AppInstallID))
if err != nil {
return nil, err
}
res := &dto.OllamaBindDomainRes{}
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(install.ID))
if website.ID == 0 {
return res, nil
}
res.WebsiteID = website.ID
res.Domain = website.PrimaryDomain
if website.WebsiteSSLID > 0 {
res.SSLID = website.WebsiteSSLID
}
res.ConnUrl = fmt.Sprintf("%s://%s", strings.ToLower(website.Protocol), website.PrimaryDomain)
res.AllowIPs = GetAllowIps(website)
return res, nil
}
func (u *AIToolService) UpdateBindDomain(req dto.OllamaBindDomain) error {
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
if nginxInstall.ID == 0 {
return buserr.New("ErrOpenrestyInstall")
}
var (
ipList []string
err error
)
if len(req.IPList) > 0 {
ipList, err = common.HandleIPList(req.IPList)
if err != nil {
return err
}
}
websiteService := NewIWebsiteService()
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
if err = ConfigAllowIPs(ipList, website); err != nil {
return err
}
if req.SSLID > 0 {
sslReq := request.WebsiteHTTPSOp{
WebsiteID: website.ID,
Enable: true,
Type: "existed",
WebsiteSSLID: req.SSLID,
HttpConfig: "HTTPSOnly",
}
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
return err
}
return nil
}
if website.WebsiteSSLID > 0 && req.SSLID == 0 {
sslReq := request.WebsiteHTTPSOp{
WebsiteID: website.ID,
Enable: false,
}
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
return err
}
}
return nil
}
func LoadContainerName() (string, error) {
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
if err != nil {
return "", fmt.Errorf("ollama service is not found, err: %v", err)
}
if ollamaBaseInfo.Status != constant.Running {
return "", fmt.Errorf("container %s of ollama is not running, please check and retry!", ollamaBaseInfo.ContainerName)
}
return ollamaBaseInfo.ContainerName, nil
}
func pullOllamaModel(file *os.File, containerName string, info model.OllamaModel) {
defer file.Close()
cmd := exec.Command("docker", "exec", containerName, "ollama", "pull", info.Name)
multiWriter := io.MultiWriter(os.Stdout, file)
cmd.Stdout = multiWriter
cmd.Stderr = multiWriter
_ = cmd.Run()
itemSize, err := loadModelSize(info.Name, containerName)
if len(itemSize) != 0 {
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize})
} else {
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
}
_, _ = file.WriteString("ollama pull completed!")
}
func loadModelSize(name string, containerName string) (string, error) {
stdout, err := cmd.Execf("docker exec %s ollama list | grep %s", containerName, name)
if err != nil {
return "", err
}
lines := strings.Split(string(stdout), "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 5 {
continue
}
return parts[2] + " " + parts[3], nil
}
return "", fmt.Errorf("no such model %s in ollama list, std: %s", name, string(stdout))
}
+11 -7
View File
@@ -94,13 +94,14 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
lang := strings.ToLower(common.GetLang(ctx))
for _, ap := range apps {
appDTO := &response.AppItem{
ID: ap.ID,
Name: ap.Name,
Key: ap.Key,
Type: ap.Type,
Icon: ap.Icon,
Resource: ap.Resource,
Limit: ap.Limit,
ID: ap.ID,
Name: ap.Name,
Key: ap.Key,
Type: ap.Type,
Icon: ap.Icon,
Resource: ap.Resource,
Limit: ap.Limit,
GpuSupport: ap.GpuSupport,
}
appDTO.Description = ap.GetDescription(ctx)
appDTOs = append(appDTOs, appDTO)
@@ -167,6 +168,7 @@ func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, erro
if err != nil {
return nil, err
}
appDTO.GpuSupport = app.GpuSupport
appDTO.Tags = tags
return &appDTO, nil
}
@@ -264,6 +266,7 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
if err := checkLimit(app); err != nil {
appDetailDTO.Enable = false
}
appDetailDTO.GpuSupport = app.GpuSupport
return appDetailDTO, nil
}
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
@@ -862,6 +865,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
global.LOG.Infof("Starting synchronization of application details...")
for _, l := range list.Apps {
app := appsMap[l.AppProperty.Key]
app.GpuSupport = l.AppProperty.GpuSupport
if l.AppProperty.Version > 0 && common.CompareVersion(strconv.FormatFloat(l.AppProperty.Version, 'f', -1, 64), setting.SystemVersion) {
delete(appsMap, l.AppProperty.Key)
+1
View File
@@ -750,6 +750,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
}
res.AppContainerConfig = config
res.HostMode = isHostModel(install.DockerCompose)
res.GpuConfig = isGpuConfig(install.DockerCompose)
return &res, nil
}
+47 -6
View File
@@ -1163,12 +1163,11 @@ func handleLocalApp(appDir string) (app *model.App, err error) {
app.Website = appDefine.Website
app.Github = appDefine.Github
app.Document = appDefine.Document
if appDefine.ShortDescZh != "" {
appDefine.Description.Zh = appDefine.ShortDescZh
app.ShortDescZh = appDefine.ShortDescZh
}
if appDefine.ShortDescEn != "" {
appDefine.Description.En = appDefine.ShortDescEn
app.ShortDescEn = appDefine.ShortDescEn
}
desc, _ := json.Marshal(appDefine.Description)
app.Description = string(desc)
@@ -1339,9 +1338,10 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
Path: installed.GetPath(),
CreatedAt: installed.CreatedAt,
App: response.AppDetail{
Github: installed.App.Github,
Website: installed.App.Website,
Document: installed.App.Document,
Github: installed.App.Github,
Website: installed.App.Website,
Document: installed.App.Document,
GpuSupport: installed.App.GpuSupport,
},
}
if updated {
@@ -1500,6 +1500,20 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
deploy["resources"] = resource
serviceValue["deploy"] = deploy
if req.GpuConfig {
resource["reservations"] = map[string]interface{}{
"devices": []map[string]interface{}{
{
"driver": "nvidia",
"count": "all",
"capabilities": []string{"gpu"},
},
},
}
} else {
delete(resource, "reservations")
}
ports, ok := serviceValue["ports"].([]interface{})
if ok {
for i, port := range ports {
@@ -1601,6 +1615,33 @@ func isHostModel(dockerCompose string) bool {
return false
}
func isGpuConfig(dockerCompose string) bool {
composeMap := make(map[string]interface{})
_ = yaml.Unmarshal([]byte(dockerCompose), &composeMap)
services, serviceValid := composeMap["services"].(map[string]interface{})
if !serviceValid {
return false
}
for _, service := range services {
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{}
if de, ok := serviceValue["deploy"]; ok {
deploy = de.(map[string]interface{})
}
resource := map[string]interface{}{}
if res, ok := deploy["resources"]; ok {
resource = res.(map[string]interface{})
}
if reservations, ok := resource["reservations"]; ok {
reservationsMap := reservations.(map[string]interface{})
if _, dOk := reservationsMap["devices"]; dOk {
return true
}
}
}
return false
}
func RequestDownloadCallBack(downloadCallBackUrl string) {
if downloadCallBackUrl == "" {
return
+3 -5
View File
@@ -3,6 +3,8 @@ package service
import (
"crypto/hmac"
"encoding/base64"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
@@ -13,7 +15,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/pkg/errors"
"strconv"
)
type AuthService struct{}
@@ -203,10 +204,7 @@ func (u *AuthService) GetSecurityEntrance() string {
func (u *AuthService) IsLogin(c *gin.Context) bool {
sID, _ := c.Cookie(constant.SessionName)
_, err := global.SESSION.Get(sID)
if err != nil {
return false
}
return true
return err == nil
}
func checkPassword(password string) error {
+28 -8
View File
@@ -10,19 +10,19 @@ import (
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/xpu"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
type DashboardService struct{}
@@ -341,7 +341,17 @@ func loadDiskInfo() []dto.DiskInfo {
}
func loadGPUInfo() []dto.GPUInfo {
list := xpack.LoadGpuInfo()
ok, client := gpu.New()
var list []interface{}
if ok {
info, err := client.LoadGpuInfo()
if err != nil || len(info.GPUs) == 0 {
return nil
}
for _, item := range info.GPUs {
list = append(list, item)
}
}
if len(list) == 0 {
return nil
}
@@ -359,7 +369,17 @@ func loadGPUInfo() []dto.GPUInfo {
}
func loadXpuInfo() []dto.XPUInfo {
list := xpack.LoadXpuInfo()
var list []interface{}
ok, xpuClient := xpu.New()
if ok {
xpus, err := xpuClient.LoadDashData()
if err != nil || len(xpus) == 0 {
return nil
}
for _, item := range xpus {
list = append(list, item)
}
}
if len(list) == 0 {
return nil
}
-4
View File
@@ -50,10 +50,6 @@ func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (st
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "mysql-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
case "mariadb-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
+2
View File
@@ -12,6 +12,8 @@ var (
appInstallRepo = repo.NewIAppInstallRepo()
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
aiRepo = repo.NewIAiRepo()
mysqlRepo = repo.NewIMysqlRepo()
postgresqlRepo = repo.NewIPostgresqlRepo()
databaseRepo = repo.NewIDatabaseRepo()
+22
View File
@@ -50,6 +50,7 @@ type IFileService interface {
ChangeMode(op request.FileCreate) error
BatchChangeModeAndOwner(op request.FileRoleReq) error
ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error)
BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo
}
var filteredPaths = []string{
@@ -478,6 +479,12 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
}
case "image-pull", "image-push", "image-build", "compose-create":
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
case "ollama-model":
logFilePath = path.Join(global.CONF.System.DataDir, "log", "AITools", req.Name)
case "mysql-slow-logs":
logFilePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
case "mariadb-slow-logs":
logFilePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
}
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
@@ -501,3 +508,18 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
}
return res, nil
}
func (f *FileService) BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo {
fileList := make([]response.ExistFileInfo, 0, len(req.Paths))
for _, filePath := range req.Paths {
if info, err := os.Stat(filePath); err == nil {
fileList = append(fileList, response.ExistFileInfo{
Size: float64(info.Size()),
Name: info.Name(),
Path: filePath,
ModTime: info.ModTime(),
})
}
}
return fileList
}
+58
View File
@@ -642,9 +642,15 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
}
if param.Name == "ssl_protocols" {
nginxParams[i].Params = req.SSLProtocol
if len(req.SSLProtocol) == 0 {
nginxParams[i].Params = []string{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"}
}
}
if param.Name == "ssl_ciphers" {
nginxParams[i].Params = []string{req.Algorithm}
if len(req.Algorithm) == 0 {
nginxParams[i].Params = []string{"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED"}
}
}
}
if req.Hsts {
@@ -1106,3 +1112,55 @@ func getResourceContent(fileOp files.FileOp, resourcePath string) (string, error
}
return "", nil
}
func ConfigAllowIPs(ips []string, website model.Website) error {
nginxFull, err := getNginxFull(&website)
if err != nil {
return err
}
nginxConfig := nginxFull.SiteConfig
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
server.RemoveDirective("allow", nil)
server.RemoveDirective("deny", nil)
if len(ips) > 0 {
server.UpdateAllowIPs(ips)
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
return nginxCheckAndReload(nginxConfig.OldContent, config.FilePath, nginxFull.Install.ContainerName)
}
func GetAllowIps(website model.Website) []string {
nginxFull, err := getNginxFull(&website)
if err != nil {
return nil
}
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
dirs := server.GetDirectives()
var ips []string
for _, dir := range dirs {
if dir.GetName() == "allow" {
ips = append(ips, dir.GetParameters()...)
}
}
return ips
}
func ConfigAIProxy(website model.Website) error {
nginxFull, err := getNginxFull(&website)
if err != nil {
return nil
}
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
dirs := server.GetDirectives()
for _, dir := range dirs {
if dir.GetName() == "location" && dir.GetParameters()[0] == "/" {
server.UpdateRootProxyForAi([]string{fmt.Sprintf("http://%s", website.Proxy)})
}
}
return nil
}
+5 -1
View File
@@ -32,6 +32,10 @@ var WebUrlMap = map[string]struct{}{
"/apps/installed": {},
"/apps/upgrade": {},
"/ai": {},
"/ai/model": {},
"/ai/gpu": {},
"/containers": {},
"/containers/container": {},
"/containers/image": {},
@@ -113,11 +117,11 @@ var WebUrlMap = map[string]struct{}{
"/xpack/monitor/rank": {},
"/xpack/monitor/log": {},
"/xpack/tamper": {},
"/xpack/gpu": {},
"/xpack/alert/dashboard": {},
"/xpack/alert/log": {},
"/xpack/alert/setting": {},
"/xpack/setting": {},
"/xpack/app": {},
}
var DynamicRoutes = []string{
+7
View File
@@ -182,3 +182,10 @@ var (
ErrAlertSync = "ErrAlertSync"
ErrAlertRemote = "ErrAlertRemote"
)
// mobile app
var (
ErrVerifyToken = "ErrVerifyToken"
ErrInvalidToken = "ErrInvalidToken"
ErrExpiredToken = "ErrExpiredToken"
)
+2
View File
@@ -6,6 +6,8 @@ const (
StatusWaiting = "Waiting"
StatusSuccess = "Success"
StatusFailed = "Failed"
StatusDeleted = "Deleted"
StatusCanceled = "Canceled"
StatusUploading = "Uploading"
StatusEnable = "Enable"
StatusDisable = "Disable"
+3 -1
View File
@@ -13,8 +13,10 @@ func NewAppStoreJob() *app {
func (a *app) Run() {
global.LOG.Info("AppStore scheduled task in progress ...")
if err := service.NewIAppService().SyncAppListFromRemote(); err != nil {
appService := service.NewIAppService()
if err := appService.SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("AppStore sync failed %s", err.Error())
}
appService.SyncAppListFromLocal()
global.LOG.Info("AppStore scheduled task has completed")
}
+8
View File
@@ -284,3 +284,11 @@ UserInfoPassHelp: "Tip: To change the password, you can execute the command: "
DBConnErr: "Error: Failed to initialize database connection, {{ .err }}"
SystemVersion: "version: "
SystemMode: "mode: "
#ai-tool
ErrOpenrestyInstall: 'Please install Openresty first'
#mobile app
ErrVerifyToken: 'Token verification error, please reset and scan again.'
ErrInvalidToken: 'Invalid token, please reset and scan again.'
ErrExpiredToken: 'Token has expired, please reset and scan again.'
+8
View File
@@ -281,3 +281,11 @@ UserInfoPassHelp: "ヒント:パスワードを変更するには、コマン
DBConnErr: "エラー:データベース接続の初期化に失敗しました、{{.err}}"
SystemVersion: "バージョン:"
SystemMode: "モード:"
#ai-tool
ErrOpenrestyInstall: 'まず Openresty をインストールしてください'
#mobile app
ErrVerifyToken: 'トークンの検証エラーです。リセット後、再度QRコードをスキャンしてください。'
ErrInvalidToken: '無効なトークンです。リセット後、再度QRコードをスキャンしてください。'
ErrExpiredToken: 'トークンの有効期限が切れました。リセット後、再度QRコードをスキャンしてください。'
+8
View File
@@ -284,3 +284,11 @@ UserInfoPassHelp: "팁: 비밀번호를 변경하려면 다음 명령어를 실
DBConnErr: "오류: 데이터베이스 연결 초기화 실패 {{ .err }}"
SystemVersion: "버전: "
SystemMode: "모드: "
#ai-tool
ErrOpenrestyInstall: '먼저 Openresty를 설치하세요'
#mobile app
ErrVerifyToken: '토큰 검증 오류가 발생했습니다. 재설정 후 다시 스캔해 주세요.'
ErrInvalidToken: '유효하지 않은 토큰입니다. 재설정 후 다시 스캔해 주세요.'
ErrExpiredToken: '토큰이 만료되었습니다. 재설정 후 다시 스캔해 주세요.'
+8
View File
@@ -283,3 +283,11 @@ UserInfoPassHelp: "Petua: Untuk menukar kata laluan, anda boleh menjalankan arah
DBConnErr: "Ralat: Gagal memulakan sambungan pangkalan data, {{ .err }}"
SystemVersion: "Versi: "
SystemMode: "Mod: "
#ai-tool
ErrOpenrestyInstall: 'Sila pasang Openresty terlebih dahulu'
#mobile app
ErrVerifyToken: 'Ralat pengesahan token, sila tetapkan semula dan imbas semula.'
ErrInvalidToken: 'Token tidak sah, sila tetapkan semula dan imbas semula.'
ErrExpiredToken: 'Token telah tamat tempoh, sila tetapkan semula dan imbas semula.'
+9 -1
View File
@@ -280,4 +280,12 @@ UserInfoAddr: "Endereço do painel: "
UserInfoPassHelp: "Dica: Para alterar a senha, você pode executar o comando: "
DBConnErr: "Erro: Falha ao inicializar a conexão com o banco de dados, {{ .err }}"
SystemVersion: "versão: "
SystemMode: "modo: "
SystemMode: "modo: "
#ai-tool
ErrOpenrestyInstall: 'Por favor, instale o Openresty primeiro'
#mobile app
ErrVerifyToken: 'Erro de verificação do token, por favor, reinicie e escaneie novamente.'
ErrInvalidToken: 'Token inválido, por favor, reinicie e escaneie novamente.'
ErrExpiredToken: 'O token expirou, por favor, reinicie e escaneie novamente.'
-63
View File
@@ -1,63 +0,0 @@
#cmd
AppVersion: "Versão do aplicativo"
AppCommands: "Comandos relacionados ao aplicativo"
AppInit: "Inicializar aplicativo"
AppKeyVal: "Chave do aplicativo (suporta apenas inglês)"
AppCreateFileErr: "Falha na criação do arquivo {{ .name }} {{ .err }}"
AppCreateDirErr: "Falha na criação da pasta {{ .name }} {{ .err }}"
AppMissKey: "Chave do aplicativo ausente, use -k para especificar"
AppMissVersion: "Versão do aplicativo ausente, use -v para especificar"
AppVersionExist: "Versão já existente!"
AppCreateSuccessful: "Criação bem-sucedida!"
AppWriteErr: "Falha na gravação do arquivo {{ .name }} {{ .err }}"
SudoHelper: "Por favor, use {{ .cmd }} ou troque para o usuário root"
ListenIPCommands: "Alterar IP de escuta"
ListenIPv4: "Escutar no IPv4"
ListenIPv6: "Escutar no IPv6"
ListenChangeSuccessful: "Alteração bem-sucedida! Agora escutando em {{ .value }}"
ResetCommands: "Redefinir informações do sistema"
ResetMFA: "Cancelar autenticação de dois fatores do 1Panel"
ResetHttps: "Cancelar login HTTPS do 1Panel"
ResetEntrance: "Cancelar entrada segura do 1Panel"
ResetIPs: "Cancelar restrições de IP autorizados do 1Panel"
ResetDomain: "Cancelar vinculação de domínio do 1Panel"
RestoreCommands: "Restaurar serviço e dados do 1Panel"
RestoreNoSuchFile: "Nenhum arquivo disponível para restauração"
RestoreStep1: "(1/5) Iniciando a restauração do serviço e dados do 1Panel a partir do diretório {{ .name }}..."
RestoreStep2: "(2/5) Restauração do binário do 1Panel bem-sucedida"
RestoreStep3: "(3/5) Restauração do script do 1Panel bem-sucedida"
RestoreStep4: "(4/5) Restauração do serviço do 1Panel bem-sucedida"
RestoreStep5: "(5/5) Restauração dos dados do 1Panel bem-sucedida"
RestoreSuccessful: "Restauração bem-sucedida! Reiniciando o serviço, aguarde..."
UpdateCommands: "Atualizar informações do painel"
UpdateUser: "Atualizar usuário do painel"
UpdatePassword: "Atualizar senha do painel"
UpdatePort: "Atualizar porta do painel"
UpdateUserNull: "Erro: usuário do painel está vazio!"
UpdateUserBlank: "Erro: usuário do painel contém espaços!"
UpdateUserFormat: "Erro: Formato de usuário inválido! Aceita apenas inglês, chinês, números e _, comprimento de 3-30"
UpdateUserErr: "Erro: Falha ao atualizar usuário do painel, {{ .err }}"
UpdateSuccessful: "Atualização bem-sucedida!"
UpdateUserResult: "Usuário do painel: {{ .name }}"
UpdatePasswordRead: "Erro: Falha ao ler informações da senha do painel, {{ .err }}"
UpdatePasswordNull: "Erro: Senha do painel está vazia!"
UpdateUPasswordBlank: "Erro: Senha do painel contém espaços!"
UpdatePasswordFormat: "Erro: A senha do painel aceita apenas letras, números, caracteres especiais !@#$%*_,.?, comprimento de 8-30!"
UpdatePasswordLen: "Erro: Por favor, insira uma senha com mais de 6 caracteres!"
UpdatePasswordRe: "Confirmar senha:"
UpdatePasswordErr: "Erro: Falha ao atualizar senha do painel, {{ .err }}"
UpdatePasswordSame: "Erro: As duas senhas não coincidem, por favor, verifique e tente novamente!"
UpdatePasswordResult: "Senha do painel: {{ .name }}"
UpdatePortFormat: "Erro: O número da porta deve estar entre 1 e 65535!"
UpdatePortUsed: "Erro: O número da porta já está em uso, por favor, verifique e tente novamente!"
UpdatePortErr: "Erro: Falha ao atualizar a porta do painel, {{ .err }}"
UpdatePortResult: "Porta do painel: {{ .name }}"
UpdatePortFirewallAdd: "Falha ao adicionar regra de porta no firewall, {{ .err }}, adicione manualmente a porta {{ .name }} às regras do firewall."
UpdatePortFirewallDel: "Erro: Falha ao excluir porta do firewall, {{ .err }}"
UpdatePortFirewallReload: "Falha ao recarregar o firewall, {{ .err }}, recarregue o firewall manualmente."
UserInfo: "Obter informações do painel"
UserInfoAddr: "Endereço do painel: "
UserInfoPassHelp: "Dica: Para alterar a senha, execute o comando: "
DBConnErr: "Erro: Falha ao inicializar conexão com o banco de dados, {{ .err }}"
SystemVersion: "versão: "
SystemMode: "modo: "
+8
View File
@@ -284,3 +284,11 @@ UserInfoPassHelp: "Подсказка: чтобы изменить пароль,
DBConnErr: "Ошибка: не удалось инициализировать подключение к базе данных, {{ .err }}"
SystemVersion: "версия: "
SystemMode: "режим: "
#ai-tool
"ErrOpenrestyInstall": "Пожалуйста, установите Openresty сначала"
#mobile app
ErrVerifyToken: 'шибка проверки токена, пожалуйста, сбросьте и отсканируйте снова.'
ErrInvalidToken: 'Неверный токен, пожалуйста, сбросьте и отсканируйте снова.'
ErrExpiredToken: 'Токен истек, пожалуйста, сбросьте и отсканируйте снова.'
+8
View File
@@ -284,3 +284,11 @@ UserInfoPassHelp: "提示:修改密碼可執行指令:"
DBConnErr: "錯誤:初始化資料庫連線失敗,{{ .err }}"
SystemVersion: "版本:"
SystemMode: "模式:"
#ai-tool
"ErrOpenrestyInstall": "請先安裝 Openresty"
#mobile app
ErrVerifyToken: '令牌驗證錯誤,請重置後再次掃碼'
ErrInvalidToken: '無效的令牌,請重置後再次掃碼'
ErrExpiredToken: '令牌過期,請重置後再次掃碼'
+8
View File
@@ -284,3 +284,11 @@ UserInfoPassHelp: "提示:修改密码可执行命令:"
DBConnErr: "错误:初始化数据库连接失败,{{ .err }}"
SystemVersion: "版本:"
SystemMode: "模式:"
#ai-tool
ErrOpenrestyInstall: '请先安装 Openresty'
#mobile app
ErrVerifyToken: '令牌验证错误,请重置后再次扫码'
ErrInvalidToken: '无效的令牌,请重置后再次扫码'
ErrExpiredToken: '令牌过期,请重置后再次扫码'
+6
View File
@@ -87,6 +87,7 @@ func Init() {
handleUserInfo(global.CONF.System.ChangeUserInfo, settingRepo)
handleCronjobStatus()
handleOllamaModelStatus()
handleSnapStatus()
loadLocalDir()
initDir()
@@ -150,6 +151,11 @@ func handleSnapStatus() {
}
}
func handleOllamaModelStatus() {
message := "the task was interrupted due to the restart of the 1panel service"
_ = global.DB.Model(&model.OllamaModel{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{"status": constant.StatusCanceled, "message": message}).Error
}
func handleCronjobStatus() {
var jobRecords []model.JobRecords
_ = global.DB.Where("status = ?", constant.StatusWaiting).Find(&jobRecords).Error
+3
View File
@@ -102,6 +102,9 @@ func Init() {
migrations.UpdateAppTag,
migrations.UpdateApp,
migrations.AddOllamaModel,
migrations.AddAppMenu,
migrations.AddAppPanelName,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+69 -1
View File
@@ -372,7 +372,7 @@ var UpdateAppTag = &gormigrate.Migration{
}
var UpdateApp = &gormigrate.Migration{
ID: "20250114-update-app",
ID: "20250213-update-app",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.App{}); err != nil {
return err
@@ -380,3 +380,71 @@ var UpdateApp = &gormigrate.Migration{
return nil
},
}
var AddOllamaModel = &gormigrate.Migration{
ID: "20250218-add-ollama-model",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.OllamaModel{}); err != nil {
return err
}
return nil
},
}
var AddAppMenu = &gormigrate.Migration{
ID: "20250217-update-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
var (
setting model.Setting
menu dto.XpackHideMenu
)
tx.Model(&model.Setting{}).Where("key = ?", "XpackHideMenu").First(&setting)
if err := json.Unmarshal([]byte(setting.Value), &menu); err != nil {
return err
}
var newChildren []dto.XpackHideMenu
for _, item := range menu.Children {
if item.ID != "4" {
newChildren = append(newChildren, item)
}
}
menu.Children = newChildren
appIsCheck := false
for _, item := range menu.Children {
if item.IsCheck {
appIsCheck = true
break
}
}
menu.Children = append(menu.Children, dto.XpackHideMenu{
ID: "8",
Title: "xpack.app.app",
Path: "/xpack/app",
Label: "XApp",
IsCheck: appIsCheck,
})
data, err := json.Marshal(menu)
if err != nil {
return err
}
return tx.Model(&model.Setting{}).Where("key = ?", "XpackHideMenu").Updates(map[string]interface{}{"value": string(data)}).Error
},
}
var AddAppPanelName = &gormigrate.Migration{
ID: "20250218-add-app-panel-name",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "AppPanelName", Value: ""}).Error; err != nil {
return err
}
return nil
},
}
+10 -3
View File
@@ -71,18 +71,25 @@ func SessionAuth() gin.HandlerFunc {
func isValid1PanelTimestamp(panelTimestamp string) bool {
apiKeyValidityTime := global.CONF.System.ApiKeyValidityTime
apiTime, err := strconv.Atoi(apiKeyValidityTime)
if err != nil {
if err != nil || apiTime < 0 {
global.LOG.Errorf("apiTime %d, err: %v", apiTime, err)
return false
}
if apiTime == 0 {
return true
}
panelTime, err := strconv.ParseInt(panelTimestamp, 10, 64)
if err != nil {
global.LOG.Errorf("panelTimestamp %s, panelTime %d, apiTime %d, err: %v", panelTimestamp, apiTime, panelTime, err)
return false
}
nowTime := time.Now().Unix()
if panelTime > nowTime {
tolerance := int64(60)
if panelTime > nowTime+tolerance {
global.LOG.Errorf("Valid Panel Timestamp, apiTime %d, panelTime %d, nowTime %d, err: %v", apiTime, panelTime, nowTime, err)
return false
}
return apiTime == 0 || nowTime-panelTime <= int64(apiTime*60)
return nowTime-panelTime <= int64(apiTime)*60+tolerance
}
func isValid1PanelToken(panelToken string, panelTimestamp string) bool {
+1
View File
@@ -23,5 +23,6 @@ func commonGroups() []CommonRouter {
&RuntimeRouter{},
&ProcessRouter{},
&WebsiteCARouter{},
&AIToolsRouter{},
}
}
+31
View File
@@ -0,0 +1,31 @@
package router
import (
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
"github.com/1Panel-dev/1Panel/backend/middleware"
"github.com/gin-gonic/gin"
)
type AIToolsRouter struct {
}
func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) {
aiToolsRouter := Router.Group("ai")
aiToolsRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi
{
aiToolsRouter.GET("/ollama/exec", baseApi.OllamaWsSsh)
aiToolsRouter.POST("/ollama/close", baseApi.CloseOllamaModel)
aiToolsRouter.POST("/ollama/model", baseApi.CreateOllamaModel)
aiToolsRouter.POST("/ollama/model/recreate", baseApi.RecreateOllamaModel)
aiToolsRouter.POST("/ollama/model/search", baseApi.SearchOllamaModel)
aiToolsRouter.POST("/ollama/model/sync", baseApi.SyncOllamaModel)
aiToolsRouter.POST("/ollama/model/load", baseApi.LoadOllamaModelDetail)
aiToolsRouter.POST("/ollama/model/del", baseApi.DeleteOllamaModel)
aiToolsRouter.GET("/gpu/load", baseApi.LoadGpuInfo)
aiToolsRouter.POST("/domain/bind", baseApi.BindDomain)
aiToolsRouter.POST("/domain/get", baseApi.GetBindDomain)
aiToolsRouter.POST("/domain/update", baseApi.UpdateBindDomain)
}
}
+1
View File
@@ -27,6 +27,7 @@ func (f *FileRouter) InitRouter(Router *gin.RouterGroup) {
fileRouter.POST("/content", baseApi.GetContent)
fileRouter.POST("/save", baseApi.SaveContent)
fileRouter.POST("/check", baseApi.CheckFile)
fileRouter.POST("/batch/check", baseApi.BatchCheckFiles)
fileRouter.POST("/upload", baseApi.UploadFiles)
fileRouter.POST("/chunkupload", baseApi.UploadChunkFiles)
fileRouter.POST("/rename", baseApi.ChangeFileName)
@@ -0,0 +1,37 @@
package common
type GpuInfo struct {
CudaVersion string `json:"cudaVersion"`
DriverVersion string `json:"driverVersion"`
Type string `json:"type"`
GPUs []GPU `json:"gpu"`
}
type GPU struct {
Index uint `json:"index"`
ProductName string `json:"productName"`
PersistenceMode string `json:"persistenceMode"`
BusID string `json:"busID"`
DisplayActive string `json:"displayActive"`
ECC string `json:"ecc"`
FanSpeed string `json:"fanSpeed"`
Temperature string `json:"temperature"`
PerformanceState string `json:"performanceState"`
PowerDraw string `json:"powerDraw"`
MaxPowerLimit string `json:"maxPowerLimit"`
MemUsed string `json:"memUsed"`
MemTotal string `json:"memTotal"`
GPUUtil string `json:"gpuUtil"`
ComputeMode string `json:"computeMode"`
MigMode string `json:"migMode"`
Processes []Process `json:"processes"`
}
type Process struct {
Pid string `json:"pid"`
Type string `json:"type"`
ProcessName string `json:"processName"`
UsedMemory string `json:"usedMemory"`
}
+65
View File
@@ -0,0 +1,65 @@
package gpu
import (
"bytes"
_ "embed"
"encoding/xml"
"errors"
"fmt"
"io"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu/common"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu/schema_v12"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
)
type NvidiaSMI struct{}
func New() (bool, NvidiaSMI) {
return cmd.Which("nvidia-smi"), NvidiaSMI{}
}
func (n NvidiaSMI) LoadGpuInfo() (*common.GpuInfo, error) {
std, err := cmd.ExecWithTimeOut("nvidia-smi -q -x", 5*time.Second)
if err != nil {
return nil, fmt.Errorf("calling nvidia-smi failed, err: %v", std)
}
data := []byte(std)
schema := "v11"
buf := bytes.NewBuffer(data)
decoder := xml.NewDecoder(buf)
for {
token, err := decoder.Token()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
return nil, fmt.Errorf("reading token failed: %w", err)
}
d, ok := token.(xml.Directive)
if !ok {
continue
}
directive := string(d)
if !strings.HasPrefix(directive, "DOCTYPE") {
continue
}
parts := strings.Split(directive, " ")
s := strings.Trim(parts[len(parts)-1], "\" ")
if strings.HasPrefix(s, "nvsmi_device_") && strings.HasSuffix(s, ".dtd") {
schema = strings.TrimSuffix(strings.TrimPrefix(s, "nvsmi_device_"), ".dtd")
} else {
global.LOG.Debugf("Cannot find schema version in %q", directive)
}
break
}
if schema != "v12" {
return &common.GpuInfo{}, nil
}
return schema_v12.Parse(data)
}
@@ -0,0 +1,58 @@
package schema_v12
import (
"encoding/xml"
"github.com/1Panel-dev/1Panel/backend/utils/ai_tools/gpu/common"
)
func Parse(buf []byte) (*common.GpuInfo, error) {
var (
s smi
info common.GpuInfo
)
if err := xml.Unmarshal(buf, &s); err != nil {
return nil, err
}
info.Type = "nvidia"
info.CudaVersion = s.CudaVersion
info.DriverVersion = s.DriverVersion
if len(s.Gpu) == 0 {
return &info, nil
}
for i := 0; i < len(s.Gpu); i++ {
var gpuItem common.GPU
gpuItem.Index = uint(i)
gpuItem.ProductName = s.Gpu[i].ProductName
gpuItem.PersistenceMode = s.Gpu[i].PersistenceMode
gpuItem.BusID = s.Gpu[i].ID
gpuItem.DisplayActive = s.Gpu[i].DisplayActive
gpuItem.ECC = s.Gpu[i].EccMode.CurrentEcc
if gpuItem.ECC == "Enabled" {
gpuItem.ECC = s.Gpu[i].EccErrors.Volatile.DramUncorrectable
}
gpuItem.FanSpeed = s.Gpu[i].FanSpeed
gpuItem.Temperature = s.Gpu[i].Temperature.GpuTemp
gpuItem.PerformanceState = s.Gpu[i].PerformanceState
gpuItem.PowerDraw = s.Gpu[i].GpuPowerReadings.PowerDraw
gpuItem.MaxPowerLimit = s.Gpu[i].GpuPowerReadings.MaxPowerLimit
gpuItem.MemUsed = s.Gpu[i].FbMemoryUsage.Used
gpuItem.MemTotal = s.Gpu[i].FbMemoryUsage.Total
gpuItem.GPUUtil = s.Gpu[i].Utilization.GpuUtil
gpuItem.ComputeMode = s.Gpu[i].ComputeMode
gpuItem.MigMode = s.Gpu[i].MigMode.CurrentMig
for _, process := range s.Gpu[i].Processes.ProcessInfo {
gpuItem.Processes = append(gpuItem.Processes, common.Process{
Pid: process.Pid,
Type: process.Type,
ProcessName: process.ProcessName,
UsedMemory: process.UsedMemory,
})
}
info.GPUs = append(info.GPUs, gpuItem)
}
return &info, nil
}
@@ -0,0 +1,294 @@
package schema_v12
type smi struct {
AttachedGpus string `xml:"attached_gpus"`
CudaVersion string `xml:"cuda_version"`
DriverVersion string `xml:"driver_version"`
Gpu []struct {
ID string `xml:"id,attr"`
AccountedProcesses struct{} `xml:"accounted_processes"`
AccountingMode string `xml:"accounting_mode"`
AccountingModeBufferSize string `xml:"accounting_mode_buffer_size"`
AddressingMode string `xml:"addressing_mode"`
ApplicationsClocks struct {
GraphicsClock string `xml:"graphics_clock"`
MemClock string `xml:"mem_clock"`
} `xml:"applications_clocks"`
Bar1MemoryUsage struct {
Free string `xml:"free"`
Total string `xml:"total"`
Used string `xml:"used"`
} `xml:"bar1_memory_usage"`
BoardID string `xml:"board_id"`
BoardPartNumber string `xml:"board_part_number"`
CcProtectedMemoryUsage struct {
Free string `xml:"free"`
Total string `xml:"total"`
Used string `xml:"used"`
} `xml:"cc_protected_memory_usage"`
ClockPolicy struct {
AutoBoost string `xml:"auto_boost"`
AutoBoostDefault string `xml:"auto_boost_default"`
} `xml:"clock_policy"`
Clocks struct {
GraphicsClock string `xml:"graphics_clock"`
MemClock string `xml:"mem_clock"`
SmClock string `xml:"sm_clock"`
VideoClock string `xml:"video_clock"`
} `xml:"clocks"`
ClocksEventReasons struct {
ClocksEventReasonApplicationsClocksSetting string `xml:"clocks_event_reason_applications_clocks_setting"`
ClocksEventReasonDisplayClocksSetting string `xml:"clocks_event_reason_display_clocks_setting"`
ClocksEventReasonGpuIdle string `xml:"clocks_event_reason_gpu_idle"`
ClocksEventReasonHwPowerBrakeSlowdown string `xml:"clocks_event_reason_hw_power_brake_slowdown"`
ClocksEventReasonHwSlowdown string `xml:"clocks_event_reason_hw_slowdown"`
ClocksEventReasonHwThermalSlowdown string `xml:"clocks_event_reason_hw_thermal_slowdown"`
ClocksEventReasonSwPowerCap string `xml:"clocks_event_reason_sw_power_cap"`
ClocksEventReasonSwThermalSlowdown string `xml:"clocks_event_reason_sw_thermal_slowdown"`
ClocksEventReasonSyncBoost string `xml:"clocks_event_reason_sync_boost"`
} `xml:"clocks_event_reasons"`
ComputeMode string `xml:"compute_mode"`
DefaultApplicationsClocks struct {
GraphicsClock string `xml:"graphics_clock"`
MemClock string `xml:"mem_clock"`
} `xml:"default_applications_clocks"`
DeferredClocks struct {
MemClock string `xml:"mem_clock"`
} `xml:"deferred_clocks"`
DisplayActive string `xml:"display_active"`
DisplayMode string `xml:"display_mode"`
DriverModel struct {
CurrentDm string `xml:"current_dm"`
PendingDm string `xml:"pending_dm"`
} `xml:"driver_model"`
EccErrors struct {
Aggregate struct {
DramCorrectable string `xml:"dram_correctable"`
DramUncorrectable string `xml:"dram_uncorrectable"`
SramCorrectable string `xml:"sram_correctable"`
SramUncorrectable string `xml:"sram_uncorrectable"`
} `xml:"aggregate"`
Volatile struct {
DramCorrectable string `xml:"dram_correctable"`
DramUncorrectable string `xml:"dram_uncorrectable"`
SramCorrectable string `xml:"sram_correctable"`
SramUncorrectable string `xml:"sram_uncorrectable"`
} `xml:"volatile"`
} `xml:"ecc_errors"`
EccMode struct {
CurrentEcc string `xml:"current_ecc"`
PendingEcc string `xml:"pending_ecc"`
} `xml:"ecc_mode"`
EncoderStats struct {
AverageFps string `xml:"average_fps"`
AverageLatency string `xml:"average_latency"`
SessionCount string `xml:"session_count"`
} `xml:"encoder_stats"`
Fabric struct {
State string `xml:"state"`
Status string `xml:"status"`
} `xml:"fabric"`
FanSpeed string `xml:"fan_speed"`
FbMemoryUsage struct {
Free string `xml:"free"`
Reserved string `xml:"reserved"`
Total string `xml:"total"`
Used string `xml:"used"`
} `xml:"fb_memory_usage"`
FbcStats struct {
AverageFps string `xml:"average_fps"`
AverageLatency string `xml:"average_latency"`
SessionCount string `xml:"session_count"`
} `xml:"fbc_stats"`
GpuFruPartNumber string `xml:"gpu_fru_part_number"`
GpuModuleID string `xml:"gpu_module_id"`
GpuOperationMode struct {
CurrentGom string `xml:"current_gom"`
PendingGom string `xml:"pending_gom"`
} `xml:"gpu_operation_mode"`
GpuPartNumber string `xml:"gpu_part_number"`
GpuPowerReadings struct {
CurrentPowerLimit string `xml:"current_power_limit"`
DefaultPowerLimit string `xml:"default_power_limit"`
MaxPowerLimit string `xml:"max_power_limit"`
MinPowerLimit string `xml:"min_power_limit"`
PowerDraw string `xml:"power_draw"`
PowerState string `xml:"power_state"`
RequestedPowerLimit string `xml:"requested_power_limit"`
} `xml:"gpu_power_readings"`
GpuResetStatus struct {
DrainAndResetRecommended string `xml:"drain_and_reset_recommended"`
ResetRequired string `xml:"reset_required"`
} `xml:"gpu_reset_status"`
GpuVirtualizationMode struct {
HostVgpuMode string `xml:"host_vgpu_mode"`
VirtualizationMode string `xml:"virtualization_mode"`
} `xml:"gpu_virtualization_mode"`
GspFirmwareVersion string `xml:"gsp_firmware_version"`
Ibmnpu struct {
RelaxedOrderingMode string `xml:"relaxed_ordering_mode"`
} `xml:"ibmnpu"`
InforomVersion struct {
EccObject string `xml:"ecc_object"`
ImgVersion string `xml:"img_version"`
OemObject string `xml:"oem_object"`
PwrObject string `xml:"pwr_object"`
} `xml:"inforom_version"`
MaxClocks struct {
GraphicsClock string `xml:"graphics_clock"`
MemClock string `xml:"mem_clock"`
SmClock string `xml:"sm_clock"`
VideoClock string `xml:"video_clock"`
} `xml:"max_clocks"`
MaxCustomerBoostClocks struct {
GraphicsClock string `xml:"graphics_clock"`
} `xml:"max_customer_boost_clocks"`
MigDevices struct {
MigDevice []struct {
Index string `xml:"index"`
GpuInstanceID string `xml:"gpu_instance_id"`
ComputeInstanceID string `xml:"compute_instance_id"`
EccErrorCount struct {
Text string `xml:",chardata" json:"text"`
VolatileCount struct {
SramUncorrectable string `xml:"sram_uncorrectable"`
} `xml:"volatile_count" json:"volatile_count"`
} `xml:"ecc_error_count" json:"ecc_error_count"`
FbMemoryUsage struct {
Total string `xml:"total"`
Reserved string `xml:"reserved"`
Used string `xml:"used"`
Free string `xml:"free"`
} `xml:"fb_memory_usage" json:"fb_memory_usage"`
Bar1MemoryUsage struct {
Total string `xml:"total"`
Used string `xml:"used"`
Free string `xml:"free"`
} `xml:"bar1_memory_usage" json:"bar1_memory_usage"`
} `xml:"mig_device" json:"mig_device"`
} `xml:"mig_devices" json:"mig_devices"`
MigMode struct {
CurrentMig string `xml:"current_mig"`
PendingMig string `xml:"pending_mig"`
} `xml:"mig_mode"`
MinorNumber string `xml:"minor_number"`
ModulePowerReadings struct {
CurrentPowerLimit string `xml:"current_power_limit"`
DefaultPowerLimit string `xml:"default_power_limit"`
MaxPowerLimit string `xml:"max_power_limit"`
MinPowerLimit string `xml:"min_power_limit"`
PowerDraw string `xml:"power_draw"`
PowerState string `xml:"power_state"`
RequestedPowerLimit string `xml:"requested_power_limit"`
} `xml:"module_power_readings"`
MultigpuBoard string `xml:"multigpu_board"`
Pci struct {
AtomicCapsInbound string `xml:"atomic_caps_inbound"`
AtomicCapsOutbound string `xml:"atomic_caps_outbound"`
PciBridgeChip struct {
BridgeChipFw string `xml:"bridge_chip_fw"`
BridgeChipType string `xml:"bridge_chip_type"`
} `xml:"pci_bridge_chip"`
PciBus string `xml:"pci_bus"`
PciBusID string `xml:"pci_bus_id"`
PciDevice string `xml:"pci_device"`
PciDeviceID string `xml:"pci_device_id"`
PciDomain string `xml:"pci_domain"`
PciGpuLinkInfo struct {
LinkWidths struct {
CurrentLinkWidth string `xml:"current_link_width"`
MaxLinkWidth string `xml:"max_link_width"`
} `xml:"link_widths"`
PcieGen struct {
CurrentLinkGen string `xml:"current_link_gen"`
DeviceCurrentLinkGen string `xml:"device_current_link_gen"`
MaxDeviceLinkGen string `xml:"max_device_link_gen"`
MaxHostLinkGen string `xml:"max_host_link_gen"`
MaxLinkGen string `xml:"max_link_gen"`
} `xml:"pcie_gen"`
} `xml:"pci_gpu_link_info"`
PciSubSystemID string `xml:"pci_sub_system_id"`
ReplayCounter string `xml:"replay_counter"`
ReplayRolloverCounter string `xml:"replay_rollover_counter"`
RxUtil string `xml:"rx_util"`
TxUtil string `xml:"tx_util"`
} `xml:"pci"`
PerformanceState string `xml:"performance_state"`
PersistenceMode string `xml:"persistence_mode"`
PowerReadings struct {
PowerState string `xml:"power_state"`
PowerManagement string `xml:"power_management"`
PowerDraw string `xml:"power_draw"`
PowerLimit string `xml:"power_limit"`
DefaultPowerLimit string `xml:"default_power_limit"`
EnforcedPowerLimit string `xml:"enforced_power_limit"`
MinPowerLimit string `xml:"min_power_limit"`
MaxPowerLimit string `xml:"max_power_limit"`
} `xml:"power_readings"`
Processes struct {
ProcessInfo []struct {
Pid string `xml:"pid"`
Type string `xml:"type"`
ProcessName string `xml:"process_name"`
UsedMemory string `xml:"used_memory"`
} `xml:"process_info"`
} `xml:"processes"`
ProductArchitecture string `xml:"product_architecture"`
ProductBrand string `xml:"product_brand"`
ProductName string `xml:"product_name"`
RemappedRows struct {
// Manually added
Correctable string `xml:"remapped_row_corr"`
Uncorrectable string `xml:"remapped_row_unc"`
Pending string `xml:"remapped_row_pending"`
Failure string `xml:"remapped_row_failure"`
} `xml:"remapped_rows"`
RetiredPages struct {
DoubleBitRetirement struct {
RetiredCount string `xml:"retired_count"`
RetiredPagelist string `xml:"retired_pagelist"`
} `xml:"double_bit_retirement"`
MultipleSingleBitRetirement struct {
RetiredCount string `xml:"retired_count"`
RetiredPagelist string `xml:"retired_pagelist"`
} `xml:"multiple_single_bit_retirement"`
PendingBlacklist string `xml:"pending_blacklist"`
PendingRetirement string `xml:"pending_retirement"`
} `xml:"retired_pages"`
Serial string `xml:"serial"`
SupportedClocks struct {
SupportedMemClock []struct {
SupportedGraphicsClock []string `xml:"supported_graphics_clock"`
Value string `xml:"value"`
} `xml:"supported_mem_clock"`
} `xml:"supported_clocks"`
SupportedGpuTargetTemp struct {
GpuTargetTempMax string `xml:"gpu_target_temp_max"`
GpuTargetTempMin string `xml:"gpu_target_temp_min"`
} `xml:"supported_gpu_target_temp"`
Temperature struct {
GpuTargetTemperature string `xml:"gpu_target_temperature"`
GpuTemp string `xml:"gpu_temp"`
GpuTempMaxGpuThreshold string `xml:"gpu_temp_max_gpu_threshold"`
GpuTempMaxMemThreshold string `xml:"gpu_temp_max_mem_threshold"`
GpuTempMaxThreshold string `xml:"gpu_temp_max_threshold"`
GpuTempSlowThreshold string `xml:"gpu_temp_slow_threshold"`
GpuTempTlimit string `xml:"gpu_temp_tlimit"`
MemoryTemp string `xml:"memory_temp"`
} `xml:"temperature"`
Utilization struct {
DecoderUtil string `xml:"decoder_util"`
EncoderUtil string `xml:"encoder_util"`
GpuUtil string `xml:"gpu_util"`
JpegUtil string `xml:"jpeg_util"`
MemoryUtil string `xml:"memory_util"`
OfaUtil string `xml:"ofa_util"`
} `xml:"utilization"`
UUID string `xml:"uuid"`
VbiosVersion string `xml:"vbios_version"`
Voltage struct {
GraphicsVolt string `xml:"graphics_volt"`
} `xml:"voltage"`
} `xml:"gpu"`
Timestamp string `xml:"timestamp"`
}
+43
View File
@@ -0,0 +1,43 @@
package xpu
type DeviceUtilByProc struct {
DeviceID int `json:"device_id"`
MemSize float64 `json:"mem_size"`
ProcessID int `json:"process_id"`
ProcessName string `json:"process_name"`
SharedMemSize float64 `json:"shared_mem_size"`
}
type DeviceUtilByProcList struct {
DeviceUtilByProcList []DeviceUtilByProc `json:"device_util_by_proc_list"`
}
type Device struct {
DeviceFunctionType string `json:"device_function_type"`
DeviceID int `json:"device_id"`
DeviceName string `json:"device_name"`
DeviceType string `json:"device_type"`
DrmDevice string `json:"drm_device"`
PciBdfAddress string `json:"pci_bdf_address"`
PciDeviceID string `json:"pci_device_id"`
UUID string `json:"uuid"`
VendorName string `json:"vendor_name"`
MemoryPhysicalSizeByte string `json:"memory_physical_size_byte"`
MemoryFreeSizeByte string `json:"memory_free_size_byte"`
DriverVersion string `json:"driver_version"`
}
type DeviceInfo struct {
DeviceList []Device `json:"device_list"`
}
type DeviceLevelMetric struct {
MetricsType string `json:"metrics_type"`
Value float64 `json:"value"`
}
type DeviceStats struct {
DeviceID int `json:"device_id"`
DeviceLevel []DeviceLevelMetric `json:"device_level"`
}
+256
View File
@@ -0,0 +1,256 @@
package xpu
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
)
type XpuSMI struct{}
func New() (bool, XpuSMI) {
return cmd.Which("xpu-smi"), XpuSMI{}
}
func (x XpuSMI) loadDeviceData(device Device, wg *sync.WaitGroup, res *[]XPUSimpleInfo, mu *sync.Mutex) {
defer wg.Done()
var xpu XPUSimpleInfo
xpu.DeviceID = device.DeviceID
xpu.DeviceName = device.DeviceName
var xpuData, statsData string
var xpuErr, statsErr error
var wgCmd sync.WaitGroup
wgCmd.Add(2)
go func() {
defer wgCmd.Done()
xpuData, xpuErr = cmd.ExecWithTimeOut(fmt.Sprintf("xpu-smi discovery -d %d -j", device.DeviceID), 5*time.Second)
}()
go func() {
defer wgCmd.Done()
statsData, statsErr = cmd.ExecWithTimeOut(fmt.Sprintf("xpu-smi stats -d %d -j", device.DeviceID), 5*time.Second)
}()
wgCmd.Wait()
if xpuErr != nil {
global.LOG.Errorf("calling xpu-smi discovery failed for device %d, err: %v\n", device.DeviceID, xpuErr)
return
}
var info Device
if err := json.Unmarshal([]byte(xpuData), &info); err != nil {
global.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err)
return
}
bytes, err := strconv.ParseInt(info.MemoryPhysicalSizeByte, 10, 64)
if err != nil {
global.LOG.Errorf("Error parsing memory size for device %d, err: %v\n", device.DeviceID, err)
return
}
xpu.Memory = fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
if statsErr != nil {
global.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v\n", device.DeviceID, statsErr)
return
}
var stats DeviceStats
if err := json.Unmarshal([]byte(statsData), &stats); err != nil {
global.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err)
return
}
for _, stat := range stats.DeviceLevel {
switch stat.MetricsType {
case "XPUM_STATS_POWER":
xpu.Power = fmt.Sprintf("%.1fW", stat.Value)
case "XPUM_STATS_GPU_CORE_TEMPERATURE":
xpu.Temperature = fmt.Sprintf("%.1f°C", stat.Value)
case "XPUM_STATS_MEMORY_USED":
xpu.MemoryUsed = fmt.Sprintf("%.1fMB", stat.Value)
case "XPUM_STATS_MEMORY_UTILIZATION":
xpu.MemoryUtil = fmt.Sprintf("%.1f%%", stat.Value)
}
}
mu.Lock()
*res = append(*res, xpu)
mu.Unlock()
}
func (x XpuSMI) LoadDashData() ([]XPUSimpleInfo, error) {
data, err := cmd.ExecWithTimeOut("xpu-smi discovery -j", 5*time.Second)
if err != nil {
return nil, fmt.Errorf("calling xpu-smi failed, err: %w", err)
}
var deviceInfo DeviceInfo
if err := json.Unmarshal([]byte(data), &deviceInfo); err != nil {
return nil, fmt.Errorf("deviceInfo json unmarshal failed, err: %w", err)
}
var res []XPUSimpleInfo
var wg sync.WaitGroup
var mu sync.Mutex
for _, device := range deviceInfo.DeviceList {
wg.Add(1)
go x.loadDeviceData(device, &wg, &res, &mu)
}
wg.Wait()
sort.Slice(res, func(i, j int) bool {
return res[i].DeviceID < res[j].DeviceID
})
return res, nil
}
func (x XpuSMI) LoadGpuInfo() (*XpuInfo, error) {
data, err := cmd.ExecWithTimeOut("xpu-smi discovery -j", 5*time.Second)
if err != nil {
return nil, fmt.Errorf("calling xpu-smi failed, err: %w", err)
}
var deviceInfo DeviceInfo
if err := json.Unmarshal([]byte(data), &deviceInfo); err != nil {
return nil, fmt.Errorf("deviceInfo json unmarshal failed, err: %w", err)
}
res := &XpuInfo{
Type: "xpu",
}
var wg sync.WaitGroup
var mu sync.Mutex
for _, device := range deviceInfo.DeviceList {
wg.Add(1)
go x.loadDeviceInfo(device, &wg, res, &mu)
}
wg.Wait()
processData, err := cmd.ExecWithTimeOut("xpu-smi ps -j", 5*time.Second)
if err != nil {
return nil, fmt.Errorf("calling xpu-smi ps failed, err: %w", err)
}
var psList DeviceUtilByProcList
if err := json.Unmarshal([]byte(processData), &psList); err != nil {
return nil, fmt.Errorf("processData json unmarshal failed, err: %w", err)
}
for _, ps := range psList.DeviceUtilByProcList {
process := Process{
PID: ps.ProcessID,
Command: ps.ProcessName,
}
if ps.SharedMemSize > 0 {
process.SHR = fmt.Sprintf("%.1f MB", ps.SharedMemSize/1024)
}
if ps.MemSize > 0 {
process.Memory = fmt.Sprintf("%.1f MB", ps.MemSize/1024)
}
for index, xpu := range res.Xpu {
if xpu.Basic.DeviceID == ps.DeviceID {
res.Xpu[index].Processes = append(res.Xpu[index].Processes, process)
}
}
}
return res, nil
}
func (x XpuSMI) loadDeviceInfo(device Device, wg *sync.WaitGroup, res *XpuInfo, mu *sync.Mutex) {
defer wg.Done()
xpu := Xpu{
Basic: Basic{
DeviceID: device.DeviceID,
DeviceName: device.DeviceName,
VendorName: device.VendorName,
PciBdfAddress: device.PciBdfAddress,
},
}
var xpuData, statsData string
var xpuErr, statsErr error
var wgCmd sync.WaitGroup
wgCmd.Add(2)
go func() {
defer wgCmd.Done()
xpuData, xpuErr = cmd.ExecWithTimeOut(fmt.Sprintf("xpu-smi discovery -d %d -j", device.DeviceID), 5*time.Second)
}()
go func() {
defer wgCmd.Done()
statsData, statsErr = cmd.ExecWithTimeOut(fmt.Sprintf("xpu-smi stats -d %d -j", device.DeviceID), 5*time.Second)
}()
wgCmd.Wait()
if xpuErr != nil {
global.LOG.Errorf("calling xpu-smi discovery failed for device %d, err: %v\n", device.DeviceID, xpuErr)
return
}
var info Device
if err := json.Unmarshal([]byte(xpuData), &info); err != nil {
global.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err)
return
}
res.DriverVersion = info.DriverVersion
xpu.Basic.DriverVersion = info.DriverVersion
bytes, err := strconv.ParseInt(info.MemoryPhysicalSizeByte, 10, 64)
if err != nil {
global.LOG.Errorf("Error parsing memory size for device %d, err: %v\n", device.DeviceID, err)
return
}
xpu.Basic.Memory = fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
xpu.Basic.FreeMemory = info.MemoryFreeSizeByte
if statsErr != nil {
global.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v\n", device.DeviceID, statsErr)
return
}
var stats DeviceStats
if err := json.Unmarshal([]byte(statsData), &stats); err != nil {
global.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err)
return
}
for _, stat := range stats.DeviceLevel {
switch stat.MetricsType {
case "XPUM_STATS_POWER":
xpu.Stats.Power = fmt.Sprintf("%.1fW", stat.Value)
case "XPUM_STATS_GPU_FREQUENCY":
xpu.Stats.Frequency = fmt.Sprintf("%.1fMHz", stat.Value)
case "XPUM_STATS_GPU_CORE_TEMPERATURE":
xpu.Stats.Temperature = fmt.Sprintf("%.1f°C", stat.Value)
case "XPUM_STATS_MEMORY_USED":
xpu.Stats.MemoryUsed = fmt.Sprintf("%.1fMB", stat.Value)
case "XPUM_STATS_MEMORY_UTILIZATION":
xpu.Stats.MemoryUtil = fmt.Sprintf("%.1f%%", stat.Value)
}
}
mu.Lock()
res.Xpu = append(res.Xpu, xpu)
mu.Unlock()
}
+49
View File
@@ -0,0 +1,49 @@
package xpu
type XpuInfo struct {
Type string `json:"type"`
DriverVersion string `json:"driverVersion"`
Xpu []Xpu `json:"xpu"`
}
type Xpu struct {
Basic Basic `json:"basic"`
Stats Stats `json:"stats"`
Processes []Process `json:"processes"`
}
type Basic struct {
DeviceID int `json:"deviceID"`
DeviceName string `json:"deviceName"`
VendorName string `json:"vendorName"`
DriverVersion string `json:"driverVersion"`
Memory string `json:"memory"`
FreeMemory string `json:"freeMemory"`
PciBdfAddress string `json:"pciBdfAddress"`
}
type Stats struct {
Power string `json:"power"`
Frequency string `json:"frequency"`
Temperature string `json:"temperature"`
MemoryUsed string `json:"memoryUsed"`
MemoryUtil string `json:"memoryUtil"`
}
type Process struct {
PID int `json:"pid"`
Command string `json:"command"`
SHR string `json:"shr"`
Memory string `json:"memory"`
}
type XPUSimpleInfo struct {
DeviceID int `json:"deviceID"`
DeviceName string `json:"deviceName"`
Memory string `json:"memory"`
Temperature string `json:"temperature"`
MemoryUsed string `json:"memoryUsed"`
Power string `json:"power"`
MemoryUtil string `json:"memoryUtil"`
}
+20
View File
@@ -3,6 +3,7 @@ package common
import (
"crypto/rand"
"fmt"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/gin-gonic/gin"
"io"
mathRand "math/rand"
@@ -351,3 +352,22 @@ func GetLang(c *gin.Context) string {
}
return lang
}
func HandleIPList(content string) ([]string, error) {
ipList := strings.Split(content, "\n")
var res []string
for _, ip := range ipList {
if ip == "" {
continue
}
if net.ParseIP(ip) != nil {
res = append(res, ip)
continue
}
if _, _, err := net.ParseCIDR(ip); err != nil {
return nil, buserr.New("ErrParseIP")
}
res = append(res, ip)
}
return res, nil
}
+3 -3
View File
@@ -133,10 +133,10 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort string, save
// 非本机转发, 按公网流程走
if err := iptables.runf(NatTab, fmt.Sprintf(
"-A %s -p %s -d %s --dport %s -j MASQUERADE",
"-A %s -d %s -p %s --dport %s -j MASQUERADE",
PostRoutingChain,
protocol,
dest,
protocol,
destPort,
)); err != nil {
return err
@@ -192,7 +192,7 @@ func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPor
// 删除公网转发规则
if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
if err := iptables.runf(NatTab, fmt.Sprintf(
"-D %s -p %s -d %s --dport %s -j MASQUERADE",
"-D %s -d %s -p %s --dport %s -j MASQUERADE",
PostRoutingChain,
dest,
protocol,
+74
View File
@@ -265,6 +265,53 @@ func (s *Server) UpdateRootProxy(proxy []string) {
s.UpdateDirectiveBySecondKey("location", "/", newDir)
}
func (s *Server) UpdateRootProxyForAi(proxy []string) {
newDir := Directive{
Name: "location",
Parameters: []string{"/"},
Block: &Block{},
}
block := &Block{}
block.Directives = []IDirective{
&Directive{
Name: "proxy_buffering",
Parameters: []string{
"off",
},
},
&Directive{
Name: "proxy_cache",
Parameters: []string{
"off",
},
},
&Directive{
Name: "proxy_http_version",
Parameters: []string{
"1.1",
},
},
&Directive{
Name: "proxy_set_header",
Parameters: []string{
"Connection", "''",
},
},
&Directive{
Name: "chunked_transfer_encoding",
Parameters: []string{
"off",
},
},
}
block.Directives = append(block.Directives, &Directive{
Name: "proxy_pass",
Parameters: proxy,
})
newDir.Block = block
s.UpdateDirectiveBySecondKey("location", "/", newDir)
}
func (s *Server) UpdatePHPProxy(proxy []string, localPath string) {
newDir := Directive{
Name: "location",
@@ -369,3 +416,30 @@ func (s *Server) AddHTTP2HTTPS() {
newDir.Block = block
s.UpdateDirectiveBySecondKey("if", "($scheme", newDir)
}
func (s *Server) UpdateAllowIPs(ips []string) {
index := -1
for i, directive := range s.Directives {
if directive.GetName() == "location" && directive.GetParameters()[0] == "/" {
index = i
break
}
}
ipDirectives := make([]IDirective, 0)
for _, ip := range ips {
ipDirectives = append(ipDirectives, &Directive{
Name: "allow",
Parameters: []string{ip},
})
}
ipDirectives = append(ipDirectives, &Directive{
Name: "deny",
Parameters: []string{"all"},
})
if index != -1 {
newDirectives := append(ipDirectives, s.Directives[index:]...)
s.Directives = append(s.Directives[:index], newDirectives...)
} else {
s.Directives = append(s.Directives, ipDirectives...)
}
}
-8
View File
@@ -29,14 +29,6 @@ func LoadRequestTransport() *http.Transport {
}
}
func LoadGpuInfo() []interface{} {
return nil
}
func LoadXpuInfo() []interface{} {
return nil
}
func StartClam(startClam model.Clam, isUpdate bool) (int, error) {
return 0, buserr.New(constant.ErrXpackNotFound)
}
+2 -2
View File
@@ -18,11 +18,11 @@ if [ ! -f "install.sh" ]; then
fi
if [ ! -f "GeoIP.mmdb" ]; then
wget https://resource.1panel.hk/geo/GeoIP.mmdb
wget https://resource.1panel.pro/geo/GeoIP.mmdb
fi
if [ ! -f "lang.tar.gz" ]; then
wget https://resource.1panel.hk/language/lang.tar.gz
wget https://resource.1panel.pro/language/lang.tar.gz
tar zxvf lang.tar.gz
rm -rf lang.tar.gz
fi
+2 -2
View File
@@ -2,8 +2,8 @@ system:
db_file: 1Panel.db
base_dir: /opt
mode: dev
repo_url: https://resource.1panel.hk
app_repo: https://apps.1panel.hk
repo_url: https://resource.1panel.pro
app_repo: https://apps.1panel.pro
is_demo: false
is_intl: true
port: 9999
+587 -28
View File
@@ -20,6 +20,398 @@ const docTemplate = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/ai/domain/bind": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Bind domain",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomain"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/ai/domain/get": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Get bind domain",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomainReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomainRes"
}
}
}
}
},
"/ai/gpu/load": {
"get": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Load gpu / xpu info",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/ai/ollama/model": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Create Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "add Ollama model [name]",
"formatZH": "添加 Ollama 模型 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/close": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Close Ollama model conn",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "close conn for Ollama model [name]",
"formatZH": "关闭 Ollama 模型连接 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/del": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Delete Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ForceDelete"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "ollama_models",
"input_column": "id",
"input_value": "ids",
"isList": true,
"output_column": "name",
"output_value": "names"
}
],
"bodyKeys": [
"ids"
],
"formatEN": "remove Ollama model [names]",
"formatZH": "删除 Ollama 模型 [names]",
"paramKeys": []
}
}
},
"/ai/ollama/model/load": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Page Ollama models",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/ai/ollama/model/recreate": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Rereate Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "re-add Ollama model [name]",
"formatZH": "添加 Ollama 模型重试 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/search": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Page Ollama models",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.PageResult"
}
}
}
}
},
"/ai/ollama/model/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"tags": [
"AI"
],
"summary": "Sync Ollama model list",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.OllamaModelDropList"
}
}
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "sync Ollama model list",
"formatZH": "同步 Ollama 模型列表",
"paramKeys": []
}
}
},
"/apps/checkupdate": {
"get": {
"security": [
@@ -6024,6 +6416,47 @@ const docTemplate = `{
}
}
},
"/files/batch/check": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"File"
],
"summary": "Batch check file exist",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.FilePathsCheck"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.ExistFileInfo"
}
}
}
}
}
},
"/files/batch/del": {
"post": {
"security": [
@@ -16759,6 +17192,9 @@ const docTemplate = `{
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"key": {
"type": "string"
},
@@ -18929,6 +19365,20 @@ const docTemplate = `{
}
}
},
"dto.ForceDelete": {
"type": "object",
"properties": {
"forceDelete": {
"type": "boolean"
},
"ids": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"dto.ForwardRuleOperate": {
"type": "object",
"properties": {
@@ -19564,6 +20014,9 @@ const docTemplate = `{
"ja": {
"type": "string"
},
"ko": {
"type": "string"
},
"ms": {
"type": "string"
},
@@ -20217,6 +20670,83 @@ const docTemplate = `{
"ProxyCache"
]
},
"dto.OllamaBindDomain": {
"type": "object",
"required": [
"appInstallID",
"domain"
],
"properties": {
"appInstallID": {
"type": "integer"
},
"domain": {
"type": "string"
},
"ipList": {
"type": "string"
},
"sslID": {
"type": "integer"
},
"websiteID": {
"type": "integer"
}
}
},
"dto.OllamaBindDomainReq": {
"type": "object",
"required": [
"appInstallID"
],
"properties": {
"appInstallID": {
"type": "integer"
}
}
},
"dto.OllamaBindDomainRes": {
"type": "object",
"properties": {
"allowIPs": {
"type": "array",
"items": {
"type": "string"
}
},
"connUrl": {
"type": "string"
},
"domain": {
"type": "string"
},
"sslID": {
"type": "integer"
},
"websiteID": {
"type": "integer"
}
}
},
"dto.OllamaModelDropList": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"dto.OllamaModelName": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"dto.OneDriveInfo": {
"type": "object",
"properties": {
@@ -22010,6 +22540,9 @@ const docTemplate = `{
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -22210,32 +22743,6 @@ const docTemplate = `{
}
}
},
"model.Tag": {
"type": "object",
"properties": {
"createdAt": {
"type": "string"
},
"id": {
"type": "integer"
},
"key": {
"type": "string"
},
"name": {
"type": "string"
},
"sort": {
"type": "integer"
},
"translations": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
}
},
"model.Website": {
"type": "object",
"properties": {
@@ -22535,6 +23042,9 @@ const docTemplate = `{
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -22698,6 +23208,9 @@ const docTemplate = `{
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -23046,6 +23559,20 @@ const docTemplate = `{
}
}
},
"request.FilePathsCheck": {
"type": "object",
"required": [
"paths"
],
"properties": {
"paths": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"request.FileReadByLineReq": {
"type": "object",
"required": [
@@ -23264,6 +23791,9 @@ const docTemplate = `{
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -24883,6 +25413,9 @@ const docTemplate = `{
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -24921,6 +25454,9 @@ const docTemplate = `{
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -24966,7 +25502,7 @@ const docTemplate = `{
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Tag"
"$ref": "#/definitions/response.TagDTO"
}
},
"type": {
@@ -25007,6 +25543,9 @@ const docTemplate = `{
"enable": {
"type": "boolean"
},
"gpuSupport": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -25087,6 +25626,9 @@ const docTemplate = `{
"description": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -25242,6 +25784,23 @@ const docTemplate = `{
}
}
},
"response.ExistFileInfo": {
"type": "object",
"properties": {
"modTime": {
"type": "string"
},
"name": {
"type": "string"
},
"path": {
"type": "string"
},
"size": {
"type": "number"
}
}
},
"response.FileInfo": {
"type": "object",
"properties": {
@@ -26162,7 +26721,7 @@ const docTemplate = `{
},
"securityDefinitions": {
"ApiKeyAuth": {
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n` + "`" + `` + "`" + `` + "`" + `\neg:\ncurl -X GET \"http://localhost:4004/api/v1/dashboard/current\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n` + "`" + `` + "`" + `` + "`" + `\n- ` + "`" + `1Panel-Token` + "`" + ` is the key for the panel API Key.",
"description": "- ` + "`" + `1Panel-Token` + "`" + ` is the key for the panel API Key.",
"type": "apiKey",
"name": "1Panel-Token",
"in": "header"
+587 -28
View File
@@ -17,6 +17,398 @@
},
"basePath": "/api/v1",
"paths": {
"/ai/domain/bind": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Bind domain",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomain"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/ai/domain/get": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Get bind domain",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomainReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.OllamaBindDomainRes"
}
}
}
}
},
"/ai/gpu/load": {
"get": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Load gpu / xpu info",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/ai/ollama/model": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Create Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "add Ollama model [name]",
"formatZH": "添加 Ollama 模型 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/close": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Close Ollama model conn",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "close conn for Ollama model [name]",
"formatZH": "关闭 Ollama 模型连接 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/del": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Delete Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ForceDelete"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "ollama_models",
"input_column": "id",
"input_value": "ids",
"isList": true,
"output_column": "name",
"output_value": "names"
}
],
"bodyKeys": [
"ids"
],
"formatEN": "remove Ollama model [names]",
"formatZH": "删除 Ollama 模型 [names]",
"paramKeys": []
}
}
},
"/ai/ollama/model/load": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Page Ollama models",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/ai/ollama/model/recreate": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Rereate Ollama model",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OllamaModelName"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [
"name"
],
"formatEN": "re-add Ollama model [name]",
"formatZH": "添加 Ollama 模型重试 [name]",
"paramKeys": []
}
}
},
"/ai/ollama/model/search": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"AI"
],
"summary": "Page Ollama models",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.PageResult"
}
}
}
}
},
"/ai/ollama/model/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"tags": [
"AI"
],
"summary": "Sync Ollama model list",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.OllamaModelDropList"
}
}
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "sync Ollama model list",
"formatZH": "同步 Ollama 模型列表",
"paramKeys": []
}
}
},
"/apps/checkupdate": {
"get": {
"security": [
@@ -6021,6 +6413,47 @@
}
}
},
"/files/batch/check": {
"post": {
"security": [
{
"ApiKeyAuth": []
},
{
"Timestamp": []
}
],
"consumes": [
"application/json"
],
"tags": [
"File"
],
"summary": "Batch check file exist",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.FilePathsCheck"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.ExistFileInfo"
}
}
}
}
}
},
"/files/batch/del": {
"post": {
"security": [
@@ -16756,6 +17189,9 @@
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"key": {
"type": "string"
},
@@ -18926,6 +19362,20 @@
}
}
},
"dto.ForceDelete": {
"type": "object",
"properties": {
"forceDelete": {
"type": "boolean"
},
"ids": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"dto.ForwardRuleOperate": {
"type": "object",
"properties": {
@@ -19561,6 +20011,9 @@
"ja": {
"type": "string"
},
"ko": {
"type": "string"
},
"ms": {
"type": "string"
},
@@ -20214,6 +20667,83 @@
"ProxyCache"
]
},
"dto.OllamaBindDomain": {
"type": "object",
"required": [
"appInstallID",
"domain"
],
"properties": {
"appInstallID": {
"type": "integer"
},
"domain": {
"type": "string"
},
"ipList": {
"type": "string"
},
"sslID": {
"type": "integer"
},
"websiteID": {
"type": "integer"
}
}
},
"dto.OllamaBindDomainReq": {
"type": "object",
"required": [
"appInstallID"
],
"properties": {
"appInstallID": {
"type": "integer"
}
}
},
"dto.OllamaBindDomainRes": {
"type": "object",
"properties": {
"allowIPs": {
"type": "array",
"items": {
"type": "string"
}
},
"connUrl": {
"type": "string"
},
"domain": {
"type": "string"
},
"sslID": {
"type": "integer"
},
"websiteID": {
"type": "integer"
}
}
},
"dto.OllamaModelDropList": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"dto.OllamaModelName": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"dto.OneDriveInfo": {
"type": "object",
"properties": {
@@ -22007,6 +22537,9 @@
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -22207,32 +22740,6 @@
}
}
},
"model.Tag": {
"type": "object",
"properties": {
"createdAt": {
"type": "string"
},
"id": {
"type": "integer"
},
"key": {
"type": "string"
},
"name": {
"type": "string"
},
"sort": {
"type": "integer"
},
"translations": {
"type": "string"
},
"updatedAt": {
"type": "string"
}
}
},
"model.Website": {
"type": "object",
"properties": {
@@ -22532,6 +23039,9 @@
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -22695,6 +23205,9 @@
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -23043,6 +23556,20 @@
}
}
},
"request.FilePathsCheck": {
"type": "object",
"required": [
"paths"
],
"properties": {
"paths": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"request.FileReadByLineReq": {
"type": "object",
"required": [
@@ -23261,6 +23788,9 @@
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -24880,6 +25410,9 @@
"editCompose": {
"type": "boolean"
},
"gpuConfig": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -24918,6 +25451,9 @@
"github": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -24963,7 +25499,7 @@
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Tag"
"$ref": "#/definitions/response.TagDTO"
}
},
"type": {
@@ -25004,6 +25540,9 @@
"enable": {
"type": "boolean"
},
"gpuSupport": {
"type": "boolean"
},
"hostMode": {
"type": "boolean"
},
@@ -25084,6 +25623,9 @@
"description": {
"type": "string"
},
"gpuSupport": {
"type": "boolean"
},
"icon": {
"type": "string"
},
@@ -25239,6 +25781,23 @@
}
}
},
"response.ExistFileInfo": {
"type": "object",
"properties": {
"modTime": {
"type": "string"
},
"name": {
"type": "string"
},
"path": {
"type": "string"
},
"size": {
"type": "number"
}
}
},
"response.FileInfo": {
"type": "object",
"properties": {
@@ -26159,7 +26718,7 @@
},
"securityDefinitions": {
"ApiKeyAuth": {
"description": "Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).\n```\neg:\ncurl -X GET \"http://localhost:4004/api/v1/dashboard/current\" \\\n-H \"1Panel-Token: \u003c1panel_token\u003e\" \\\n-H \"1Panel-Timestamp: \u003ccurrent_unix_timestamp\u003e\"\n```\n- `1Panel-Token` is the key for the panel API Key.",
"description": "- `1Panel-Token` is the key for the panel API Key.",
"type": "apiKey",
"name": "1Panel-Token",
"in": "header"
+359 -27
View File
@@ -108,6 +108,8 @@ definitions:
type: string
github:
type: string
gpuSupport:
type: boolean
key:
type: string
limit:
@@ -1565,6 +1567,15 @@ definitions:
- type
- vars
type: object
dto.ForceDelete:
properties:
forceDelete:
type: boolean
ids:
items:
type: integer
type: array
type: object
dto.ForwardRuleOperate:
properties:
rules:
@@ -1991,6 +2002,8 @@ definitions:
type: string
ja:
type: string
ko:
type: string
ms:
type: string
pt-br:
@@ -2442,6 +2455,56 @@ definitions:
- CACHE
- HttpPer
- ProxyCache
dto.OllamaBindDomain:
properties:
appInstallID:
type: integer
domain:
type: string
ipList:
type: string
sslID:
type: integer
websiteID:
type: integer
required:
- appInstallID
- domain
type: object
dto.OllamaBindDomainReq:
properties:
appInstallID:
type: integer
required:
- appInstallID
type: object
dto.OllamaBindDomainRes:
properties:
allowIPs:
items:
type: string
type: array
connUrl:
type: string
domain:
type: string
sslID:
type: integer
websiteID:
type: integer
type: object
dto.OllamaModelDropList:
properties:
id:
type: integer
name:
type: string
type: object
dto.OllamaModelName:
properties:
name:
type: string
type: object
dto.OneDriveInfo:
properties:
client_id:
@@ -3646,6 +3709,8 @@ definitions:
type: string
github:
type: string
gpuSupport:
type: boolean
icon:
type: string
id:
@@ -3778,23 +3843,6 @@ definitions:
workDir:
type: string
type: object
model.Tag:
properties:
createdAt:
type: string
id:
type: integer
key:
type: string
name:
type: string
sort:
type: integer
translations:
type: string
updatedAt:
type: string
type: object
model.Website:
properties:
IPV6:
@@ -3990,6 +4038,8 @@ definitions:
type: string
editCompose:
type: boolean
gpuConfig:
type: boolean
hostMode:
type: boolean
memoryLimit:
@@ -4099,6 +4149,8 @@ definitions:
type: string
editCompose:
type: boolean
gpuConfig:
type: boolean
hostMode:
type: boolean
installId:
@@ -4332,6 +4384,15 @@ definitions:
required:
- path
type: object
request.FilePathsCheck:
properties:
paths:
items:
type: string
type: array
required:
- paths
type: object
request.FileReadByLineReq:
properties:
ID:
@@ -4479,6 +4540,8 @@ definitions:
type: string
editCompose:
type: boolean
gpuConfig:
type: boolean
hostMode:
type: boolean
memoryLimit:
@@ -5573,6 +5636,8 @@ definitions:
type: string
editCompose:
type: boolean
gpuConfig:
type: boolean
hostMode:
type: boolean
memoryLimit:
@@ -5598,6 +5663,8 @@ definitions:
type: string
github:
type: string
gpuSupport:
type: boolean
icon:
type: string
id:
@@ -5628,7 +5695,7 @@ definitions:
type: string
tags:
items:
$ref: '#/definitions/model.Tag'
$ref: '#/definitions/response.TagDTO'
type: array
type:
type: string
@@ -5655,6 +5722,8 @@ definitions:
type: string
enable:
type: boolean
gpuSupport:
type: boolean
hostMode:
type: boolean
id:
@@ -5708,6 +5777,8 @@ definitions:
properties:
description:
type: string
gpuSupport:
type: boolean
icon:
type: string
id:
@@ -5810,6 +5881,17 @@ definitions:
required:
- size
type: object
response.ExistFileInfo:
properties:
modTime:
type: string
name:
type: string
path:
type: string
size:
type: number
type: object
response.FileInfo:
properties:
content:
@@ -6421,6 +6503,240 @@ info:
title: 1Panel
version: "1.0"
paths:
/ai/domain/bind:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaBindDomain'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Bind domain
tags:
- AI
/ai/domain/get:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaBindDomainReq'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dto.OllamaBindDomainRes'
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Get bind domain
tags:
- AI
/ai/gpu/load:
get:
consumes:
- application/json
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Load gpu / xpu info
tags:
- AI
/ai/ollama/model:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaModelName'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Create Ollama model
tags:
- AI
x-panel-log:
BeforeFunctions: []
bodyKeys:
- name
formatEN: add Ollama model [name]
formatZH: 添加 Ollama 模型 [name]
paramKeys: []
/ai/ollama/model/close:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaModelName'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Close Ollama model conn
tags:
- AI
x-panel-log:
BeforeFunctions: []
bodyKeys:
- name
formatEN: close conn for Ollama model [name]
formatZH: 关闭 Ollama 模型连接 [name]
paramKeys: []
/ai/ollama/model/del:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.ForceDelete'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Delete Ollama model
tags:
- AI
x-panel-log:
BeforeFunctions:
- db: ollama_models
input_column: id
input_value: ids
isList: true
output_column: name
output_value: names
bodyKeys:
- ids
formatEN: remove Ollama model [names]
formatZH: 删除 Ollama 模型 [names]
paramKeys: []
/ai/ollama/model/load:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaModelName'
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Page Ollama models
tags:
- AI
/ai/ollama/model/recreate:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OllamaModelName'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Rereate Ollama model
tags:
- AI
x-panel-log:
BeforeFunctions: []
bodyKeys:
- name
formatEN: re-add Ollama model [name]
formatZH: 添加 Ollama 模型重试 [name]
paramKeys: []
/ai/ollama/model/search:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.SearchWithPage'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dto.PageResult'
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Page Ollama models
tags:
- AI
/ai/ollama/model/sync:
post:
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/dto.OllamaModelDropList'
type: array
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Sync Ollama model list
tags:
- AI
x-panel-log:
BeforeFunctions: []
bodyKeys: []
formatEN: sync Ollama model list
formatZH: 同步 Ollama 模型列表
paramKeys: []
/apps/{key}:
get:
consumes:
@@ -10045,6 +10361,30 @@ paths:
formatEN: Create dir or file [path]
formatZH: 创建文件/文件夹 [path]
paramKeys: []
/files/batch/check:
post:
consumes:
- application/json
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.FilePathsCheck'
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/response.ExistFileInfo'
type: array
security:
- ApiKeyAuth: []
- Timestamp: []
summary: Batch check file exist
tags:
- File
/files/batch/del:
post:
consumes:
@@ -16422,15 +16762,7 @@ schemes:
- https
securityDefinitions:
ApiKeyAuth:
description: |-
Custom Token Format, Format: md5('1panel' + API-Key + UnixTimestamp).
```
eg:
curl -X GET "http://localhost:4004/api/v1/dashboard/current" \
-H "1Panel-Token: <1panel_token>" \
-H "1Panel-Timestamp: <current_unix_timestamp>"
```
- `1Panel-Token` is the key for the panel API Key.
description: '- `1Panel-Token` is the key for the panel API Key.'
in: header
name: 1Panel-Token
type: apiKey
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>أفضل أداة إدارة خوادم لينكس عبر الويب بتقييم عالٍ</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -46,14 +46,14 @@
أعد تشغيل البرنامج النصي أدناه واتبع التعليمات التي تظهر لتثبيت 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
يرجى الرجوع إلى مستنداتنا [هنا](https://docs.1panel.hk/quick_start/) لمزيد من التفاصيل.
يرجى الرجوع إلى مستنداتنا [هنا](https://docs.1panel.pro/quick_start/) لمزيد من التفاصيل.
## مقاطع شاشة
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## تاريخ النجوم
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Hochbewertetes Web-basiertes Linux-Server-Management-Tool</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Führen Sie das folgende Skript aus und befolgen Sie die Anweisungen, um 1Panel zu installieren:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Bitte verweisen Sie auf unsere [Dokumentation](https://docs.1panel.hk/quick_start/) für weitere Informationen.
Bitte verweisen Sie auf unsere [Dokumentation](https://docs.1panel.pro/quick_start/) für weitere Informationen.
## Bildschirmfoto
![Benutzeroberflächenanzeige](https://resource.1panel.hk/img/1panel.png)
![Benutzeroberflächenanzeige](https://resource.1panel.pro/img/1panel.png)
## Sternverlauf
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Herramienta de gestión de servidores Linux basada en la web mejor valorada</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Ejecute el script a continuación y siga las indicaciones para instalar 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Por favor, consulte nuestra [dokumentasi](https://docs.1panel.hk/quick_start/) para más detalles.
Por favor, consulte nuestra [dokumentasi](https://docs.1panel.pro/quick_start/) para más detalles.
## Captura de Pantalla
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Historial de Estrellas
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Outil de gestion de serveurs Linux basé sur le web le mieux noté</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Exécutez le script ci-dessous et suivez les instructions pour installer 1Panel :
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Veuillez vous référer à notre [documentation](https://docs.1panel.hk/quick_start/) pour plus d'informations.
Veuillez vous référer à notre [documentation](https://docs.1panel.pro/quick_start/) pour plus d'informations.
## Capture d'écran
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Histoire des étoiles
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Alat Manajemen Server Linux Berbasis Web dengan Peringkat Teratas</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Jalankan skrip di bawah ini dan ikuti petunjuk untuk menginstal 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Silakan merujuk ke [dokumentasi](https://docs.1panel.hk/quick_start/) kami untuk informasi lebih lanjut.
Silakan merujuk ke [dokumentasi](https://docs.1panel.pro/quick_start/) kami untuk informasi lebih lanjut.
## Tangkapan Layar
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Star History
+2 -2
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>最高評価のWebベースのLinuxサーバー管理ツール</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,7 +45,7 @@
ワンクリックで 1Panel をインストールするには、次のコマンドを実行します:
```sh
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
## UI ディスプレイ
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>최고 평점의 웹 기반 리눅스 서버 관리 도구</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
아래 스크립트를 실행하고 프롬프트에 따라 1Panel을 설치하세요:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
자세한 내용은 [문서](https://docs.1panel.hk/quick_start/)를 참조하세요.
자세한 내용은 [문서](https://docs.1panel.pro/quick_start/)를 참조하세요.
## 스크린샷
![UI 디스플레이](https://resource.1panel.hk/img/1panel.png)
![UI 디스플레이](https://resource.1panel.pro/img/1panel.png)
## 스타 히스토리
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Alat Pengurusan Pelayan Linux Berasaskan Web Terbaik</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Jalankan skrip di bawah dan ikuti arahan untuk memasang 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Sila rujuk [dokumentasi](https://docs.1panel.hk/quick_start/) untuk maklumat lanjut.
Sila rujuk [dokumentasi](https://docs.1panel.pro/quick_start/) untuk maklumat lanjut.
## Tangkap Layar
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Sejarah Bintang
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Ferramenta de Gerenciamento de Servidores Linux Baseada na Web Mais Avaliada</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Execute o script abaixo e siga as instruções para instalar o 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Por favor, consulte nossa [documentação](https://docs.1panel.hk/quick_start/) para mais detalhes.
Por favor, consulte nossa [documentação](https://docs.1panel.pro/quick_start/) para mais detalhes.
## Captura de Tela
![Exibição da UI](https://resource.1panel.hk/img/1panel.png)
![Exibição da UI](https://resource.1panel.pro/img/1panel.png)
## Histórico de Estrelas
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Высококлассная веб-панель управления Linux-серверами</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,14 +45,14 @@
Выполните скрипт ниже и следуйте инструкциям для установки 1Panel:
```bash
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Для получения дополнительной информации обратитесь к нашей [документации](https://docs.1panel.hk/quick_start/).
Для получения дополнительной информации обратитесь к нашей [документации](https://docs.1panel.pro/quick_start/).
## Скриншот
![Интерфейс](https://resource.1panel.hk/img/1panel.png)
![Интерфейс](https://resource.1panel.pro/img/1panel.png)
## История звезд
+4 -4
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>En Yüksek Puanlı Web Tabanlı Linux Sunucu Yönetim Aracı</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -47,14 +47,14 @@
Aşağıdaki komutu çalıştırın ve 1Panel’i kurmak için yönergeleri takip edin:
```sh
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
Daha fazla detay için [dokümantasyonumuza](https://docs.1panel.hk/quick_start/) göz atın.
Daha fazla detay için [dokümantasyonumuza](https://docs.1panel.pro/quick_start/) göz atın.
## Ekran Görüntüsü
![UI Display](https://resource.1panel.hk/img/1panel.png)
![UI Display](https://resource.1panel.pro/img/1panel.png)
## Yıldız Geçmişi
+3 -3
View File
@@ -1,4 +1,4 @@
<p align="center"><a href="https://1panel.hk"><img src="https://resource.1panel.hk/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>評分最高的基於網頁的 Linux 伺服器管理工具</b></p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
@@ -45,12 +45,12 @@
執行如下命令一鍵安裝 1Panel:
```sh
curl -sSL https://resource.1panel.hk/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
## UI 展示
![UI展示](https://resource.1panel.hk/img/1panel.png)
![UI展示](https://resource.1panel.pro/img/1panel.png)
## Star History
+111
View File
@@ -0,0 +1,111 @@
import { ReqPage } from '.';
export namespace AI {
export interface OllamaModelInfo {
id: number;
name: string;
size: string;
from: string;
logFileExist: boolean;
status: string;
message: string;
createdAt: Date;
}
export interface OllamaModelDropInfo {
id: number;
name: string;
}
export interface OllamaModelSearch extends ReqPage {
info: string;
}
export interface Info {
cudaVersion: string;
driverVersion: string;
type: string;
gpu: GPU[];
}
export interface GPU {
index: number;
productName: string;
persistenceMode: string;
busID: string;
displayActive: string;
ecc: string;
fanSpeed: string;
temperature: string;
performanceState: string;
powerDraw: string;
maxPowerLimit: string;
memUsed: string;
memTotal: string;
gpuUtil: string;
computeMode: string;
migMode: string;
processes: Process[];
}
export interface Process {
pid: string;
type: string;
processName: string;
usedMemory: string;
}
export interface XpuInfo {
type: string;
driverVersion: string;
xpu: Xpu[];
}
interface Xpu {
basic: Basic;
stats: Stats;
processes: XpuProcess[];
}
interface Basic {
deviceID: number;
deviceName: string;
vendorName: string;
driverVersion: string;
memory: string;
freeMemory: string;
pciBdfAddress: string;
}
interface Stats {
power: string;
frequency: string;
temperature: string;
memoryUsed: string;
memoryUtil: string;
}
interface XpuProcess {
pid: number;
command: string;
shr: string;
memory: string;
}
export interface BindDomain {
domain: string;
sslID: number;
ipList: string;
appInstallID: number;
websiteID?: number;
}
export interface BindDomainReq {
appInstallID: number;
}
export interface BindDomainRes {
domain: string;
sslID: number;
allowIPs: string[];
websiteID?: number;
connUrl: string;
}
}
+3
View File
@@ -14,6 +14,7 @@ export namespace App {
type: string;
status: string;
limit: number;
gpuSupport: boolean;
}
export interface AppDTO extends App {
@@ -46,6 +47,7 @@ export namespace App {
dockerCompose: string;
image: string;
hostMode?: boolean;
gpuSupport: boolean;
}
export interface AppReq extends ReqPage {
@@ -240,6 +242,7 @@ export namespace App {
allowPort: boolean;
dockerCompose: string;
hostMode?: boolean;
gpuConfig?: boolean;
}
export interface IgnoredApp {
+8
View File
@@ -152,6 +152,14 @@ export namespace File {
path: string;
}
export interface ExistFileInfo {
name: string;
path: string;
size: number;
uploadSize: number;
modTime: string;
}
export interface RecycleBin {
sourcePath: string;
name: string;
+41
View File
@@ -0,0 +1,41 @@
import { AI } from '@/api/interface/ai';
import http from '@/api';
import { ResPage } from '../interface';
export const createOllamaModel = (name: string) => {
return http.post(`/ai/ollama/model`, { name: name });
};
export const recreateOllamaModel = (name: string) => {
return http.post(`/ai/ollama/model/recreate`, { name: name });
};
export const deleteOllamaModel = (ids: Array<number>, force: boolean) => {
return http.post(`/ai/ollama/model/del`, { ids: ids, forceDelete: force });
};
export const searchOllamaModel = (params: AI.OllamaModelSearch) => {
return http.post<ResPage<AI.OllamaModelInfo>>(`/ai/ollama/model/search`, params);
};
export const loadOllamaModel = (name: string) => {
return http.post<string>(`/ai/ollama/model/load`, { name: name });
};
export const syncOllamaModel = () => {
return http.post<Array<AI.OllamaModelDropInfo>>(`/ai/ollama/model/sync`);
};
export const closeOllamaModel = (name: string) => {
return http.post(`/ai/ollama/close`, { name: name });
};
export const loadGPUInfo = () => {
return http.get<any>(`/ai/gpu/load`);
};
export const bindDomain = (req: AI.BindDomain) => {
return http.post(`/ai/domain/bind`, req);
};
export const getBindDomain = (req: AI.BindDomainReq) => {
return http.post<AI.BindDomainRes>(`/ai/domain/get`, req);
};
export const updateBindDomain = (req: AI.BindDomain) => {
return http.post(`/ai/domain/update`, req);
};
+4
View File
@@ -53,6 +53,10 @@ export const CheckFile = (path: string) => {
return http.post<boolean>('files/check', { path: path });
};
export const BatchCheckFiles = (paths: string[]) => {
return http.post<File.ExistFileInfo[]>('files/batch/check', { paths: paths }, TimeoutEnum.T_5M);
};
export const UploadFileData = (params: FormData, config: AxiosRequestConfig) => {
return http.upload<File.File>('files/upload', params, config);
};
+21 -9
View File
@@ -1,9 +1,9 @@
@font-face {
font-family: "panel"; /* Project id 3575356 */
src: url('iconfont.woff2?t=1732681110788') format('woff2'),
url('iconfont.woff?t=1732681110788') format('woff'),
url('iconfont.ttf?t=1732681110788') format('truetype'),
url('iconfont.svg?t=1732681110788#panel') format('svg');
src: url('iconfont.woff2?t=1739946811686') format('woff2'),
url('iconfont.woff?t=1739946811686') format('woff'),
url('iconfont.ttf?t=1739946811686') format('truetype'),
url('iconfont.svg?t=1739946811686#panel') format('svg');
}
.panel {
@@ -14,6 +14,22 @@
-moz-osx-font-smoothing: grayscale;
}
.p-app-3:before {
content: "\e69e";
}
.p-app-2:before {
content: "\e6ec";
}
.p-app-1:before {
content: "\e639";
}
.p-jiqiren2:before {
content: "\e613";
}
.p-alert-3:before {
content: "\e728";
}
@@ -170,12 +186,8 @@
content: "\e604";
}
.p-gpu-2:before {
content: "\e6d8";
}
.p-gpu-1:before {
content: "\e623";
content: "\e63d";
}
.p-monitor-4:before {
File diff suppressed because one or more lines are too long
+32 -11
View File
@@ -5,6 +5,34 @@
"css_prefix_text": "p-",
"description": "",
"glyphs": [
{
"icon_id": "10593804",
"name": "过程监控_jurassic",
"font_class": "app-3",
"unicode": "e69e",
"unicode_decimal": 59038
},
{
"icon_id": "26508547",
"name": "服务信息",
"font_class": "app-2",
"unicode": "e6ec",
"unicode_decimal": 59116
},
{
"icon_id": "28544760",
"name": "移动管理-01",
"font_class": "app-1",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "10505865",
"name": "机器人",
"font_class": "jiqiren2",
"unicode": "e613",
"unicode_decimal": 58899
},
{
"icon_id": "4472516",
"name": "告警设置",
@@ -279,18 +307,11 @@
"unicode_decimal": 58884
},
{
"icon_id": "640495",
"name": "详细信息",
"font_class": "gpu-2",
"unicode": "e6d8",
"unicode_decimal": 59096
},
{
"icon_id": "6176565",
"name": "监控",
"icon_id": "24848551",
"name": "系统监控",
"font_class": "gpu-1",
"unicode": "e623",
"unicode_decimal": 58915
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "40398413",
+9 -3
View File
@@ -14,6 +14,14 @@
/>
<missing-glyph />
<glyph glyph-name="app-3" unicode="&#59038;" d="M872.8 800H151.2C103.1 800 64 760.8 64 712.6v-445.1c0-48.2 39.1-87.4 87.2-87.4h721.6c48.1 0 87.2 39.2 87.2 87.4V712.6c0 48.2-39.1 87.4-87.2 87.4z m-721.6-63.6h721.6c13.1 0 23.8-10.7 23.8-23.8v-246.4H696.2L569.9 672 369.6 399.6l-66.5 66.6H127.4V712.6c0 13.1 10.7 23.8 23.8 23.8z m721.6-492.8H151.2c-13.1 0-23.8 10.7-23.8 23.8V402.6h149.4l100-100.3L565 558.4l95.6-155.8h235.8v-135.1c0.2-13.2-10.5-23.9-23.6-23.9zM179 31.6h666.1V-32H179z" horiz-adv-x="1024" />
<glyph glyph-name="app-2" unicode="&#59116;" d="M544-64H211.2c-44.8 0-83.2 38.4-83.2 83.2V748.8C128 793.6 166.4 832 211.2 832h608c38.4 0 76.8-38.4 76.8-83.2v-403.2c0-19.2-12.8-32-32-32s-32 12.8-32 32V748.8c0 12.8-12.8 25.6-19.2 25.6H211.2c-12.8 0-19.2-12.8-19.2-25.6v-729.6c0-12.8 6.4-25.6 19.2-25.6h339.2c19.2 0 32-12.8 32-32-6.4-12.8-19.2-25.6-38.4-25.6z m198.4 601.6H281.6c-12.8 0-25.6 12.8-25.6 32s12.8 32 32 32h454.4c19.2 0 32-12.8 32-32s-19.2-32-32-32zM537.6 377.6h-256c-12.8 0-25.6 12.8-25.6 32s12.8 32 32 32h256c19.2 0 32-12.8 32-32-6.4-19.2-25.6-32-38.4-32zM652.8 256h108.8c12.8 0 19.2-6.4 19.2-19.2V128c0-12.8-6.4-19.2-19.2-19.2h-108.8c-12.8 0-19.2 6.4-19.2 19.2v108.8c0 6.4 12.8 19.2 19.2 19.2zM652.8 83.2h108.8c12.8 0 19.2-6.4 19.2-19.2v-108.8c0-12.8-6.4-19.2-19.2-19.2h-108.8c-12.8 0-19.2 6.4-19.2 19.2V64c0 12.8 12.8 19.2 19.2 19.2zM825.6 256h108.8c12.8 0 19.2-6.4 19.2-19.2V128c0-12.8-6.4-19.2-19.2-19.2h-108.8c-12.8 0-19.2 6.4-19.2 19.2v108.8c0 6.4 6.4 19.2 19.2 19.2zM825.6 83.2h108.8c12.8 0 19.2-6.4 19.2-19.2v-108.8c0-12.8-6.4-19.2-19.2-19.2h-108.8c-12.8 0-19.2 6.4-19.2 19.2V64c0 12.8 6.4 19.2 19.2 19.2zM288 281.6h102.4c19.2 0 32-12.8 32-32s-12.8-32-32-32H288c-19.2 0-32 12.8-32 32 6.4 19.2 19.2 32 32 32z" horiz-adv-x="1024" />
<glyph glyph-name="app-1" unicode="&#58937;" d="M741.34-53.35H284.17A103.43 103.43 0 0 0 180.87 50V716.39a103.41 103.41 0 0 0 103.3 103.29h457.17a103.39 103.39 0 0 0 103.28-103.29V50a103.41 103.41 0 0 0-103.28-103.35zM284.17 760.82a44.49 44.49 0 0 1-44.45-44.43V50a44.51 44.51 0 0 1 44.45-44.45h457.17A44.49 44.49 0 0 1 785.77 50V716.39a44.47 44.47 0 0 1-44.43 44.43zM601 644.53H424.47a29.43 29.43 0 0 0 0 58.86H601a29.43 29.43 0 1 0 0-58.86zM512.76 63a48.82 48.82 0 1 0 49 48.82 49 49 0 0 0-49-48.82z m0 58.86a10 10 0 1 1 9.81-10 9.94 9.94 0 0 1-9.81 9.96z" horiz-adv-x="1024" />
<glyph glyph-name="jiqiren2" unicode="&#58899;" d="M554.667 533.333h-320V64h554.666V533.333H554.667z m-85.334 85.334V704H448a21.333 21.333 0 0 0-21.333 21.333V810.667A21.333 21.333 0 0 0 448 832h128a21.333 21.333 0 0 0 21.333-21.333v-85.334A21.333 21.333 0 0 0 576 704h-21.333v-85.333H832A42.667 42.667 0 0 0 874.667 576v-554.667A42.667 42.667 0 0 0 832-21.333H192a42.667 42.667 0 0 0-42.667 42.666V576A42.667 42.667 0 0 0 192 618.667h277.333zM21.333 384H64a21.333 21.333 0 0 0 21.333-21.333v-128A21.333 21.333 0 0 0 64 213.333H21.333A21.333 21.333 0 0 0 0 234.667v128A21.333 21.333 0 0 0 21.333 384zM320 362.667h128v-128H320v128z m256 0h128v-128H576v128zM960 384h42.667A21.333 21.333 0 0 0 1024 362.667v-128a21.333 21.333 0 0 0-21.333-21.334H960a21.333 21.333 0 0 0-21.333 21.334v128A21.333 21.333 0 0 0 960 384z" horiz-adv-x="1024" />
<glyph glyph-name="alert-3" unicode="&#59176;" d="M334.506667 364.495238a97.562819 97.562819 0 1 0 0 39.009524H863.085714a19.504762 19.504762 0 1 0 0-39.009524H334.506667z m354.986666-273.066666H160.914286a19.504762 19.504762 0 1 0 0 39.009523h528.579047a97.523809 97.523809 0 1 0 0-39.009523z m0 546.133333H160.914286a19.504762 19.504762 0 0 0 0 39.009523h528.579047a97.523809 97.523809 0 1 0 0-39.009523zM843.580953 657.066667a58.514286 58.514286 0 1 1-117.028572 0 58.514286 58.514286 0 0 1 117.028572 0z m0-546.133334a58.514286 58.514286 0 1 1-117.028572 0 58.514286 58.514286 0 0 1 117.028572 0z m-546.133334 273.066667a58.514286 58.514286 0 1 1-117.028572 0 58.514286 58.514286 0 0 1 117.028572 0z" horiz-adv-x="1024" />
<glyph glyph-name="tongyijiancha" unicode="&#58905;" d="M464 704a270.95 270.95 0 1 0-105.85-21.35A270.24 270.24 0 0 0 464 704m0 64c-185.57 0-336-150.43-336-336s150.43-336 336-336 336 150.43 336 336-150.43 336-336 336zM710.63 230.63l-45.26-45.26L850.75 0 896 45.25 710.63 230.63zM604.97 569.94L419.6 384.57l-96.57 96.57-45.26-45.26 96.57-96.57 45.26-45.25 45.25 45.25 185.38 185.38-45.26 45.25z" horiz-adv-x="1024" />
@@ -92,9 +100,7 @@
<glyph glyph-name="xpack" unicode="&#58884;" d="M971.527 503.922L839.149 726.406c-5.729 11.652-17.836 20.114-32.248 20.114H217.227v-0.442c-12.134 0-24.007-5.962-30.647-17.394L54.201 506.903c-10.077-14.177-8.931-33.836 3.645-46.178l428.043-428.499 1.133-0.456c13.943-13.722 36.362-13.722 50.306 0l428.707 428.955h-0.222c11.43 11.431 14.412 29.267 5.714 43.197zM760.032 674.968l-85.743-140.632a47.989 47.989 0 0 1-3.789 0.164c-2.771 0-5.48-0.25-8.12-0.706l-98.988 141.174h196.64z m-132.05-166.793c-0.136-0.271-0.273-0.541-0.404-0.815H401.421a47.213 47.213 0 0 1-2.563 4.683l113.537 161.311 115.587-165.179zM460.736 674.968l-98.403-140.636a48.105 48.105 0 0 1-3.833 0.167c-2.775 0-5.49-0.251-8.135-0.708l-86.504 141.176h196.875z m-234.605-19.45l89.842-147.361c-0.132-0.265-0.267-0.528-0.394-0.796h-178.16l88.712 148.157zM154.799 464.37h161.928c6.511-11.994 18.04-20.861 31.767-23.805l98.051-267.719L154.799 464.37z m357.597-345.475L390.021 451.478a47.675 47.675 0 0 1 10.252 12.892h228.454a47.625 47.625 0 0 1 6.843-9.55L512.396 118.89499999999998z m64.939 53.951l97.977 266.896c15.992 1.609 29.644 11.149 36.962 24.628h156.364L577.335 172.846zM713.422 507.36a47.323 47.323 0 0 1-2.727 4.938l87.756 143.22 88.022-148.158H713.422z" horiz-adv-x="1024" />
<glyph glyph-name="gpu-2" unicode="&#59096;" d="M392.585795 223.71443399999998l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 223.71443399999998 392.585795 223.71443399999998zM392.585795 103.84434599999997l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 103.84434599999997 392.585795 103.84434599999997zM392.585795 330.26312199999995l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 330.26312199999995 392.585795 330.26312199999995zM473.523175 304.65181399999994c0-14.145162 11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308s-11.466146 25.611308-25.611308 25.611308l-226.416729 0C484.990345 330.26312199999995 473.523175 318.796976 473.523175 304.65181399999994zM852.245729 471.110987c-54.019311 71.51887-226.167043 271.164886-294.330492 347.954807-2.820232 3.175319-6.088672 5.656837-9.639544 7.385201l-2.437515 2.849908-9.704013 0c-0.049119 0-0.097214 0.004093-0.146333 0.004093-0.039909 0-0.079818-0.004093-0.12075-0.004093L213.635123 829.300902c-15.878642 0-32.363082-6.886851-45.228087-18.896372-13.467733-12.571317-21.190625-29.167297-21.190625-45.533033L147.216411 5.710303999999951c0-16.116049 7.467065-32.885991 20.48659-46.007847 13.072737-13.175067 29.815049-20.732184 45.933145-20.732184l602.350774 0c16.676821 0 33.07428 8.121981 44.989657 22.281469 10.622942 12.624529 16.714683 28.828582 16.714683 44.457538L877.691261 441.366545 852.245729 471.110987zM559.654858 734.350366l239.987816-280.545534L563.927161 453.804832c-2.067079 3.163039-4.272303 9.214872-4.272303 13.115716L559.654858 734.350366zM826.467623 5.710303999999951c0-7.726985-7.185656-15.516392-10.480702-15.516392L213.635123-9.806087000000048c-5.396917 0-15.196097 10.005888-15.196097 15.516392L198.439026 764.87252c0 4.66423 8.933463 13.205766 15.196097 13.205766l294.79712 0 0-311.158762c0-26.295899 18.24555-64.339354 51.235918-64.339354l266.799462 0L826.467623 5.710303999999951zM430.875866 634.92696L297.690518 634.92696c-14.145162 0-25.611308-11.467169-25.611308-25.611308l0-133.186372c0-14.145162 11.467169-25.612331 25.611308-25.612331l133.185348 0c14.145162 0 25.611308 11.467169 25.611308 25.612331L456.487174 609.314629C456.487174 623.45979 445.021028 634.92696 430.875866 634.92696zM405.264559 501.739565l-81.962733 0 0 81.963757 81.962733 0L405.264559 501.739565zM725.551212 223.71443399999998l-226.416729 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S739.697397 223.71443399999998 725.551212 223.71443399999998zM725.551212 103.84434599999997l-226.416729 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S739.697397 103.84434599999997 725.551212 103.84434599999997z" horiz-adv-x="1024" />
<glyph glyph-name="gpu-1" unicode="&#58915;" d="M838.22 139.59000000000003H187.78a89.1 89.1 0 0 0-89.1 89.1V697.46a89.1 89.1 0 0 0 89.1 89.1h650.44a89.1 89.1 0 0 0 89.1-89.1v-468.77a89.1 89.1 0 0 0-89.1-89.1zM852 224.64999999999998V701.5a9 9 0 0 1-9 8.95H183a9 9 0 0 1-9-8.95v-476.85a9 9 0 0 1 9-8.94h660a9 9 0 0 1 9 8.94zM287.01 63.48000000000002m37.86 0l376.26 0q37.86 0 37.86-37.86l0-0.39q0-37.86-37.86-37.86l-376.26 0q-37.86 0-37.86 37.86l0 0.39q0 37.86 37.86 37.86ZM249.34 558.22m31.68 0l11.97 0q31.68 0 31.68-31.68l0-203.04q0-31.68-31.68-31.68l-11.97 0q-31.68 0-31.68 31.68l0 203.04q0 31.68 31.68 31.68ZM400 444.05m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-76.89q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 76.89q0 37.67 37.67 37.67ZM550.67 634.3299999999999m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-267.17q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 267.17q0 37.67 37.67 37.67ZM701.33 482.11m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-114.94q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 114.94q0 37.67 37.67 37.67Z" horiz-adv-x="1024" />
<glyph glyph-name="gpu-1" unicode="&#58941;" d="M938.666667 55.893333H85.333333c-11.946667 0-21.333333-9.386667-21.333333-21.333333s9.386667-21.333333 21.333333-21.333333h853.333334c11.946667 0 21.333333 9.386667 21.333333 21.333333s-9.386667 21.333333-21.333333 21.333333zM853.333333 754.773333H170.666667a106.666667 106.666667 0 0 1-106.666667-106.666666v-426.666667a106.666667 106.666667 0 0 1 106.666667-106.666667h682.666666a106.666667 106.666667 0 0 1 106.666667 106.666667v426.666667a106.666667 106.666667 0 0 1-106.666667 106.666666z m-682.666666-42.666666h682.666666c35.413333 0 64-28.586667 64-64v-256h-107.946666l-109.226667 52.48a21.589333 21.589333 0 0 1-24.746667-4.693334l-125.44-135.253333-108.8 308.053333a21.333333 21.333333 0 0 1-17.92 14.08 20.864 20.864 0 0 1-20.48-9.813333L260.266667 392.106667H106.666667v256c0 35.413333 28.586667 64 64 64z m682.666666-554.666667H170.666667c-35.413333 0-64 28.586667-64 64v128h165.12c7.253333 0 14.08 3.84 17.92 9.813333l125.44 197.546667 105.813333-299.946667a20.565333 20.565333 0 0 1 20.053333-14.08c5.973333 0 11.52 2.56 15.786667 6.826667l138.666667 149.333333 99.413333-47.786666c2.986667-1.28 5.973333-2.133333 9.386667-2.133334h112.64v-128c0.426667-34.56-28.16-63.573333-63.573334-63.573333z" horiz-adv-x="1024" />
<glyph glyph-name="monitor-4" unicode="&#60494;" d="M838.22 139.59000000000003H187.78a89.1 89.1 0 0 0-89.1 89.1V697.46a89.1 89.1 0 0 0 89.1 89.1h650.44a89.1 89.1 0 0 0 89.1-89.1v-468.77a89.1 89.1 0 0 0-89.1-89.1zM852 224.64999999999998V701.5a9 9 0 0 1-9 8.95H183a9 9 0 0 1-9-8.95v-476.85a9 9 0 0 1 9-8.94h660a9 9 0 0 1 9 8.94zM287.01 63.48000000000002m37.86 0l376.26 0q37.86 0 37.86-37.86l0-0.39q0-37.86-37.86-37.86l-376.26 0q-37.86 0-37.86 37.86l0 0.39q0 37.86 37.86 37.86ZM249.34 558.22m31.68 0l11.97 0q31.68 0 31.68-31.68l0-203.04q0-31.68-31.68-31.68l-11.97 0q-31.68 0-31.68 31.68l0 203.04q0 31.68 31.68 31.68ZM400 444.05m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-76.89q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 76.89q0 37.67 37.67 37.67ZM550.67 634.3299999999999m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-267.17q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 267.17q0 37.67 37.67 37.67ZM701.33 482.11m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-114.94q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 114.94q0 37.67 37.67 37.67Z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+23 -3
View File
@@ -31,7 +31,7 @@
>
{{ $t('app.restart') }}
</el-button>
<el-divider direction="vertical" />
<el-divider v-if="!hideSetting" direction="vertical" />
<el-button
type="primary"
link
@@ -43,6 +43,7 @@
</el-button>
<el-divider v-if="data.app === 'OpenResty'" direction="vertical" />
<el-button
v-if="!hideSetting"
type="primary"
@click="setting"
link
@@ -64,6 +65,11 @@
>
{{ $t('nginx.clearProxyCache') }}
</el-button>
<el-divider direction="vertical" v-if="slots.extra" />
<span v-if="slots.extra">
<slot name="extra"></slot>
</span>
</div>
<div class="ml-5" v-if="key === 'openresty' && (httpPort != 80 || httpsPort != 443)">
@@ -108,12 +114,13 @@
<script lang="ts" setup>
import { CheckAppInstalled, InstalledOp } from '@/api/modules/app';
import router from '@/routers';
import { onMounted, reactive, ref } from 'vue';
import { onMounted, reactive, ref, useSlots } from 'vue';
import Status from '@/components/status/index.vue';
import { ElMessageBox } from 'element-plus';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { ClearNginxCache } from '@/api/modules/nginx';
const slots = useSlots();
const props = defineProps({
appKey: {
@@ -124,6 +131,10 @@ const props = defineProps({
type: String,
default: '',
},
hideSetting: {
type: Boolean,
default: false,
},
});
let key = ref('');
@@ -146,7 +157,15 @@ let refresh = ref(1);
const httpPort = ref(0);
const httpsPort = ref(0);
const em = defineEmits(['setting', 'isExist', 'before', 'after', 'update:loading', 'update:maskShow']);
const em = defineEmits([
'setting',
'isExist',
'before',
'after',
'update:loading',
'update:maskShow',
'update:appInstallID',
]);
const setting = () => {
em('setting', false);
};
@@ -166,6 +185,7 @@ const onCheck = async (key: any, name: any) => {
em('isExist', res.data);
em('update:maskShow', res.data.status !== 'Running');
operateReq.installId = res.data.appInstallId;
em('update:appInstallID', res.data.appInstallId);
httpPort.value = res.data.httpPort;
httpsPort.value = res.data.httpsPort;
refresh.value++;
@@ -0,0 +1,78 @@
<template>
<div>
<el-dialog
v-model="dialogVisible"
:title="$t('file.existFileTitle')"
width="35%"
:close-on-click-modal="false"
:destroy-on-close="true"
>
<el-alert :show-icon="true" type="warning" :closable="false">
<div class="whitespace-break-spaces">
<span>{{ $t('file.existFileHelper') }}</span>
</div>
</el-alert>
<div>
<el-table :data="existFiles" max-height="350">
<el-table-column type="index" :label="$t('commons.table.serialNumber')" width="55" />
<el-table-column prop="path" :label="$t('commons.table.name')" :min-width="200" />
<el-table-column :label="$t('file.existFileSize')" width="230">
<template #default="{ row }">
{{ getFileSize(row.uploadSize) }} -> {{ getFileSize(row.size) }}
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleSkip">{{ $t('commons.button.skip') }}</el-button>
<el-button type="primary" @click="handleOverwrite()">
{{ $t('commons.button.cover') }}
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { computeSize } from '@/utils/util';
const dialogVisible = ref();
const existFiles = ref<DialogProps[]>([]);
interface DialogProps {
name: string;
path: string;
size: number;
uploadSize: number;
modTime: string;
}
let onConfirmCallback = null;
const getFileSize = (size: number) => {
return computeSize(size);
};
const handleSkip = () => {
dialogVisible.value = false;
if (onConfirmCallback) {
onConfirmCallback(
'skip',
existFiles.value.map((file) => file.path),
);
}
};
const handleOverwrite = () => {
dialogVisible.value = false;
if (onConfirmCallback) {
onConfirmCallback('overwrite');
}
};
const acceptParams = async ({ paths, onConfirm }): Promise<void> => {
existFiles.value = paths;
onConfirmCallback = onConfirm;
dialogVisible.value = true;
};
defineExpose({ acceptParams });
</script>
@@ -77,7 +77,7 @@ const toLxware = () => {
if (!globalStore.isIntl) {
window.open('https://www.lxware.cn/1panel' + '', '_blank', 'noopener,noreferrer');
} else {
window.open('https://1panel.hk/pricing' + '', '_blank', 'noopener,noreferrer');
window.open('https://1panel.pro/pricing' + '', '_blank', 'noopener,noreferrer');
}
};
+6 -3
View File
@@ -72,6 +72,7 @@ const stopSignals = [
'image pull successful!',
'image push failed!',
'image push successful!',
'ollama pull completed!',
];
const emit = defineEmits(['update:loading', 'update:hasContent', 'update:isReading']);
const tailLog = ref(false);
@@ -173,9 +174,11 @@ const getContent = async (pre: boolean) => {
}
if (res.data.lines && res.data.lines.length > 0) {
res.data.lines = res.data.lines.map((line) =>
line.replace(/\\u(\w{4})/g, function (match, grp) {
return String.fromCharCode(parseInt(grp, 16));
}),
line
.replace(/\\u(\w{4})/g, function (match, grp) {
return String.fromCharCode(parseInt(grp, 16));
})
.replace(/\x1B\[[0-?9;]*[mKhlGA]/g, ''),
);
const newLogs = res.data.lines;
if (newLogs.length === readReq.pageSize && readReq.page < res.data.total) {
@@ -126,7 +126,7 @@ const toLxware = () => {
if (!globalStore.isIntl) {
window.open('https://www.lxware.cn/1panel' + '', '_blank', 'noopener,noreferrer');
} else {
window.open('https://1panel.hk/pricing' + '', '_blank', 'noopener,noreferrer');
window.open('https://1panel.pro/pricing' + '', '_blank', 'noopener,noreferrer');
}
};
+1 -1
View File
@@ -422,7 +422,7 @@ const checkDoc = (rule: any, value: any, callback: any) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.nginxDoc')));
} else {
const reg = /^[A-Za-z0-9\n./]+$/;
const reg = /^[A-Za-z0-9_\n./]+$/;
if (!reg.test(value) && value !== '') {
callback(new Error(i18n.global.t('commons.rule.nginxDoc')));
} else {
+81 -5
View File
@@ -15,6 +15,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: 'Run',
create: 'Create ',
add: 'Add ',
save: 'Save ',
@@ -74,6 +75,8 @@ const message = {
createNewFile: 'Create new file',
helpDoc: 'Help Document',
unbind: 'Unbind',
cover: 'cover',
skip: 'skip',
},
search: {
timeStart: 'Time start',
@@ -110,6 +113,7 @@ const message = {
refreshRate: 'Refresh rate',
refreshRateUnit: 'No refresh | {n} second/time | {n} seconds/time',
selectColumn: 'Select column',
serialNumber: 'Serial number',
},
loadingText: {
Upgrading: 'System upgrade, please wait...',
@@ -119,6 +123,8 @@ const message = {
},
msg: {
noneData: 'No data available',
disConn:
'Please click the disconnect button directly to terminate the terminal connection, avoiding the use of exit commands like {0}.',
delete: `This operation delete can't be undone. Do you want to continue?`,
clean: `This operation clean can't be undone. Do you want to continue?`,
deleteTitle: 'Delete',
@@ -222,7 +228,7 @@ const message = {
'This field must consist of English, numbers, ".", "-", and "_" characters with a length of 2-30.',
paramComplexity: `This field mustn't start and end with special characters and must consist of English, numbers, "{0}" characters with a length of 6-128.`,
paramUrlAndPort: 'This field must be in the format of "http(s)://(domain name/ip):(port)".',
nginxDoc: 'This field must consist of English, numbers and "." characters.',
nginxDoc: 'This field must consist of English, numbers, _ and "." characters.',
appName: 'Supports lowercase letters, numbers, -, and _, length 2-30, and cannot start or end with - or _',
containerName: 'Supports letters, numbers, -, _ and .; cannot start with - _ or .; length: 2-128',
mirror: 'The mirror acceleration address should start with http(s)://, support English letters (both uppercase and lowercase), numbers, . / and -, and should not contain blank lines.',
@@ -327,6 +333,7 @@ const message = {
firewall: 'Firewall',
ssl: 'Certificate | Certificates',
database: 'Database | Databases',
ai_tools: 'AI',
container: 'Container | Containers',
cronjob: 'Cron Job | Cron Jobs',
host: 'Host | Hosts',
@@ -589,6 +596,56 @@ const message = {
'This connnection address can be used by applications running on non-container or external applications.',
localIP: 'Local IP',
},
ai_tools: {
model: {
model: 'Model',
create: 'Add Model',
create_helper: 'Pull "{0}"',
ollama_doc: 'You can visit the Ollama official website to search and find more models.',
container_conn_helper: 'Use this address for inter-container access or connection',
ollama_sync: 'Syncing Ollama model found the following models do not exist, do you want to delete them?',
from_remote: 'This model was not downloaded via 1Panel, no related pull logs.',
no_logs: 'The pull logs for this model have been deleted and cannot be viewed.',
},
gpu: {
gpu: 'GPU Monitor',
base: 'Basic Information',
gpuHelper: 'NVIDIA-SMI or XPU-SMI command not detected on the current system. Please check and try again!',
driverVersion: 'Driver Version',
cudaVersion: 'CUDA Version',
process: 'Process Information',
type: 'Type',
typeG: 'Graphics',
typeC: 'Compute',
typeCG: 'Compute + Graphics',
processName: 'Process Name',
processMemoryUsage: 'Memory Usage',
temperatureHelper: 'High GPU temperature can cause GPU frequency throttling',
performanceStateHelper: 'From P0 (maximum performance) to P12 (minimum performance)',
busID: 'Bus ID',
persistenceMode: 'Persistence Mode',
enabled: 'Enabled',
disabled: 'Disabled',
persistenceModeHelper:
'Persistence mode allows quicker task responses but increases standby power consumption.',
displayActive: 'Graphics Card Initialized',
displayActiveT: 'Yes',
displayActiveF: 'No',
ecc: 'Error Correction and Check Technology',
computeMode: 'Compute Mode',
default: 'Default',
exclusiveProcess: 'Exclusive Process',
exclusiveThread: 'Exclusive Thread',
prohibited: 'Prohibited',
defaultHelper: 'Default: Processes can execute concurrently',
exclusiveProcessHelper:
'Exclusive Process: Only one CUDA context can use the GPU, but can be shared by multiple threads',
exclusiveThreadHelper: 'Exclusive Thread: Only one thread in a CUDA context can use the GPU',
prohibitedHelper: 'Prohibited: Processes are not allowed to execute simultaneously',
migModeHelper: 'Used to create MIG instances for physical isolation of the GPU at the user level.',
migModeNA: 'Not Supported',
},
},
container: {
create: 'Create container',
edit: 'Edit container',
@@ -1175,6 +1232,7 @@ const message = {
resource: 'Resource',
operate: 'Operate',
detail: {
ai: 'AI',
groups: 'Group',
hosts: 'Host',
apps: 'App',
@@ -1320,6 +1378,10 @@ const message = {
minimap: 'Code mini map',
fileCanNotRead: 'File can not read',
panelInstallDir: `1Panel installation directory can't be deleted`,
existFileTitle: 'Same name file prompt',
existFileHelper: 'The uploaded file contains a file with the same name, do you want to overwrite it?',
existFileSize: 'File size (new -> old)',
existFileDirHelper: 'The selected file/folder has a duplicate name. Please proceed with caution!',
},
ssh: {
setting: 'Setting',
@@ -1428,8 +1490,9 @@ const message = {
proxyDockerHelper:
'Synchronize proxy server configuration to Docker, support offline server image pulling and other operations',
apiInterface: 'Enable API',
apiInterfaceClose: 'Once closed, API interfaces cannot be accessed. Do you want to continue?',
apiInterfaceHelper: 'Allow third-party applications to access the API.',
apiInterfaceClose:
'API interfaces are unavailable, app functionality will be restricted. Do you want to continue?',
apiInterfaceHelper: 'Supports panel API interface access (this feature needs to be enabled for the panel app)',
apiInterfaceAlert1: `Don't enable it in production environments because it may increase server security risks.`,
apiInterfaceAlert2: `Don't use third-party applications to call the API to prevent potential security threats.`,
apiInterfaceAlert3: 'API Docs',
@@ -1739,16 +1802,16 @@ const message = {
levelUpPro: 'Upgrade to Pro',
licenseSync: 'License Sync',
knowMorePro: 'Learn More',
closeAlert: 'The current page can be closed in the panel settings',
closeAlert: 'The current page can be hidden in the panel settings',
introduce: 'Feature Introduction',
waf: 'Upgrading to the professional version can provide features such as interception map, logs, block records, geographical location blocking, custom rules, custom interception pages, etc.',
tamper: 'Upgrading to the professional version can protect websites from unauthorized modifications or tampering.',
gpu: 'Upgrading to the professional version can help users visually monitor important parameters of GPU such as workload, temperature, memory usage in real time.',
setting:
'Upgrading to the professional version allows customization of panel logo, welcome message, and other information.',
monitor:
'Upgrade to the professional version to view the real-time status of the website, visitor trends, visitor sources, request logs and other information. ',
alert: 'Upgrade to the professional version to receive alarm information via SMS and view alarm logs, fully control various key events, and ensure worry-free system operation',
app: 'Upgrade to the professional version to manage servers and view monitoring features via the mobile app.',
},
clean: {
scan: 'Start scanning',
@@ -1921,6 +1984,8 @@ const message = {
'The left side is the old version, the right side is the new version. After editing, click to save the custom version',
pullImage: 'Pull Image',
pullImageHelper: 'Execute docker pull to pull the image before the application starts',
gpuConfig: 'GPU Acceleration',
gpuConfigHelper: 'Please ensure that the server has NVIDIA drivers and NVIDIA Container Toolkit installed',
},
website: {
website: 'Website | Websites',
@@ -2523,6 +2588,17 @@ const message = {
licenseHelper: 'Professional version supports SMS alert',
alertCountHelper: 'Maximum daily alarm frequency',
},
aitool: {
proxy: 'AI Proxy Enhancement',
proxyHelper1: 'Bind domain and enable HTTPS for enhanced transmission security',
proxyHelper2: 'Limit IP access to prevent exposure on the public internet',
proxyHelper3: 'Enable streaming',
proxyHelper4: 'Once created, you can view and manage it in the website list',
proxyHelper5:
'After enabling, you can disable external access to the port in the App Store - Installed - Ollama - Parameters to improve security.',
proxyHelper6: 'To disable proxy configuration, you can delete it from the website list.',
whiteListHelper: 'Restrict access to only IPs in the whitelist',
},
};
export default {
+88 -11
View File
@@ -14,6 +14,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: '実行',
create: '作成する',
add: '追加',
save: '保存',
@@ -55,7 +56,7 @@ const message = {
refresh: 'リロード',
get: '得る',
upgrade: 'アップグレード',
ignore: 'アップグレードを無視します',
ignore: '更新を無視する',
copy: 'コピー',
random: 'ランダム',
uninstall: 'アンインストール',
@@ -73,6 +74,8 @@ const message = {
createNewFile: '新しいファイルを作成します',
helpDoc: '文書をヘルプします',
unbind: 'バインド',
cover: '上書き',
skip: 'スキップ',
},
search: {
timeStart: '時間開始',
@@ -107,8 +110,9 @@ const message = {
protocol: 'プロトコル',
tableSetting: 'テーブル設定',
refreshRate: 'リフレッシュレート',
refreshRateUnit: '更新なし|{n}秒/時間 |{n}秒/時間',
refreshRateUnit: '更新なし|{n}秒/時 |{n}秒/時',
selectColumn: '列を選択します',
serialNumber: 'シリアル番号',
},
loadingText: {
Upgrading: 'システムのアップグレード、待ってください...',
@@ -118,6 +122,8 @@ const message = {
},
msg: {
noneData: '利用可能なデータはありません',
disConn:
'端末接続を切断するには、{0} のような終了コマンドを使用せずに、直接切断ボタンをクリックしてください',
delete: `この操作削除は元に戻すことはできません。続けたいですか?`,
clean: `この操作は取り消すことはできません。続けたいですか?`,
deleteTitle: '消去',
@@ -221,7 +227,7 @@ const message = {
paramComplexity: `このフィールドは、特殊文字で開始および終了する必要はなく、英語、数字「{0}」文字で構成されている必要があります。`,
paramUrlAndPort:
'このフィールドは、「http(s)://(domain name/ip):(ポート)」の形式でなければなりません。',
nginxDoc: 'このフィールドは、英語、数字、「」で構成されている必要があります。文字。',
nginxDoc: 'このフィールドは、英語、数字、_、「」で構成されている必要があります。文字。',
appName:
'小文字の英字、数字、-および_をサポートし、長さは2〜30で、-または_で始まったり終わったりすることはできません',
containerName: '文字、数字、 - 、_および。;- _または。で始めることはできません。長さ:2-128',
@@ -291,7 +297,7 @@ const message = {
units: {
second: '2番目|2番目|秒',
minute: '分|分|分',
hour: '時間|時間|時間',
hour: '時|時|時',
day: '日|日|日',
week: '週|週|週',
month: '月|月|数ヶ月',
@@ -327,6 +333,7 @@ const message = {
firewall: 'ファイアウォール',
ssl: '証明書|証明書',
database: 'データベース|データベース',
ai_tools: 'AI',
container: 'コンテナ|コンテナ',
cronjob: 'クロンジョブ|クロンの仕事',
host: 'ホスト|ホスト',
@@ -589,6 +596,56 @@ const message = {
'この接続アドレスは、非コンテナまたは外部アプリケーションで実行されているアプリケーションで使用できます。',
localIP: 'ローカルIP',
},
ai_tools: {
model: {
model: 'モデル',
create: 'モデルを追加',
create_helper: 'を取得 "{0}"',
ollama_doc: 'Ollama の公式ウェブサイトを訪れて、さらに多くのモデルを検索して見つけることができます。',
container_conn_helper: 'コンテナ間のアクセスまたは接続にこのアドレスを使用',
ollama_sync: 'Ollamaモデルの同期中に、以下のモデルが存在しないことが判明しました。削除しますか?',
from_remote: 'このモデルは1Panelを介してダウンロードされておらず、関連するプルログはありません。',
no_logs: 'このモデルのプルログは削除されており、関連するログを表示できません。',
},
gpu: {
gpu: 'GPUモニター',
base: '基本情報',
gpuHelper:
'現在のシステムでNVIDIA-SMIまたはXPU-SMIコマンドが検出されませんでした。確認して再試行してください!',
driverVersion: 'ドライバーバージョン',
cudaVersion: 'CUDAバージョン',
process: 'プロセス情報',
type: 'タイプ',
typeG: 'グラフィックス',
typeC: 'コンピュート',
typeCG: 'コンピュート + グラフィックス',
processName: 'プロセス名',
processMemoryUsage: 'メモリ使用量',
temperatureHelper: '高いGPU温度はGPUの周波数制限を引き起こす可能性があります',
performanceStateHelper: 'P0(最大性能)からP12(最小性能)まで',
busID: 'バスID',
persistenceMode: '永続モード',
enabled: '有効',
disabled: '無効',
persistenceModeHelper: '永続モードはタスクの応答速度を速くしますが、待機時の消費電力が増加します。',
displayActive: 'グラフィックカード初期化済み',
displayActiveT: 'はい',
displayActiveF: 'いいえ',
ecc: 'エラー訂正およびチェック技術',
computeMode: 'コンピュートモード',
default: 'デフォルト',
exclusiveProcess: '専用プロセス',
exclusiveThread: '専用スレッド',
prohibited: '禁止',
defaultHelper: 'デフォルト:プロセスは並行して実行できます',
exclusiveProcessHelper:
'専用プロセス:1つのCUDAコンテキストのみがGPUを使用できますが、複数のスレッドで共有できます',
exclusiveThreadHelper: '専用スレッド:CUDAコンテキスト内の1つのスレッドのみがGPUを使用できます',
prohibitedHelper: '禁止:プロセスは同時に実行できません',
migModeHelper: 'ユーザーレベルでGPUの物理的分離を行うためのMIGインスタンスを作成するために使用されます。',
migModeNA: 'サポートされていません',
},
},
container: {
create: 'コンテナを作成します',
edit: 'コンテナを編集します',
@@ -1155,6 +1212,7 @@ const message = {
resource: 'リソース',
operate: '動作します',
detail: {
ai: 'AI',
groups: 'グループ',
hosts: 'ホスト',
apps: 'アプリ',
@@ -1298,6 +1356,10 @@ const message = {
minimap: 'コードミニマップ',
fileCanNotRead: 'ファイルは読み取れません',
panelInstallDir: `1Panelインストールディレクトリは削除できません`,
existFileTitle: '同名ファイルの警告',
existFileHelper: 'アップロードしたファイルに同じ名前のファイルが含まれています。上書きしますか?',
existFileSize: 'ファイルサイズ(新しい -> 古い)',
existFileDirHelper: '選択したファイル/フォルダーには同じ名前のものが既に存在します。慎重に操作してください!',
},
ssh: {
setting: '設定',
@@ -1404,8 +1466,9 @@ const message = {
proxyDockerHelper:
'プロキシサーバーの構成をDockerに同期し、オフラインサーバーイメージの引っ張りやその他の操作をサポートします',
apiInterface: 'APIを有効にします',
apiInterfaceClose: '閉じたら、APIインターフェイスにアクセスできません。続けたいですか?',
apiInterfaceHelper: 'サードパーティのアプリケーションにAPIにアクセスできるようにします。',
apiInterfaceClose: 'APIインターフェースが利用できません。アプリ機能が制限されます。続行しますか?',
apiInterfaceHelper:
'パネルAPIインターフェースアクセスをサポート(この機能はパネルアプリで有効にする必要があります)',
apiInterfaceAlert1: `サーバーのセキュリティリスクが増加する可能性があるため、生産環境で有効にしないでください。`,
apiInterfaceAlert2: `サードパーティのアプリケーションを使用してAPIを呼び出して、潜在的なセキュリティの脅威を防止しないでください。`,
apiInterfaceAlert3: 'APIドキュメント',
@@ -1712,16 +1775,16 @@ const message = {
levelUpPro: 'Proにアップグレードします',
licenseSync: 'ライセンス同期',
knowMorePro: 'もっと詳しく知る',
closeAlert: '現在のページはパネル設定で閉じることができます',
closeAlert: '現在のページはパネル設定で非表示にできます',
introduce: '機能の紹介',
waf: 'プロフェッショナルバージョンにアップグレードすると、インターセプトマップ、ログ、ブロックレコード、地理的位置ブロッキング、カスタムルール、カスタムインターセプトページなどの機能を提供できます。',
tamper: 'プロのバージョンにアップグレードすると、不正な変更や改ざんからWebサイトを保護できます。',
gpu: 'プロのバージョンにアップグレードすることで、ユーザーはワークロード、温度、メモリ使用量などのGPUの重要なパラメーターをリアルタイムで視覚的に監視するのに役立ちます。',
setting:
'プロのバージョンにアップグレードすることで、パネルロゴ、ウェルカムメッセージ、その他の情報のカスタマイズが可能になります。',
monitor:
'プロのバージョンにアップグレードして、Webサイトのリアルタイムステータス、訪問者の傾向、訪問者ソース、リクエストログ、その他の情報を表示します。',
alert: 'プロのバージョンにアップグレードして、SMSを介してアラーム情報を受信し、アラームログを表示し、さまざまなキーイベントを完全に制御し、心配のないシステム操作を確実にする',
alert: 'プロのバージョンにアップグレードして、SMSを介してアラーム情報を受信し、アラームログを表示し、さまざまなキーイベントを完全に制御し、心配のないシステム操作を確実にする。',
app: 'プロ版にアップグレードすると、モバイルアプリを使ってサーバーを管理し、監視機能を確認できます。',
},
clean: {
scan: 'スキャンを開始します',
@@ -1832,7 +1895,7 @@ const message = {
noService: 'いいえ{0}',
toInstall: 'インストールに移動します',
param: 'パラメーター',
alreadyRun: '年',
alreadyRun: 'インストール済み',
syncAppList: '同期',
less1Minute: '1分未満',
appOfficeWebsite: 'オフィスのウェブサイト',
@@ -1863,7 +1926,7 @@ const message = {
upgradeHelper:
'アップグレードする前に、異常なアプリケーションを通常のステータスに戻します。アップグレードが失敗した場合は、「ログ>システムログ」に移動して、障害の理由を確認します。',
installWarn: `外部アクセスは有効になっていないため、アプリケーションが外部ネットワークを介してアクセスできるようになります。続けたいですか?`,
showIgnore: '無視されたアプリケーションを表示します',
showIgnore: '無視したアプリ一覧',
cancelIgnore: 'キャンセルは無視します',
ignoreList: '無視されたアプリケーション',
appHelper:
@@ -1894,6 +1957,9 @@ const message = {
'左側は古いバージョンで、右側は新しいバージョンです。編集後、クリックしてカスタムバージョンを保存します',
pullImage: '画像を引っ張ります',
pullImageHelper: 'アプリケーションが開始する前に、Docker Pullを実行して画像をプルします',
gpuConfig: 'GPU アクセラレーション',
gpuConfigHelper:
'サーバーにNVIDIAドライバーとNVIDIA Container Toolkitがインストールされていることを確認してください',
},
website: {
website: 'ウェブサイト|ウェブサイト',
@@ -2491,6 +2557,17 @@ const message = {
licenseHelper: 'プロのバージョンはSMSアラートをサポートします',
alertCountHelper: '最大毎日のアラーム周波数',
},
aitool: {
proxy: 'AI プロキシ強化',
proxyHelper1: 'ドメインをバインドし、HTTPS を有効にして通信のセキュリティを強化',
proxyHelper2: 'IP アクセスを制限し、パブリックインターネットでの露出を防止',
proxyHelper3: 'ストリーミングを有効にする',
proxyHelper4: '作成後、ウェブサイトリストで確認および管理できます',
proxyHelper5:
'有効にすると、アプリストア - インストール済み - Ollama - パラメータでポートの外部アクセスを無効にし、セキュリティを向上させることができます。',
proxyHelper6: 'プロキシ設定を無効にするには、ウェブサイトリストから削除できます。',
whiteListHelper: 'ホワイトリスト内のIPのみアクセスを許可する',
},
};
export default {
...fit2cloudJaLocale,
+80 -6
View File
@@ -15,6 +15,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: '실행',
create: '생성',
add: '추가',
save: '저장',
@@ -74,6 +75,8 @@ const message = {
createNewFile: '새 파일 생성',
helpDoc: '도움말 문서',
unbind: '연결 해제',
cover: '덮어쓰기',
skip: '건너뛰기',
},
search: {
timeStart: '시작 시간',
@@ -110,6 +113,7 @@ const message = {
refreshRate: '새로 고침 속도',
refreshRateUnit: '새로 고침 안 함 | {n} 초/회 | {n} 초/회',
selectColumn: '열 선택',
serialNumber: '일련 번호',
},
loadingText: {
Upgrading: '시스템 업그레이드 중입니다. 잠시만 기다려 주십시오...',
@@ -119,6 +123,8 @@ const message = {
},
msg: {
noneData: '데이터가 없습니다',
disConn:
'종료 명령어인 {0} 등을 사용하지 않고 직접 연결 끊기 버튼을 클릭하여 터미널 연결을 종료해 주십시오.',
delete: `이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?`,
clean: `이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?`,
deleteTitle: '삭제',
@@ -221,7 +227,7 @@ const message = {
paramComplexity:
'이 필드는 특수 문자로 시작하거나 끝날 수 없으며, 영어, 숫자, "{0}" 문자로 구성되어야 하며 길이는 6-128 자여야 합니다.',
paramUrlAndPort: '이 필드는 "http(s)://(도메인 이름/IP):(포트)" 형식이어야 합니다.',
nginxDoc: '이 필드는 영어, 숫자 및 "." 문자로 구성되어야 합니다.',
nginxDoc: '이 필드는 영어, 숫자 및 _ "." 문자로 구성되어야 합니다.',
appName:
'소문자, 숫자, "-", "_"를 지원하며 길이는 2-30 자이고, "-" 또는 "_"로 시작하거나 끝날 수 없습니다.',
containerName:
@@ -328,6 +334,7 @@ const message = {
firewall: '방화벽',
ssl: '인증서 | 인증서들',
database: '데이터베이스 | 데이터베이스들',
ai_tools: 'AI',
container: '컨테이너 | 컨테이너들',
cronjob: '크론 작업 | 크론 작업들',
host: '호스트 | 호스트들',
@@ -585,6 +592,55 @@ const message = {
'이 연결 주소는 컨테이너 외부 또는 외부 애플리케이션에서 실행 중인 애플리케이션에서 사용할 수 있습니다.',
localIP: '로컬 IP',
},
ai_tools: {
model: {
model: '모델',
create: '모델 추가',
create_helper: '가져오기 "{0}"',
ollama_doc: 'Ollama 공식 웹사이트를 방문하여 더 많은 모델을 검색하고 찾을 수 있습니다.',
container_conn_helper: '컨테이너 간 접근 또는 연결에 이 주소를 사용',
ollama_sync: 'Ollama 모델 동기화 중 다음 모델이 존재하지 않음을 발견했습니다. 삭제하시겠습니까?',
from_remote: '이 모델은 1Panel을 통해 다운로드되지 않았으며 관련 풀 로그가 없습니다.',
no_logs: '이 모델의 풀 로그가 삭제되어 관련 로그를 볼 수 없습니다.',
},
gpu: {
gpu: 'GPU 모니터',
base: '기본 정보',
gpuHelper: '현재 시스템에서 NVIDIA-SMI 또는 XPU-SMI 명령이 감지되지 않았습니다. 확인 후 다시 시도하세요!',
driverVersion: '드라이버 버전',
cudaVersion: 'CUDA 버전',
process: '프로세스 정보',
type: '유형',
typeG: '그래픽',
typeC: '연산',
typeCG: '연산 + 그래픽',
processName: '프로세스 이름',
processMemoryUsage: '메모리 사용량',
temperatureHelper: 'GPU 온도가 높으면 GPU 주파수 제한이 발생할 수 있습니다.',
performanceStateHelper: 'P0(최대 성능)부터 P12(최소 성능)까지',
busID: '버스 ID',
persistenceMode: '지속 모드',
enabled: '활성화됨',
disabled: '비활성화됨',
persistenceModeHelper: '지속 모드는 작업 응답 속도를 빠르게 하지만 대기 전력 소비를 증가시킵니다.',
displayActive: '그래픽 카드 초기화됨',
displayActiveT: '예',
displayActiveF: '아니요',
ecc: '오류 감지 및 수정 기술',
computeMode: '연산 모드',
default: '기본값',
exclusiveProcess: '단독 프로세스',
exclusiveThread: '단독 스레드',
prohibited: '금지됨',
defaultHelper: '기본값: 프로세스가 동시에 실행될 수 있음',
exclusiveProcessHelper:
'단독 프로세스: 하나의 CUDA 컨텍스트만 GPU 를 사용할 수 있지만, 여러 스레드에서 공유 가능',
exclusiveThreadHelper: '단독 스레드: CUDA 컨텍스트의 하나의 스레드만 GPU 를 사용할 수 있음',
prohibitedHelper: '금지됨: 프로세스가 동시에 실행되는 것이 허용되지 않음',
migModeHelper: '사용자 수준에서 GPU 를 물리적으로 분리하는 MIG 인스턴스를 생성하는 데 사용됩니다.',
migModeNA: '지원되지 않음',
},
},
container: {
create: '컨테이너 만들기',
edit: '컨테이너 편집',
@@ -1143,6 +1199,7 @@ const message = {
resource: '자원',
operate: '작업',
detail: {
ai: 'AI',
groups: '그룹',
hosts: '호스트',
apps: '애플리케이션',
@@ -1285,6 +1342,10 @@ const message = {
minimap: '코드 미니맵',
fileCanNotRead: '파일을 읽을 수 없습니다.',
panelInstallDir: `1Panel 설치 디렉터리는 삭제할 수 없습니다.`,
existFileTitle: '동일한 이름의 파일 경고',
existFileHelper: '업로드한 파일에 동일한 이름의 파일이 포함되어 있습니다. 덮어쓰시겠습니까?',
existFileSize: '파일 크기 (새로운 -> 오래된)',
existFileDirHelper: '선택한 파일/폴더에 동일한 이름이 이미 존재합니다. 신중하게 작업하세요!',
},
ssh: {
setting: '설정',
@@ -1387,10 +1448,10 @@ const message = {
proxyDockerHelper:
'프록시 서버 구성을 Docker 에 동기화하여 오프라인 서버 이미지 가져오기 등의 작업을 지원합니다.',
apiInterface: 'API 활성화',
apiInterfaceClose: '비활성화하면 API 인터페이스에 접근할 수 없습니다. 계속하시겠습니까?',
apiInterfaceHelper: '서드파티 애플리케이션이 API 에 접근할 수 있도록 허용합니다.',
apiInterfaceClose: 'API 인터페이스를 사용할 수 없습니다. 앱 기능이 제한됩니다. 계속하시겠습니까?',
apiInterfaceHelper: '패널 API 인터페이스 액세스를 지원합니다(패널 앱에서 이 기능을 활성화해야 합니다)',
apiInterfaceAlert1: '운영 환경에서는 활성화하지 마십시오. 서버 보안 위험이 증가할 수 있습니다.',
apiInterfaceAlert2: '잠재적인 보안 위협을 방지하기 위해 서드파티 애플리케이션으로 API를 호출하지 마십시오.',
apiInterfaceAlert2: '잠재적인 보안 위협을 방지하기 위해 서드파티 애플리케이션으로 API 를 호출하지 마십시오.',
apiInterfaceAlert3: 'API 문서',
apiInterfaceAlert4: '사용 설명서',
apiKey: 'API 키',
@@ -1684,15 +1745,15 @@ const message = {
levelUpPro: 'Pro 로 업그레이드',
licenseSync: '라이센스 동기화',
knowMorePro: '더 알아보기',
closeAlert: '현재 페이지는 패널 설정에서 닫을 수 있습니다.',
closeAlert: '현재 페이지는 패널 설정에서 숨길 수 있습니다',
introduce: '기능 소개',
waf: '전문 버전으로 업그레이드하면 차단 맵, 로그, 차단 기록, 지리적 위치 차단, 사용자 정의 규칙, 사용자 정의 차단 페이지 등의 기능을 제공받을 수 있습니다.',
tamper: '전문 버전으로 업그레이드하면 웹사이트를 무단 수정이나 변조로부터 보호할 수 있습니다.',
gpu: '전문 버전으로 업그레이드하면 GPU 의 작업 부하, 온도, 메모리 사용량 등 중요한 매개변수를 실시간으로 시각적으로 모니터링할 수 있습니다.',
setting: '전문 버전으로 업그레이드하면 패널 로고, 환영 메시지 등 정보를 사용자 정의할 수 있습니다.',
monitor:
'전문 버전으로 업그레이드하면 웹사이트의 실시간 상태, 방문자 트렌드, 방문자 출처, 요청 로그 등 정보를 확인할 수 있습니다.',
alert: '전문 버전으로 업그레이드하면 SMS 를 통해 알림 정보를 받고 알림 로그를 볼 수 있으며, 다양한 주요 이벤트를 완벽하게 제어하여 시스템 운영을 걱정 없이 유지할 수 있습니다.',
app: '전문 버전으로 업그레이드하면 모바일 앱을 통해 서버를 관리하고 모니터링 기능을 확인할 수 있습니다.',
},
clean: {
scan: '스캔 시작',
@@ -1863,6 +1924,8 @@ const message = {
diffHelper: '왼쪽은 이전 버전, 오른쪽은 새 버전입니다. 편집 후 사용자 정의 버전을 저장하려면 클릭하세요.',
pullImage: '이미지 풀',
pullImageHelper: '애플리케이션 시작 전에 docker pull 을 실행하여 이미지를 다운로드하세요.',
gpuConfig: 'GPU 가속',
gpuConfigHelper: '서버에 NVIDIA 드라이버와 NVIDIA Container Toolkit이 설치되어 있는지 확인하십시오',
},
website: {
website: '웹사이트 | 웹사이트들',
@@ -2454,6 +2517,17 @@ const message = {
licenseHelper: '전문 버전에서는 SMS 알림을 지원합니다.',
alertCountHelper: '최대 일일 알림 빈도',
},
aitool: {
proxy: 'AI 프록시 강화',
proxyHelper1: '도메인을 바인딩하고 HTTPS를 활성화하여 전송 보안을 강화',
proxyHelper2: 'IP 접근을 제한하여 공용 인터넷에서의 노출을 방지',
proxyHelper3: '스트리밍을 활성화',
proxyHelper4: '생성 후, 웹사이트 목록에서 이를 보고 관리할 수 있습니다',
proxyHelper5:
'활성화한 후, 앱 스토어 - 설치됨 - Ollama - 매개변수에서 포트 외부 접근을 비활성화하여 보안을 강화할 수 있습니다.',
proxyHelper6: '프록시 구성을 비활성화하려면 웹사이트 목록에서 삭제할 수 있습니다.',
whiteListHelper: '화이트리스트에 있는 IP만 접근 허용',
},
};
export default {
+81 -5
View File
@@ -15,6 +15,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: 'Jalankan',
create: 'Cipta',
add: 'Tambah',
save: 'Simpan',
@@ -74,6 +75,8 @@ const message = {
createNewFile: 'Cipta fail baru',
helpDoc: 'Dokumen Bantuan',
unbind: 'Nyahkaitkan',
cover: 'Tindih',
skip: 'Langkau',
},
search: {
timeStart: 'Masa mula',
@@ -110,6 +113,7 @@ const message = {
refreshRate: 'Kadar penyegaran',
refreshRateUnit: 'Tiada penyegaran | {n} saat/masa | {n} saat/masa',
selectColumn: 'Pilih lajur',
serialNumber: 'Nombor siri',
},
loadingText: {
Upgrading: 'Peningkatan sistem, sila tunggu...',
@@ -119,6 +123,8 @@ const message = {
},
msg: {
noneData: 'Tiada data tersedia',
disConn:
'Sila klik butang putus sambungan secara langsung untuk menamatkan sambungan terminal, mengelakkan penggunaan arahan keluar seperti {0}.',
delete: 'Operasi ini tidak boleh diundur. Adakah anda mahu meneruskan?',
clean: 'Operasi ini tidak boleh diundur. Adakah anda mahu meneruskan?',
deleteTitle: 'Padam',
@@ -227,7 +233,7 @@ const message = {
paramComplexity:
'Ruangan ini tidak boleh bermula atau berakhir dengan aksara khas dan mesti terdiri daripada aksara rumi, nombor, "{0}" dengan panjang 6-128 aksara.',
paramUrlAndPort: 'Ruangan ini mesti dalam format "http(s)://(nama domain/IP):(port)".',
nginxDoc: 'Ruangan ini mesti terdiri daripada aksara rumi, nombor, dan ".".',
nginxDoc: 'Ruangan ini mesti terdiri daripada aksara rumi, nombor, _, dan ".".',
appName:
'Menyokong huruf kecil, nombor, -, dan _, panjang 2-30, dan tidak boleh bermula atau berakhir dengan - atau _',
containerName:
@@ -334,6 +340,7 @@ const message = {
firewall: 'Firewall',
ssl: 'Certificate | Certificates',
database: 'Database | Databases',
ai_tools: 'AI',
container: 'Container | Containers',
cronjob: 'Cron Job | Cron Jobs',
host: 'Host | Hosts',
@@ -600,6 +607,57 @@ const message = {
'Alamat sambungan ini boleh digunakan oleh aplikasi yang berjalan di luar kontena atau aplikasi luaran.',
localIP: 'IP Tempatan',
},
ai_tools: {
model: {
model: 'Model',
create: 'Tambah Model',
create_helper: 'Tarik "{0}"',
ollama_doc: 'Anda boleh melawat laman web rasmi Ollama untuk mencari dan menemui lebih banyak model.',
container_conn_helper: 'Gunakan alamat ini untuk akses atau sambungan antara kontena',
ollama_sync:
'Sincronizando o modelo Ollama, encontrou que os seguintes modelos não existem, deseja excluí-los?',
from_remote: 'Este modelo não foi baixado via 1Panel, sem logs de pull relacionados.',
no_logs: 'Os logs de pull deste modelo foram excluídos e não podem ser visualizados.',
},
gpu: {
gpu: 'Monitor GPU',
base: 'Maklumat Asas',
gpuHelper: 'Perintah NVIDIA-SMI atau XPU-SMI tidak dikesan pada sistem semasa. Sila periksa dan cuba lagi!',
driverVersion: 'Versi Pemacu',
cudaVersion: 'Versi CUDA',
process: 'Maklumat Proses',
type: 'Jenis',
typeG: 'Grafik',
typeC: 'Pengiraan',
typeCG: 'Pengiraan + Grafik',
processName: 'Nama Proses',
processMemoryUsage: 'Penggunaan Memori',
temperatureHelper: 'Suhu GPU yang tinggi boleh menyebabkan pelambatan frekuensi GPU',
performanceStateHelper: 'Dari P0 (prestasi maksimum) hingga P12 (prestasi minimum)',
busID: 'ID Bas',
persistenceMode: 'Mod Ketekalan',
enabled: 'Diaktifkan',
disabled: 'Dilumpuhkan',
persistenceModeHelper:
'Mod ketekalan membolehkan respons tugas lebih cepat tetapi meningkatkan penggunaan kuasa sedia.',
displayActive: 'Kad Grafik Dimulakan',
displayActiveT: 'Ya',
displayActiveF: 'Tidak',
ecc: 'Teknologi Pemeriksaan dan Pembetulan Ralat',
computeMode: 'Mod Pengiraan',
default: 'Asal',
exclusiveProcess: 'Proses Eksklusif',
exclusiveThread: 'Thread Eksklusif',
prohibited: 'Dilarang',
defaultHelper: 'Asal: Proses boleh dilaksanakan secara serentak',
exclusiveProcessHelper:
'Proses Eksklusif: Hanya satu konteks CUDA boleh menggunakan GPU, tetapi boleh dikongsi oleh berbilang thread',
exclusiveThreadHelper: 'Thread Eksklusif: Hanya satu thread dalam konteks CUDA boleh menggunakan GPU',
prohibitedHelper: 'Dilarang: Proses tidak dibenarkan dilaksanakan serentak',
migModeHelper: 'Digunakan untuk membuat contoh MIG bagi pengasingan fizikal GPU pada tahap pengguna.',
migModeNA: 'Tidak Disokong',
},
},
container: {
create: 'Cipta kontena',
edit: 'Sunting kontena',
@@ -1196,6 +1254,7 @@ const message = {
resource: 'Sumber',
operate: 'Operasi',
detail: {
ai: 'AI',
groups: 'Kumpulan',
hosts: 'Hos',
apps: 'Aplikasi',
@@ -1340,6 +1399,10 @@ const message = {
minimap: 'Peta mini kod',
fileCanNotRead: 'Fail tidak dapat dibaca',
panelInstallDir: 'Direktori pemasangan 1Panel tidak boleh dipadamkan',
existFileTitle: 'Amaran fail dengan nama yang sama',
existFileHelper: 'Fail yang dimuat naik mengandungi fail dengan nama yang sama. Adakah anda mahu menimpanya?',
existFileSize: 'Saiz fail (baru -> lama)',
existFileDirHelper: 'Fail/folder yang dipilih mempunyai nama yang sama. Sila berhati-hati!',
},
ssh: {
setting: 'tetapan',
@@ -1446,8 +1509,8 @@ const message = {
proxyDockerHelper:
'Selaraskan konfigurasi pelayan proksi ke Docker, menyokong tarikan imej pelayan luar talian dan operasi lain',
apiInterface: 'Aktifkan API',
apiInterfaceClose: 'Setelah ditutup, antara muka API tidak boleh diakses. Adakah anda mahu meneruskan?',
apiInterfaceHelper: 'Benarkan aplikasi pihak ketiga mengakses API.',
apiInterfaceClose: 'ntaramuka API tidak tersedia, fungsi aplikasi akan terhad. Adakah anda ingin meneruskan?',
apiInterfaceHelper: 'Menyokong akses antara muka API panel (fungsi ini perlu diaktifkan untuk aplikasi panel)',
apiInterfaceAlert1:
'Jangan aktifkan dalam persekitaran pengeluaran kerana ia mungkin meningkatkan risiko keselamatan pelayan.',
apiInterfaceAlert2:
@@ -1767,16 +1830,16 @@ const message = {
levelUpPro: 'Tingkatkan ke Pro',
licenseSync: 'Penyegerakan Lesen',
knowMorePro: 'Ketahui Lebih Lanjut',
closeAlert: 'Halaman semasa boleh ditutup dalam tetapan panel',
closeAlert: 'Halaman semasa boleh disembunyikan dalam tetapan panel',
introduce: 'Pengenalan Ciri',
waf: 'Menaik taraf ke versi profesional boleh menyediakan ciri seperti peta pencegahan, log, rekod blok, sekatan lokasi geografi, peraturan tersuai, halaman pencegahan tersuai, dan sebagainya.',
tamper: 'Menaik taraf ke versi profesional boleh melindungi laman web daripada pengubahsuaian atau manipulasi tanpa kebenaran.',
gpu: 'Menaik taraf ke versi profesional boleh membantu pengguna memantau parameter penting GPU secara visual seperti beban kerja, suhu, penggunaan memori secara masa nyata.',
setting:
'Menaik taraf ke versi profesional membolehkan penyesuaian logo panel, mesej selamat datang, dan maklumat lain.',
monitor:
'Tingkatkan ke versi profesional untuk melihat status masa nyata laman web, tren pelawat, sumber pelawat, log permintaan dan maklumat lain.',
alert: 'Tingkatkan ke versi profesional untuk menerima maklumat amaran melalui SMS dan melihat log amaran, mengawal sepenuhnya pelbagai acara utama, dan memastikan operasi sistem bebas kerisauan.',
app: 'Tingkatkan ke versi profesional untuk menguruskan pelayan dan melihat ciri pemantauan melalui aplikasi mudah alih.',
},
clean: {
scan: 'Mulakan imbasan',
@@ -1945,6 +2008,8 @@ const message = {
diffHelper: 'Bahagian kiri ialah versi lama, kanan ialah versi baru.',
pullImage: 'Tarik Imej',
pullImageHelper: 'Laksanakan docker pull untuk menarik imej sebelum aplikasi dimulakan.',
gpuConfig: 'Pecutan GPU',
gpuConfigHelper: 'Sila pastikan bahawa pelayan telah dipasang pemacu NVIDIA dan NVIDIA Container Toolkit',
},
website: {
website: 'Laman Web | Laman Web',
@@ -2551,6 +2616,17 @@ const message = {
licenseHelper: 'Versi profesional menyokong amaran SMS',
alertCountHelper: 'Kekerapan maksimum amaran harian',
},
aitool: {
proxy: 'Peningkatan Proksi AI',
proxyHelper1: 'Ikatkan domain dan aktifkan HTTPS untuk meningkatkan keselamatan penghantaran',
proxyHelper2: 'Hadkan akses IP untuk mengelakkan pendedahan di internet awam',
proxyHelper3: 'Aktifkan penstriman',
proxyHelper4: 'Setelah selesai, anda boleh melihat dan mengurusnya dalam senarai laman web',
proxyHelper5:
'Selepas diaktifkan, anda boleh melumpuhkan akses luaran ke port dalam App Store - Dipasang - Ollama - Parameter untuk meningkatkan keselamatan.',
proxyHelper6: 'Untuk melumpuhkan konfigurasi proksi, anda boleh memadamnya dari senarai laman web.',
whiteListHelper: 'Hadkan akses kepada hanya IP dalam senarai putih',
},
};
export default {
+85 -5
View File
@@ -15,6 +15,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: 'Executar',
create: 'Criar',
add: 'Adicionar',
save: 'Salvar',
@@ -74,6 +75,8 @@ const message = {
createNewFile: 'Criar novo arquivo',
helpDoc: 'Documento de ajuda',
unbind: 'Desvincular',
cover: 'Substituir',
skip: 'Pular',
},
search: {
timeStart: 'Hora inicial',
@@ -110,6 +113,7 @@ const message = {
refreshRate: 'Taxa de atualização',
refreshRateUnit: 'Sem atualização | {n} segundo/atualização | {n} segundos/atualização',
selectColumn: 'Selecionar coluna',
serialNumber: 'Número de série',
},
loadingText: {
Upgrading: 'Atualizando o sistema, por favor, aguarde...',
@@ -119,6 +123,8 @@ const message = {
},
msg: {
noneData: 'Nenhum dado disponível',
disConn:
'Por favor, clique diretamente no botão de desconexão para encerrar a conexão do terminal, evitando o uso de comandos de saída como {0}.',
delete: 'Esta operação de exclusão não pode ser desfeita. Deseja continuar?',
clean: 'Esta operação de limpeza não pode ser desfeita. Deseja continuar?',
deleteTitle: 'Excluir',
@@ -225,7 +231,7 @@ const message = {
paramComplexity:
'Este campo não deve começar ou terminar com caracteres especiais e deve conter letras, números e "{0}" com comprimento de 6-128.',
paramUrlAndPort: 'Este campo deve estar no formato "http(s)://(nome do domínio/IP):(porta)".',
nginxDoc: 'Este campo deve conter letras, números e ".".',
nginxDoc: 'Este campo deve conter letras, _, números e ".".',
appName:
'Suporta letras minúsculas, números, - e _, comprimento de 2 a 30, e não pode começar ou terminar com - ou _',
containerName:
@@ -332,6 +338,7 @@ const message = {
firewall: 'Firewall',
ssl: 'Certificado | Certificados',
database: 'Banco de Dados | Bancos de Dados',
ai_tools: 'AI',
container: 'Container | Containers',
cronjob: 'Tarefa Cron | Tarefas Cron',
host: 'Host | Hosts',
@@ -597,6 +604,58 @@ const message = {
'Este endereço de conexão pode ser utilizado por aplicações que estão fora do contêiner ou por aplicações externas.',
localIP: 'IP local',
},
ai_tools: {
model: {
model: 'Modelo',
create: 'Adicionar Modelo',
create_helper: 'Puxar "{0}"',
ollama_doc: 'Você pode visitar o site oficial da Ollama para pesquisar e encontrar mais modelos.',
container_conn_helper: 'Use este endereço para acesso ou conexão entre contêineres',
ollama_sync:
'Menyelaraskan model Ollama mendapati model berikut tidak wujud, adakah anda ingin memadamnya?',
from_remote: 'Model ini tidak dimuat turun melalui 1Panel, tiada log pengambilan berkaitan.',
no_logs: 'Log pengambilan untuk model ini telah dipadam dan tidak dapat dilihat.',
},
gpu: {
gpu: 'Monitor de GPU',
base: 'Informações Básicas',
gpuHelper:
'Comando NVIDIA-SMI ou XPU-SMI não detectado no sistema atual. Por favor, verifique e tente novamente!',
driverVersion: 'Versão do Driver',
cudaVersion: 'Versão do CUDA',
process: 'Informações do Processo',
type: 'Tipo',
typeG: 'Gráficos',
typeC: 'Cálculo',
typeCG: 'Cálculo + Gráficos',
processName: 'Nome do Processo',
processMemoryUsage: 'Uso de Memória',
temperatureHelper: 'Temperaturas altas da GPU podem causar limitação de frequência da GPU.',
performanceStateHelper: 'De P0 (máximo desempenho) a P12 (mínimo desempenho).',
busID: 'ID do Barramento',
persistenceMode: 'Modo de Persistência',
enabled: 'Ativado',
disabled: 'Desativado',
persistenceModeHelper:
'O modo de persistência permite respostas mais rápidas às tarefas, mas aumenta o consumo de energia em standby.',
displayActive: 'Placa Gráfica Inicializada',
displayActiveT: 'Sim',
displayActiveF: 'Não',
ecc: 'Tecnologia de Correção e Verificação de Erros',
computeMode: 'Modo de Cálculo',
default: 'Padrão',
exclusiveProcess: 'Processo Exclusivo',
exclusiveThread: 'Thread Exclusivo',
prohibited: 'Proibido',
defaultHelper: 'Padrão: Processos podem ser executados simultaneamente.',
exclusiveProcessHelper:
'Processo Exclusivo: Apenas um contexto CUDA pode usar a GPU, mas pode ser compartilhado por múltiplas threads.',
exclusiveThreadHelper: 'Thread Exclusivo: Apenas uma thread em um contexto CUDA pode usar a GPU.',
prohibitedHelper: 'Proibido: Não é permitido que processos sejam executados simultaneamente.',
migModeHelper: 'Usado para criar instâncias MIG para isolamento físico da GPU no nível do usuário.',
migModeNA: 'Não Suportado',
},
},
container: {
create: 'Criar contêiner',
edit: 'Editar contêiner',
@@ -1180,6 +1239,7 @@ const message = {
resource: 'Recurso',
operate: 'Operar',
detail: {
ai: 'AI',
groups: 'Grupo',
hosts: 'Host',
apps: 'Aplicativo',
@@ -1326,6 +1386,10 @@ const message = {
minimap: 'Mini mapa de código',
fileCanNotRead: 'O arquivo não pode ser lido',
panelInstallDir: 'O diretório de instalação do 1Panel não pode ser excluído',
existFileTitle: 'Aviso de arquivo com o mesmo nome',
existFileHelper: 'O arquivo enviado contém um arquivo com o mesmo nome. Deseja substituí-lo?',
existFileSize: 'Tamanho do arquivo (novo -> antigo)',
existFileDirHelper: 'O arquivo/pasta selecionado tem um nome duplicado. Por favor, prossiga com cautela!',
},
ssh: {
setting: 'configuração',
@@ -1432,8 +1496,10 @@ const message = {
proxyDockerHelper:
'Sincronize a configuração do servidor proxy com o Docker, suportando operações de puxar imagens de servidor offline e outras',
apiInterface: 'Habilitar API',
apiInterfaceClose: 'Uma vez fechado, as interfaces da API não poderão ser acessadas. Deseja continuar?',
apiInterfaceHelper: 'Permitir que aplicativos de terceiros acessem a API.',
apiInterfaceClose:
'As interfaces de API estão indisponíveis, a funcionalidade do aplicativo será restrita. Deseja continuar?',
apiInterfaceHelper:
'Suporta acesso à interface de API do painel (essa funcionalidade precisa ser ativada no aplicativo do painel)',
apiInterfaceAlert1:
'Não habilite em ambientes de produção, pois pode aumentar os riscos de segurança do servidor.',
apiInterfaceAlert2:
@@ -1753,16 +1819,16 @@ const message = {
levelUpPro: 'Upgrade para Pro',
licenseSync: 'Sincronização de Licença',
knowMorePro: 'Saiba mais',
closeAlert: 'A página atual pode ser fechada nas configurações do painel',
closeAlert: 'A página atual pode ser oculta nas configurações do painel',
introduce: 'Introdução de recursos',
waf: 'O upgrade para a versão profissional pode fornecer recursos como mapa de intercepção, logs, registros de bloqueio, bloqueio por localização geográfica, regras personalizadas, páginas de intercepção personalizadas, etc.',
tamper: 'O upgrade para a versão profissional pode proteger sites contra modificações ou adulterações não autorizadas.',
gpu: 'O upgrade para a versão profissional pode ajudar os usuários a monitorar visualmente parâmetros importantes da GPU, como carga de trabalho, temperatura e uso de memória em tempo real.',
setting:
'O upgrade para a versão profissional permite a personalização do logo do painel, mensagem de boas-vindas e outras informações.',
monitor:
'Upgrade para a versão profissional para visualizar o status em tempo real do site, tendências de visitantes, fontes de visitantes, logs de solicitações e outras informações.',
alert: 'Upgrade para a versão profissional para receber informações de alarme via SMS e visualizar logs de alarmes, controlar completamente vários eventos chave e garantir a operação sem preocupações do sistema',
app: 'Atualize para a versão profissional para gerenciar servidores e visualizar recursos de monitoramento via o aplicativo móvel.',
},
clean: {
scan: 'Iniciar escaneamento',
@@ -1935,6 +2001,9 @@ const message = {
'O lado esquerdo é a versão antiga, o lado direito é a nova versão. Após editar, clique para salvar a versão personalizada',
pullImage: 'Puxar Imagem',
pullImageHelper: 'Execute o comando docker pull para puxar a imagem antes de iniciar o aplicativo',
gpuConfig: 'Aceleração de GPU',
gpuConfigHelper:
'Por favor, certifique-se de que o servidor tenha os drivers NVIDIA e o NVIDIA Container Toolkit instalados',
},
website: {
website: 'Website | Websites',
@@ -2543,6 +2612,17 @@ const message = {
cronJobHelper: 'Dispara alerta via SMS ao falhar na execução de tarefas',
licenseHelper: 'A versão profissional suporta alertas via SMS',
alertCountHelper: 'Frequência máxima diária de alertas',
proxyHelper5:
'Após ativar, você pode desabilitar o acesso externo à porta na Loja de Aplicativos - Instalados - Ollama - Parâmetros para melhorar a segurança.',
},
aitool: {
proxy: 'Melhoria de Proxy AI',
proxyHelper1: 'Vincule o domínio e habilite o HTTPS para aumentar a segurança na transmissão',
proxyHelper2: 'Limite o acesso por IP para evitar exposição na internet pública',
proxyHelper3: 'Habilite a transmissão em fluxo',
proxyHelper4: 'Após a criação, você pode visualizar e gerenciar no lista de sites',
proxyHelper6: 'Para desativar a configuração de proxy, você pode excluí-la da lista de sites.',
whiteListHelper: 'Restringir o acesso apenas aos IPs na lista branca',
},
};
+86 -6
View File
@@ -15,6 +15,7 @@ const message = {
fit2cloud: 'FIT2CLOUD',
lingxia: 'Lingxia',
button: {
run: 'Запуск',
create: 'Создать ',
add: 'Добавить ',
save: 'Сохранить ',
@@ -43,7 +44,7 @@ const message = {
collapse: 'Свернуть',
log: 'Логи',
back: 'Назад',
backup: 'Резервное копирование',
backup: 'Бэкап',
recover: 'Восстановить',
retry: 'Повторить',
upload: 'Загрузить',
@@ -74,6 +75,8 @@ const message = {
createNewFile: 'Создать новый файл',
helpDoc: 'Справка',
unbind: 'Отвязать',
cover: 'Заменить',
skip: 'Пропустить',
},
search: {
timeStart: 'Время начала',
@@ -110,6 +113,8 @@ const message = {
refreshRate: 'Частота обновления',
refreshRateUnit: 'Без обновления | {n} секунда/раз | {n} секунд/раз',
selectColumn: 'Выбрать столбец',
cover: 'Заменить',
skip: 'Пропустить',
},
loadingText: {
Upgrading: 'Обновление системы, пожалуйста, подождите...',
@@ -119,6 +124,8 @@ const message = {
},
msg: {
noneData: 'Нет данных',
disConn:
'Пожалуйста, нажмите кнопку отключения, чтобы разорвать соединение с терминалом, избегая использования команд выхода, таких как {0}.',
delete: 'Эта операция удаления не может быть отменена. Хотите продолжить?',
clean: 'Эта операция очистки не может быть отменена. Хотите продолжить?',
deleteTitle: 'Удалить',
@@ -222,7 +229,7 @@ const message = {
paramComplexity:
'Это поле не должно начинаться и заканчиваться специальными символами и должно состоять из английских букв, цифр, "{0}" длиной 6-128.',
paramUrlAndPort: 'Это поле должно быть в формате "http(s)://(доменное имя/ip):(порт)".',
nginxDoc: 'Это поле должно состоять из английских букв, цифр и ".".',
nginxDoc: 'Это поле должно состоять из английских букв, цифр и _,".".',
appName:
'Поддерживает строчные буквы, цифры, - и _, длина 2-30, и не может начинаться или заканчиваться на - или _',
containerName: 'Поддерживаются буквы, цифры, -, _ и .; не может начинаться с - _ или .; длина: 2-128',
@@ -328,6 +335,7 @@ const message = {
firewall: 'Firewall',
ssl: 'Сертификат | Сертификаты',
database: 'База данных | Базы данных',
ai_tools: 'AI',
container: 'Контейнер | Контейнеры',
cronjob: 'Cron | Задачи Cron',
host: 'Хост | Хосты',
@@ -594,6 +602,58 @@ const message = {
'Этот адрес подключения может использоваться приложениями, работающими вне контейнера или внешними приложениями.',
localIP: 'Локальный IP',
},
ai_tools: {
model: {
model: 'Модель',
create: 'Добавить модель',
create_helper: 'Загрузить "{0}"',
ollama_doc: 'Вы можете посетить официальный сайт Ollama, чтобы искать и находить больше моделей.',
container_conn_helper: 'Используйте этот адрес для доступа или подключения между контейнерами',
ollama_sync:
'Синхронизация модели Ollama обнаружила, что следующие модели не существуют, хотите удалить их?',
from_remote: 'Эта модель не была загружена через 1Panel, нет связанных журналов извлечения.',
no_logs: 'Журналы извлечения для этой модели были удалены и не могут быть просмотрены.',
},
gpu: {
gpu: 'Мониторинг GPU',
base: 'Основная информация',
gpuHelper: 'Команда NVIDIA-SMI или XPU-SMI не обнаружена в текущей системе. Проверьте и попробуйте снова!',
driverVersion: 'Версия драйвера',
cudaVersion: 'Версия CUDA',
process: 'Информация о процессе',
type: 'Тип',
typeG: 'Графика',
typeC: 'Вычисления',
typeCG: 'Вычисления + Графика',
processName: 'Имя процесса',
processMemoryUsage: 'Использование памяти',
temperatureHelper: 'Высокая температура GPU может вызвать снижение частоты GPU',
performanceStateHelper: 'От P0 (максимальная производительность) до P12 (минимальная производительность)',
busID: 'ID шины',
persistenceMode: 'Режим постоянства',
enabled: 'Включен',
disabled: 'Выключен',
persistenceModeHelper:
'Режим постоянства позволяет быстрее реагировать на задачи, но увеличивает потребление энергии в режиме ожидания.',
displayActive: 'Инициализация видеокарты',
displayActiveT: 'Да',
displayActiveF: 'Нет',
ecc: 'Технология проверки и коррекции ошибок (ECC)',
computeMode: 'Режим вычислений',
default: 'По умолчанию',
exclusiveProcess: 'Исключительный процесс',
exclusiveThread: 'Исключительный поток',
prohibited: 'Запрещено',
defaultHelper: 'По умолчанию: процессы могут выполняться одновременно',
exclusiveProcessHelper:
'Исключительный процесс: только один контекст CUDA может использовать GPU, но его могут разделять несколько потоков',
exclusiveThreadHelper: 'Исключительный поток: только один поток в контексте CUDA может использовать GPU',
prohibitedHelper: 'Запрещено: процессам не разрешено выполняться одновременно',
migModeHelper:
'Используется для создания MIG-инстансов для физической изоляции GPU на уровне пользователя.',
migModeNA: 'Не поддерживается',
},
},
container: {
create: 'Создать контейнер',
edit: 'Редактировать контейнер',
@@ -1185,6 +1245,7 @@ const message = {
resource: 'Ресурс',
operate: 'Операция',
detail: {
ai: 'AI',
groups: 'Группа',
hosts: 'Хост',
apps: 'Приложение',
@@ -1328,6 +1389,10 @@ const message = {
minimap: 'Мини-карта кода',
fileCanNotRead: 'Файл не может быть прочитан',
panelInstallDir: 'Директорию установки 1Panel нельзя удалить',
existFileTitle: 'Предупреждение о файле с тем же именем',
existFileHelper: 'Загруженный файл содержит файл с таким же именем. Заменить его?',
existFileSize: 'Размер файла (новый -> старый)',
existFileDirHelper: 'Выбранный файл/папка имеет дублирующееся имя. Пожалуйста, действуйте осторожно!',
},
ssh: {
setting: 'настройка',
@@ -1433,8 +1498,10 @@ const message = {
proxyDockerHelper:
'Синхронизировать конфигурацию прокси-сервера с Docker, поддержка офлайн загрузки образов и других операций',
apiInterface: 'Включить API',
apiInterfaceClose: 'После закрытия API-интерфейсы будут недоступны. Хотите продолжить?',
apiInterfaceHelper: 'Разрешить сторонним приложениям доступ к API.',
apiInterfaceClose:
'API интерфейсы недоступны, функциональность приложения будет ограничена. Хотите продолжить?',
apiInterfaceHelper:
'Поддержка доступа к API-интерфейсу панели (эта функция должна быть включена для мобильного приложения панели)',
apiInterfaceAlert1:
'Не включайте в производственной среде, так как это может повысить риски безопасности сервера.',
apiInterfaceAlert2:
@@ -1751,16 +1818,16 @@ const message = {
levelUpPro: 'Обновить до Pro',
licenseSync: 'Синхронизация лицензии',
knowMorePro: 'Узнать больше',
closeAlert: 'Текущую страницу можно закрыть в настройках панели',
closeAlert: 'Эту страницу можно скрыть в настройках панели',
introduce: 'Описание функций',
waf: 'Обновление до профессиональной версии предоставляет такие функции, как карта перехватов, логи, записи блокировок, блокировка по географическому положению, пользовательские правила, пользовательские страницы перехвата и т.д.',
tamper: 'Обновление до профессиональной версии может защитить веб-сайты от несанкционированных изменений или подделок.',
gpu: 'Обновление до профессиональной версии помогает пользователям визуально отслеживать важные параметры GPU, такие как нагрузка, температура, использование памяти в реальном времени.',
setting:
'Обновление до профессиональной версии позволяет настраивать логотип панели, приветственное сообщение и другую информацию.',
monitor:
'Обновление до профессиональной версии позволяет просматривать статус веб-сайта в реальном времени, тенденции посещений, источники посетителей, логи запросов и другую информацию.',
alert: 'Обновление до профессиональной версии позволяет получать информацию о тревогах через SMS и просматривать логи тревог, полностью контролировать различные ключевые события и обеспечивать беспроблемную работу системы',
app: 'Обновите до профессиональной версии, чтобы управлять серверами и просматривать функции мониторинга через мобильное приложение.',
},
clean: {
scan: 'Начать сканирование',
@@ -1936,6 +2003,8 @@ const message = {
'Слева старая версия, справа новая версия. После редактирования нажмите для сохранения пользовательской версии',
pullImage: 'Загрузить образ',
pullImageHelper: 'Выполнить docker pull для загрузки образа перед запуском приложения',
gpuConfig: 'GPU Hızlandırma',
gpuConfigHelper: 'Пожалуйста, убедитесь, что на сервере установлены драйверы NVIDIA и NVIDIA Container Toolkit',
},
website: {
website: 'Веб-сайт | Веб-сайты',
@@ -2542,6 +2611,17 @@ const message = {
licenseHelper: 'Профессиональная версия поддерживает SMS-оповещения',
alertCountHelper: 'Максимальная дневная частота оповещений',
},
aitool: {
proxy: 'Усиление AI-прокси',
proxyHelper1: 'Привяжите домен и включите HTTPS для повышения безопасности передачи данных',
proxyHelper2: 'Ограничьте доступ по IP, чтобы предотвратить утечку данных в публичной сети',
proxyHelper3: 'Включите потоковую передачу',
proxyHelper4: 'После создания вы можете просматривать и управлять этим в списке сайтов',
proxyHelper5:
'После включения вы можете отключить внешний доступ к порту в Магазине приложений - Установленные - Ollama - Параметры для повышения безопасности.',
proxyHelper6: 'Чтобы отключить настройку прокси, вы можете удалить её из списка сайтов.',
whiteListHelper: 'Ограничить доступ только для IP-адресов из белого списка',
},
};
export default {
+77 -6
View File
@@ -14,6 +14,7 @@ const message = {
fit2cloud: '飛致雲',
lingxia: '凌霞',
button: {
run: '運行',
create: '建立',
add: '新增',
save: '儲存',
@@ -73,6 +74,8 @@ const message = {
createNewFile: '新增檔案',
helpDoc: '說明文件',
unbind: '解綁',
cover: '覆蓋',
skip: '跳過',
},
search: {
timeStart: '開始時間',
@@ -110,6 +113,7 @@ const message = {
noRefresh: '不更新',
refreshRateUnit: '不更新 | {0} 秒/次 | {0} 秒/次',
selectColumn: '選擇列',
serialNumber: '序號',
},
loadingText: {
Upgrading: '系統升級中,請稍候...',
@@ -119,6 +123,7 @@ const message = {
},
msg: {
noneData: '暫無資料',
disConn: '請直接點擊斷開按鈕斷開終端連接,避免使用 {0} 等退出命令。',
delete: '刪除 操作不可復原,是否繼續?',
clean: '清空 操作不可復原,是否繼續?',
deleteTitle: '刪除',
@@ -216,7 +221,7 @@ const message = {
paramName: '支援英文、數字、.-和_,長度2-64',
paramComplexity: '支援英文、數字、{0},長度6-128,特殊字元不能在首尾',
paramUrlAndPort: '格式為 http(s)://(域名/ip):(埠)',
nginxDoc: '僅支援英文大小寫,數字,和.',
nginxDoc: '僅支援英文大小寫,數字,_,和.',
appName: '支援小寫英文、數字、-和_,長度2-30,並且不能以-_開頭和結尾',
containerName: '支援字母、數字、_-和.,不能以-_或.開頭,長度2-128',
mirror: '支援以 http(s):// 開頭,英文大小寫,數字,. / 和 - 的鏡像加速地址,且不能有空行',
@@ -321,6 +326,7 @@ const message = {
firewall: '防火牆',
ssl: '證書',
database: '資料庫',
ai_tools: 'AI',
container: '容器',
cronjob: '計劃任務',
host: '主機',
@@ -570,6 +576,54 @@ const message = {
remoteConnHelper2: '非容器或外部連接使用此地址',
localIP: '本機 IP',
},
ai_tools: {
model: {
model: '模型',
create: '添加模型',
create_helper: '拉取 "{0}"',
ollama_doc: '您可以訪問 Ollama 官方網站,搜索並查找更多模型。',
container_conn_helper: '容器間訪問或連接使用此地址',
ollama_sync: '同步 Ollama 模型發現下列模型不存在,是否刪除?',
from_remote: '該模型並非通過 1Panel 下載,無相關拉取日誌。',
no_logs: '該模型的拉取日誌已被刪除,無法查看相關日誌。',
},
gpu: {
gpu: 'GPU 监控',
base: '基礎資訊',
gpuHelper: '目前系統未檢測到 NVIDIA-SMI或者XPU-SMI 指令,請檢查後重試!',
driverVersion: '驅動版本',
cudaVersion: 'CUDA 版本',
process: '行程資訊',
type: '類型',
typeG: '圖形',
typeC: '計算',
typeCG: '計算+圖形',
processName: '行程名稱',
processMemoryUsage: '顯存使用',
temperatureHelper: 'GPU 溫度過高會導致 GPU 頻率下降',
performanceStateHelper: '從 P0 (最大性能) 到 P12 (最小性能)',
busID: '總線地址',
persistenceMode: '持續模式',
enabled: '開啟',
disabled: '關閉',
persistenceModeHelper: '持續模式能更加快速地響應任務,但相應待機功耗也會增加',
displayActive: '顯卡初始化',
displayActiveT: '是',
displayActiveF: '否',
ecc: '是否開啟錯誤檢查和紀正技術',
computeMode: '計算模式',
default: '預設',
exclusiveProcess: '行程排他',
exclusiveThread: '線程排他',
prohibited: '禁止',
defaultHelper: '預設: 行程可以並發執行',
exclusiveProcessHelper: '行程排他: 只有一個 CUDA 上下文可以使用 GPU, 但可以由多個線程共享',
exclusiveThreadHelper: '線程排他: 只有一個線程在 CUDA 上下文中可以使用 GPU',
prohibitedHelper: '禁止: 不允許行程同時執行',
migModeHelper: '用於建立 MIG 實例,在用戶層實現 GPU 的物理隔離。',
migModeNA: '不支援',
},
},
container: {
create: '建立容器',
edit: '編輯容器',
@@ -1117,6 +1171,7 @@ const message = {
resource: '資源',
operate: '操作',
detail: {
ai: 'AI',
groups: '分組',
hosts: '主機',
apps: '應用',
@@ -1257,6 +1312,10 @@ const message = {
minimap: '縮圖',
fileCanNotRead: '此檔案不支援預覽',
panelInstallDir: '1Panel 安裝目錄不能刪除',
existFileTitle: '同名檔案提示',
existFileHelper: '上傳的檔案存在同名檔案,是否覆蓋?',
existFileSize: '文件大小(新->舊)',
existFileDirHelper: '選擇的檔案/資料夾存在同名,請謹慎操作!',
},
ssh: {
setting: '設定',
@@ -1354,10 +1413,10 @@ const message = {
proxyDocker: 'Docker 代理',
proxyDockerHelper: '將代理伺服器配寘同步至 Docker,支援離線伺服器拉取鏡像等操作',
apiInterface: 'API 介面',
apiInterfaceClose: '關閉後將不能使用 API 介面進行瀏覽,是否繼續?',
apiInterfaceHelper: '提供面板支援 API 介面瀏覽',
apiInterfaceClose: '關閉後將不能使用 API 介面進行瀏覽,APP功能將被限制,是否繼續?',
apiInterfaceHelper: '支持面板 API 接口訪問功能(面板 APP 需要開啟該功能)',
apiInterfaceAlert1: '請不要在生產環境開啟,這可能新增伺服器安全風險',
apiInterfaceAlert2: '請不要使用協力廠商應用呼叫面板 API,以防止潛在的安全威脅。',
apiInterfaceAlert2: '請不要使用協力廠商應用呼叫面板 API,以防止潛在的安全威脅',
apiInterfaceAlert3: 'API 介面檔案',
apiInterfaceAlert4: '使用檔案',
apiKey: '介面金鑰',
@@ -1626,14 +1685,14 @@ const message = {
levelUpPro: '升級專業版',
licenseSync: '許可證同步',
knowMorePro: '了解更多',
closeAlert: '目前頁面可在面板設定中關閉顯示',
closeAlert: '目前頁面可在面板設定中隱藏',
introduce: '功能介紹',
waf: '升級專業版可以獲得攔截地圖、日誌、封鎖記錄、地理位置封禁、自訂規則、自訂攔截頁面等功能。',
tamper: '升級專業版可以保護網站免受未經授權的修改或篡改。',
gpu: '升級專業版可以幫助用戶即時直觀查看到 GPU 的工作負載、溫度、記憶體等重要參數。',
setting: '升級專業版可以自訂面板 Logo、歡迎簡介等資訊。',
monitor: '升級專業版可以查看網站的即時狀態、訪客趨勢、訪客來源、請求日誌等資訊。 ',
alert: '升級專業版可透過簡訊接收告警資訊,並查看告警日誌,全面掌控各類關鍵事件,確保系統執行無憂。',
app: '升級專業版可以通過手機 APP 管理伺服器並查看監控等功能。',
},
clean: {
scan: '開始掃描',
@@ -1796,6 +1855,8 @@ const message = {
diffHelper: '左側為舊版本,右側為新版,編輯之後點選使用自訂版本儲存',
pullImage: '拉取鏡像',
pullImageHelper: '在應用啟動之前執行 docker pull 來拉取鏡像',
gpuConfig: 'GPU 加速',
gpuConfigHelper: '請確保伺服器已安裝 NVIDIA 驅動程式和 NVIDIA Container Toolkit',
},
website: {
website: '網站',
@@ -2363,6 +2424,16 @@ const message = {
licenseHelper: '專業版支援簡訊告警功能',
alertCountHelper: '每日最大告警次數',
},
aitool: {
proxy: 'AI 代理增強',
proxyHelper1: '綁定域名並啟用 HTTPS,提高傳輸安全性',
proxyHelper2: '限制 IP 訪問,防止在公共網絡上暴露',
proxyHelper3: '啟用流式傳輸',
proxyHelper4: '創建後,您可以在網站列表中查看並管理',
proxyHelper5: '啟用後,您可以在應用商店 - 已安裝 - Ollama - 參數中取消端口外部訪問以提高安全性。',
proxyHelper6: '如需關閉代理配置,可以在網站列表中刪除',
whiteListHelper: '限制僅白名單中的 IP 可訪問',
},
};
export default {
...fit2cloudTwLocale,

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