diff --git a/backend/app/api/v1/ai_tool.go b/backend/app/api/v1/ai_tool.go index b36ed4fdd..89d6d162f 100644 --- a/backend/app/api/v1/ai_tool.go +++ b/backend/app/api/v1/ai_tool.go @@ -134,3 +134,64 @@ func (b *BaseApi) LoadGpuInfo(c *gin.Context) { } helper.SuccessWithData(c, &common.GpuInfo{}) } + +// @Tags AITools +// @Summary Bind domain +// @Accept json +// @Param request body dto.WebsiteConfig true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /aitool/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 AITools +// @Summary Get bind domain +// @Accept json +// @Param request body dto.OllamaBindDomainReq true "request" +// @Success 200 {object} dto.OllamaBindDomainRes +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /aitool/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 AITools +// Summary Update bind domain +// Accept json +// Param request body dto.OllamaBindDomain true "request" +// Success 200 +// Security ApiKeyAuth +// Security Timestamp +// Router /aitool/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) +} diff --git a/backend/app/dto/ai_tool.go b/backend/app/dto/ai_tool.go index 49b2d5d93..9835a8487 100644 --- a/backend/app/dto/ai_tool.go +++ b/backend/app/dto/ai_tool.go @@ -9,3 +9,22 @@ type OllamaModelInfo struct { 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"` + AllowIPs []string `json:"allowIPs"` + WebsiteID uint `json:"websiteID"` +} + +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"` +} diff --git a/backend/app/service/ai_tool.go b/backend/app/service/ai_tool.go index 7dbe18ca9..47a075e0c 100644 --- a/backend/app/service/ai_tool.go +++ b/backend/app/service/ai_tool.go @@ -1,7 +1,9 @@ package service import ( + "context" "fmt" + "github.com/1Panel-dev/1Panel/backend/app/dto/request" "io" "os" "os/exec" @@ -22,6 +24,9 @@ type IAIToolService interface { Create(name string) error Delete(name string) 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 { @@ -192,3 +197,98 @@ func (u *AIToolService) Delete(name string) error { } return nil } + +func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error { + nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty) + if nginxInstall.ID == 0 { + return buserr.New("ErrOpenrestyInstall") + } + 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 err = ConfigAllowIPs(req.AllowIPs, 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 +} + +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.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") + } + websiteService := NewIWebsiteService() + website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID)) + if err != nil { + return err + } + if err = ConfigAllowIPs(req.AllowIPs, 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 +} diff --git a/backend/app/service/website_utils.go b/backend/app/service/website_utils.go index 7906a6062..3f3987119 100644 --- a/backend/app/service/website_utils.go +++ b/backend/app/service/website_utils.go @@ -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.UpdateRootProxy() + } + } + return nil +} diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index e17a2bdfe..68a39cd68 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -284,3 +284,6 @@ 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' diff --git a/backend/i18n/lang/ja.yaml b/backend/i18n/lang/ja.yaml index 2d172bdb4..880353080 100644 --- a/backend/i18n/lang/ja.yaml +++ b/backend/i18n/lang/ja.yaml @@ -281,3 +281,6 @@ UserInfoPassHelp: "ヒント:パスワードを変更するには、コマン DBConnErr: "エラー:データベース接続の初期化に失敗しました、{{.err}}" SystemVersion: "バージョン:" SystemMode: "モード:" + +#ai-tool +ErrOpenrestyInstall: 'まず Openresty をインストールしてください' \ No newline at end of file diff --git a/backend/i18n/lang/ko.yaml b/backend/i18n/lang/ko.yaml index 2f1ecc59e..5338b5c8d 100644 --- a/backend/i18n/lang/ko.yaml +++ b/backend/i18n/lang/ko.yaml @@ -284,3 +284,6 @@ UserInfoPassHelp: "팁: 비밀번호를 변경하려면 다음 명령어를 실 DBConnErr: "오류: 데이터베이스 연결 초기화 실패 {{ .err }}" SystemVersion: "버전: " SystemMode: "모드: " + +#ai-tool +ErrOpenrestyInstall: '먼저 Openresty를 설치하세요' \ No newline at end of file diff --git a/backend/i18n/lang/ms.yml b/backend/i18n/lang/ms.yml index 02c5056cf..ace41c67f 100644 --- a/backend/i18n/lang/ms.yml +++ b/backend/i18n/lang/ms.yml @@ -283,3 +283,6 @@ 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' \ No newline at end of file diff --git a/backend/i18n/lang/pt-BR.yaml b/backend/i18n/lang/pt-BR.yaml index 9e9a5158e..78e96743b 100644 --- a/backend/i18n/lang/pt-BR.yaml +++ b/backend/i18n/lang/pt-BR.yaml @@ -280,4 +280,7 @@ 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: " \ No newline at end of file +SystemMode: "modo: " + +#ai-tool +ErrOpenrestyInstall: 'Por favor, instale o Openresty primeiro' \ No newline at end of file diff --git a/backend/i18n/lang/pt.yaml b/backend/i18n/lang/pt.yaml deleted file mode 100644 index f42f9f515..000000000 --- a/backend/i18n/lang/pt.yaml +++ /dev/null @@ -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: " \ No newline at end of file diff --git a/backend/i18n/lang/ru.yaml b/backend/i18n/lang/ru.yaml index c813aa133..bb32d2356 100644 --- a/backend/i18n/lang/ru.yaml +++ b/backend/i18n/lang/ru.yaml @@ -284,3 +284,6 @@ UserInfoPassHelp: "Подсказка: чтобы изменить пароль, DBConnErr: "Ошибка: не удалось инициализировать подключение к базе данных, {{ .err }}" SystemVersion: "версия: " SystemMode: "режим: " + +#ai-tool +"ErrOpenrestyInstall": "Пожалуйста, установите Openresty сначала" diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml index 8b3cf952e..54ff41298 100644 --- a/backend/i18n/lang/zh-Hant.yaml +++ b/backend/i18n/lang/zh-Hant.yaml @@ -284,3 +284,6 @@ UserInfoPassHelp: "提示:修改密碼可執行指令:" DBConnErr: "錯誤:初始化資料庫連線失敗,{{ .err }}" SystemVersion: "版本:" SystemMode: "模式:" + +#ai-tool +"ErrOpenrestyInstall": "請先安裝 Openresty" \ No newline at end of file diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index ffd65edf6..fab315a0b 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -284,3 +284,6 @@ UserInfoPassHelp: "提示:修改密码可执行命令:" DBConnErr: "错误:初始化数据库连接失败,{{ .err }}" SystemVersion: "版本:" SystemMode: "模式:" + +#ai-tool +ErrOpenrestyInstall: '请先安装 Openresty' \ No newline at end of file diff --git a/backend/router/ro_aitool.go b/backend/router/ro_aitool.go index 63ca06c75..093ca5e78 100644 --- a/backend/router/ro_aitool.go +++ b/backend/router/ro_aitool.go @@ -20,5 +20,8 @@ func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) { 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) } } diff --git a/backend/utils/nginx/components/server.go b/backend/utils/nginx/components/server.go index c7138936f..d2cecbe57 100644 --- a/backend/utils/nginx/components/server.go +++ b/backend/utils/nginx/components/server.go @@ -265,6 +265,41 @@ 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", + }, + }, + } + 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 +404,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...) + } +} diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 3ad351f8e..213b0e21f 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1,4 +1,5 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag package docs import "github.com/swaggo/swag" @@ -20,6 +21,267 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/aitool/domain/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Bind domain", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.WebsiteConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/aitool/domain/get": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, + "/aitool/gpu/load": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Load gpu / xpu info", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/aitool/ollama/model/del": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Delete 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": "remove Ollama model [name]", + "formatZH": "删除模型 [name]", + "paramKeys": [] + } + } + }, + "/aitools/ollama/model": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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": "添加模型 [name]", + "paramKeys": [] + } + } + }, + "/aitools/ollama/model/load": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, + "/aitools/ollama/model/search": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, "/apps/checkupdate": { "get": { "security": [ @@ -6024,6 +6286,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 +17062,9 @@ const docTemplate = `{ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "key": { "type": "string" }, @@ -16991,6 +17297,41 @@ const docTemplate = `{ } } }, + "dto.CCConfig": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "code": { + "type": "integer" + }, + "duration": { + "type": "integer" + }, + "ipBlock": { + "type": "string" + }, + "ipBlockTime": { + "type": "integer" + }, + "mode": { + "type": "string" + }, + "res": { + "type": "string" + }, + "state": { + "type": "string" + }, + "threshold": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { @@ -17435,6 +17776,26 @@ const docTemplate = `{ } } }, + "dto.CommonConfig": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "code": { + "type": "integer" + }, + "res": { + "type": "string" + }, + "state": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "dto.CommonRecover": { "type": "object", "required": [ @@ -19131,6 +19492,29 @@ const docTemplate = `{ } } }, + "dto.GeoRestrict": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "res": { + "type": "string" + }, + "rules": { + "type": "array", + "items": { + "type": "string" + } + }, + "state": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "dto.GroupCreate": { "type": "object", "required": [ @@ -19564,6 +19948,9 @@ const docTemplate = `{ "ja": { "type": "string" }, + "ko": { + "type": "string" + }, "ms": { "type": "string" }, @@ -20217,6 +20604,45 @@ const docTemplate = `{ "ProxyCache" ] }, + "dto.OllamaBindDomainReq": { + "type": "object", + "required": [ + "appInstallID" + ], + "properties": { + "appInstallID": { + "type": "integer" + } + } + }, + "dto.OllamaBindDomainRes": { + "type": "object", + "properties": { + "allowIPs": { + "type": "array", + "items": { + "type": "string" + } + }, + "domain": { + "type": "string" + }, + "sslID": { + "type": "integer" + }, + "websiteID": { + "type": "integer" + } + } + }, + "dto.OllamaModelName": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, "dto.OneDriveInfo": { "type": "object", "properties": { @@ -21683,6 +22109,14 @@ const docTemplate = `{ } } }, + "dto.StateConfig": { + "type": "object", + "properties": { + "state": { + "type": "string" + } + } + }, "dto.SwapHelper": { "type": "object", "required": [ @@ -21881,6 +22315,72 @@ const docTemplate = `{ } } }, + "dto.WafConfig": { + "type": "object", + "required": [ + "mode", + "secret", + "state" + ], + "properties": { + "mode": { + "type": "string" + }, + "secret": { + "type": "string" + }, + "state": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "dto.WebsiteConfig": { + "type": "object", + "properties": { + "args": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "cc": { + "$ref": "#/definitions/dto.CCConfig" + }, + "cdn": { + "$ref": "#/definitions/dto.StateConfig" + }, + "cookie": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "defaultUaBlack": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "defaultUrlBlack": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "fileExt": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "geoRestrict": { + "$ref": "#/definitions/dto.GeoRestrict" + }, + "header": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "methodWhite": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "sql": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "waf": { + "$ref": "#/definitions/dto.WafConfig" + }, + "xss": { + "$ref": "#/definitions/dto.CommonConfig" + } + } + }, "dto.XPUInfo": { "type": "object", "properties": { @@ -22010,6 +22510,9 @@ const docTemplate = `{ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -22210,32 +22713,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 +23012,9 @@ const docTemplate = `{ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -22698,6 +23178,9 @@ const docTemplate = `{ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -23046,6 +23529,20 @@ const docTemplate = `{ } } }, + "request.FilePathsCheck": { + "type": "object", + "required": [ + "paths" + ], + "properties": { + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "request.FileReadByLineReq": { "type": "object", "required": [ @@ -23264,6 +23761,9 @@ const docTemplate = `{ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -24883,6 +25383,9 @@ const docTemplate = `{ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -24921,6 +25424,9 @@ const docTemplate = `{ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -24966,7 +25472,7 @@ const docTemplate = `{ "tags": { "type": "array", "items": { - "$ref": "#/definitions/model.Tag" + "$ref": "#/definitions/response.TagDTO" } }, "type": { @@ -25007,6 +25513,9 @@ const docTemplate = `{ "enable": { "type": "boolean" }, + "gpuSupport": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -25087,6 +25596,9 @@ const docTemplate = `{ "description": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -25242,6 +25754,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 +26691,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" @@ -26186,8 +26715,6 @@ var SwaggerInfo = &swag.Spec{ Description: "Top-Rated Web-based Linux Server Management Tool", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, - LeftDelim: "{{", - RightDelim: "}}", } func init() { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 050fffdce..86965f97f 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -17,6 +17,267 @@ }, "basePath": "/api/v1", "paths": { + "/aitool/domain/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Bind domain", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.WebsiteConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/aitool/domain/get": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, + "/aitool/gpu/load": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Load gpu / xpu info", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/aitool/ollama/model/del": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "summary": "Delete 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": "remove Ollama model [name]", + "formatZH": "删除模型 [name]", + "paramKeys": [] + } + } + }, + "/aitools/ollama/model": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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": "添加模型 [name]", + "paramKeys": [] + } + } + }, + "/aitools/ollama/model/load": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, + "/aitools/ollama/model/search": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "AITools" + ], + "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" + } + } + } + } + }, "/apps/checkupdate": { "get": { "security": [ @@ -6021,6 +6282,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 +17058,9 @@ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "key": { "type": "string" }, @@ -16988,6 +17293,41 @@ } } }, + "dto.CCConfig": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "code": { + "type": "integer" + }, + "duration": { + "type": "integer" + }, + "ipBlock": { + "type": "string" + }, + "ipBlockTime": { + "type": "integer" + }, + "mode": { + "type": "string" + }, + "res": { + "type": "string" + }, + "state": { + "type": "string" + }, + "threshold": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { @@ -17432,6 +17772,26 @@ } } }, + "dto.CommonConfig": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "code": { + "type": "integer" + }, + "res": { + "type": "string" + }, + "state": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "dto.CommonRecover": { "type": "object", "required": [ @@ -19128,6 +19488,29 @@ } } }, + "dto.GeoRestrict": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "res": { + "type": "string" + }, + "rules": { + "type": "array", + "items": { + "type": "string" + } + }, + "state": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "dto.GroupCreate": { "type": "object", "required": [ @@ -19561,6 +19944,9 @@ "ja": { "type": "string" }, + "ko": { + "type": "string" + }, "ms": { "type": "string" }, @@ -20214,6 +20600,45 @@ "ProxyCache" ] }, + "dto.OllamaBindDomainReq": { + "type": "object", + "required": [ + "appInstallID" + ], + "properties": { + "appInstallID": { + "type": "integer" + } + } + }, + "dto.OllamaBindDomainRes": { + "type": "object", + "properties": { + "allowIPs": { + "type": "array", + "items": { + "type": "string" + } + }, + "domain": { + "type": "string" + }, + "sslID": { + "type": "integer" + }, + "websiteID": { + "type": "integer" + } + } + }, + "dto.OllamaModelName": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, "dto.OneDriveInfo": { "type": "object", "properties": { @@ -21680,6 +22105,14 @@ } } }, + "dto.StateConfig": { + "type": "object", + "properties": { + "state": { + "type": "string" + } + } + }, "dto.SwapHelper": { "type": "object", "required": [ @@ -21878,6 +22311,72 @@ } } }, + "dto.WafConfig": { + "type": "object", + "required": [ + "mode", + "secret", + "state" + ], + "properties": { + "mode": { + "type": "string" + }, + "secret": { + "type": "string" + }, + "state": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, + "dto.WebsiteConfig": { + "type": "object", + "properties": { + "args": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "cc": { + "$ref": "#/definitions/dto.CCConfig" + }, + "cdn": { + "$ref": "#/definitions/dto.StateConfig" + }, + "cookie": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "defaultUaBlack": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "defaultUrlBlack": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "fileExt": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "geoRestrict": { + "$ref": "#/definitions/dto.GeoRestrict" + }, + "header": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "methodWhite": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "sql": { + "$ref": "#/definitions/dto.CommonConfig" + }, + "waf": { + "$ref": "#/definitions/dto.WafConfig" + }, + "xss": { + "$ref": "#/definitions/dto.CommonConfig" + } + } + }, "dto.XPUInfo": { "type": "object", "properties": { @@ -22007,6 +22506,9 @@ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -22207,32 +22709,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 +23008,9 @@ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -22695,6 +23174,9 @@ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -23043,6 +23525,20 @@ } } }, + "request.FilePathsCheck": { + "type": "object", + "required": [ + "paths" + ], + "properties": { + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "request.FileReadByLineReq": { "type": "object", "required": [ @@ -23261,6 +23757,9 @@ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -24880,6 +25379,9 @@ "editCompose": { "type": "boolean" }, + "gpuConfig": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -24918,6 +25420,9 @@ "github": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -24963,7 +25468,7 @@ "tags": { "type": "array", "items": { - "$ref": "#/definitions/model.Tag" + "$ref": "#/definitions/response.TagDTO" } }, "type": { @@ -25004,6 +25509,9 @@ "enable": { "type": "boolean" }, + "gpuSupport": { + "type": "boolean" + }, "hostMode": { "type": "boolean" }, @@ -25084,6 +25592,9 @@ "description": { "type": "string" }, + "gpuSupport": { + "type": "boolean" + }, "icon": { "type": "string" }, @@ -25239,6 +25750,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 +26687,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" diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index ab2cc1c2c..57149ad69 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -108,6 +108,8 @@ definitions: type: string github: type: string + gpuSupport: + type: boolean key: type: string limit: @@ -261,6 +263,29 @@ definitions: - permission - username type: object + dto.CCConfig: + properties: + action: + type: string + code: + type: integer + duration: + type: integer + ipBlock: + type: string + ipBlockTime: + type: integer + mode: + type: string + res: + type: string + state: + type: string + threshold: + type: integer + type: + type: string + type: object dto.CaptchaResponse: properties: captchaID: @@ -555,6 +580,19 @@ definitions: required: - type type: object + dto.CommonConfig: + properties: + action: + type: string + code: + type: integer + res: + type: string + state: + type: string + type: + type: string + type: object dto.CommonRecover: properties: detailName: @@ -1702,6 +1740,21 @@ definitions: required: - encryptionMode type: object + dto.GeoRestrict: + properties: + action: + type: string + res: + type: string + rules: + items: + type: string + type: array + state: + type: string + type: + type: string + type: object dto.GroupCreate: properties: id: @@ -1991,6 +2044,8 @@ definitions: type: string ja: type: string + ko: + type: string ms: type: string pt-br: @@ -2442,6 +2497,31 @@ definitions: - CACHE - HttpPer - ProxyCache + dto.OllamaBindDomainReq: + properties: + appInstallID: + type: integer + required: + - appInstallID + type: object + dto.OllamaBindDomainRes: + properties: + allowIPs: + items: + type: string + type: array + domain: + type: string + sslID: + type: integer + websiteID: + type: integer + type: object + dto.OllamaModelName: + properties: + name: + type: string + type: object dto.OneDriveInfo: properties: client_id: @@ -3432,6 +3512,11 @@ definitions: upload: type: string type: object + dto.StateConfig: + properties: + state: + type: string + type: object dto.SwapHelper: properties: isNew: @@ -3561,6 +3646,50 @@ definitions: type: type: string type: object + dto.WafConfig: + properties: + mode: + type: string + secret: + type: string + state: + type: string + token: + type: string + required: + - mode + - secret + - state + type: object + dto.WebsiteConfig: + properties: + args: + $ref: '#/definitions/dto.CommonConfig' + cc: + $ref: '#/definitions/dto.CCConfig' + cdn: + $ref: '#/definitions/dto.StateConfig' + cookie: + $ref: '#/definitions/dto.CommonConfig' + defaultUaBlack: + $ref: '#/definitions/dto.CommonConfig' + defaultUrlBlack: + $ref: '#/definitions/dto.CommonConfig' + fileExt: + $ref: '#/definitions/dto.CommonConfig' + geoRestrict: + $ref: '#/definitions/dto.GeoRestrict' + header: + $ref: '#/definitions/dto.CommonConfig' + methodWhite: + $ref: '#/definitions/dto.CommonConfig' + sql: + $ref: '#/definitions/dto.CommonConfig' + waf: + $ref: '#/definitions/dto.WafConfig' + xss: + $ref: '#/definitions/dto.CommonConfig' + type: object dto.XPUInfo: properties: deviceID: @@ -3646,6 +3775,8 @@ definitions: type: string github: type: string + gpuSupport: + type: boolean icon: type: string id: @@ -3778,23 +3909,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 +4104,8 @@ definitions: type: string editCompose: type: boolean + gpuConfig: + type: boolean hostMode: type: boolean memoryLimit: @@ -4099,6 +4215,8 @@ definitions: type: string editCompose: type: boolean + gpuConfig: + type: boolean hostMode: type: boolean installId: @@ -4332,6 +4450,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 +4606,8 @@ definitions: type: string editCompose: type: boolean + gpuConfig: + type: boolean hostMode: type: boolean memoryLimit: @@ -5573,6 +5702,8 @@ definitions: type: string editCompose: type: boolean + gpuConfig: + type: boolean hostMode: type: boolean memoryLimit: @@ -5598,6 +5729,8 @@ definitions: type: string github: type: string + gpuSupport: + type: boolean icon: type: string id: @@ -5628,7 +5761,7 @@ definitions: type: string tags: items: - $ref: '#/definitions/model.Tag' + $ref: '#/definitions/response.TagDTO' type: array type: type: string @@ -5655,6 +5788,8 @@ definitions: type: string enable: type: boolean + gpuSupport: + type: boolean hostMode: type: boolean id: @@ -5708,6 +5843,8 @@ definitions: properties: description: type: string + gpuSupport: + type: boolean icon: type: string id: @@ -5810,6 +5947,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 +6569,159 @@ info: title: 1Panel version: "1.0" paths: + /aitool/domain/bind: + post: + consumes: + - application/json + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.WebsiteConfig' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + - Timestamp: [] + summary: Bind domain + tags: + - AITools + /aitool/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: + - AITools + /aitool/gpu/load: + get: + consumes: + - application/json + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + - Timestamp: [] + summary: Load gpu / xpu info + tags: + - AITools + /aitool/ollama/model/del: + 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: Delete Ollama model + tags: + - AITools + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - name + formatEN: remove Ollama model [name] + formatZH: 删除模型 [name] + paramKeys: [] + /aitools/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: + - AITools + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - name + formatEN: add Ollama model [name] + formatZH: 添加模型 [name] + paramKeys: [] + /aitools/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: + - AITools + /aitools/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: + - AITools /apps/{key}: get: consumes: @@ -10045,6 +10346,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 +16747,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: " - ``` - - `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 diff --git a/frontend/src/api/interface/ai-tool.ts b/frontend/src/api/interface/ai-tool.ts index 32c9125e5..f26e20f0b 100644 --- a/frontend/src/api/interface/ai-tool.ts +++ b/frontend/src/api/interface/ai-tool.ts @@ -79,4 +79,23 @@ export namespace AITool { shr: string; memory: string; } + + export interface BindDomain { + domain: string; + sslID: number; + allowIPs: string[]; + appInstallID: number; + websiteID?: number; + } + + export interface BindDomainReq { + appInstallID: number; + } + + export interface BindDomainRes { + domain: string; + sslID: number; + allowIPs: string[]; + websiteID?: number; + } } diff --git a/frontend/src/api/modules/ai-tool.ts b/frontend/src/api/modules/ai-tool.ts index 1f8878004..c9a3d17a3 100644 --- a/frontend/src/api/modules/ai-tool.ts +++ b/frontend/src/api/modules/ai-tool.ts @@ -18,3 +18,15 @@ export const loadOllamaModel = (name: string) => { export const loadGPUInfo = () => { return http.get(`/aitools/gpu/load`); }; + +export const bindDomain = (req: AITool.BindDomain) => { + return http.post(`/aitools/domain/bind`, req); +}; + +export const getBindDomain = (req: AITool.BindDomainReq) => { + return http.post(`/aitools/domain/get`, req); +}; + +export const updateBindDomain = (req: AITool.BindDomain) => { + return http.post(`/aitools/domain/update`, req); +}; diff --git a/frontend/src/components/app-status/index.vue b/frontend/src/components/app-status/index.vue index e2c4d1ddb..afccdc175 100644 --- a/frontend/src/components/app-status/index.vue +++ b/frontend/src/components/app-status/index.vue @@ -65,6 +65,11 @@ > {{ $t('nginx.clearProxyCache') }} + + + + +
@@ -109,12 +114,13 @@ diff --git a/frontend/src/views/ai-tools/model/index.vue b/frontend/src/views/ai-tools/model/index.vue index 00cceb724..0824f3a41 100644 --- a/frontend/src/views/ai-tools/model/index.vue +++ b/frontend/src/views/ai-tools/model/index.vue @@ -15,9 +15,14 @@ v-model:loading="loading" :hide-setting="true" v-model:mask-show="maskShow" + v-model:appInstallID="appInstallID" @is-exist="checkExist" ref="appStatusRef" - > + > + + @@ -129,11 +135,11 @@ import { AITool } from '@/api/interface/ai-tool'; import { GetAppPort } from '@/api/modules/app'; import router from '@/routers'; import { MsgSuccess } from '@/utils/message'; +import BindDomain from '@/views/ai-tools/model/domain/index.vue'; const globalStore = GlobalStore(); const loading = ref(false); const maskShow = ref(true); - const addRef = ref(); const logRef = ref(); const detailRef = ref(); @@ -141,9 +147,8 @@ const connRef = ref(); const openWebUIPort = ref(); const dashboardVisible = ref(false); const dialogPortJumpRef = ref(); - const appStatusRef = ref(); - +const bindDomainRef = ref(); const data = ref(); const paginationConfig = reactive({ cacheSizeKey: 'model-page-size', @@ -152,6 +157,7 @@ const paginationConfig = reactive({ total: 0, }); const searchName = ref(); +const appInstallID = ref(0); const modelInfo = reactive({ status: '', @@ -209,6 +215,10 @@ const goDashboard = async () => { dialogPortJumpRef.value.acceptParams({ port: openWebUIPort.value }); }; +const bindDomain = () => { + bindDomainRef.value.acceptParams(appInstallID.value); +}; + const goInstall = (name: string) => { router.push({ name: 'AppAll', query: { install: name } }); };