mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-01 03:24:14 +08:00
295 lines
7.9 KiB
Go
295 lines
7.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
|
"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"
|
|
)
|
|
|
|
type AIToolService struct{}
|
|
|
|
type IAIToolService interface {
|
|
Search(search dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error)
|
|
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 {
|
|
return &AIToolService{}
|
|
}
|
|
|
|
func (u *AIToolService) Search(req dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error) {
|
|
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
if ollamaBaseInfo.Status != constant.Running {
|
|
return 0, nil, nil
|
|
}
|
|
stdout, err := cmd.Execf("docker exec %s ollama list", ollamaBaseInfo.ContainerName)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
var list []dto.OllamaModelInfo
|
|
modelMaps := make(map[string]struct{})
|
|
lines := strings.Split(stdout, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 5 {
|
|
continue
|
|
}
|
|
if parts[0] == "NAME" {
|
|
continue
|
|
}
|
|
modelMaps[strings.ReplaceAll(parts[0], ":", "-")] = struct{}{}
|
|
list = append(list, dto.OllamaModelInfo{Name: parts[0], Size: parts[2] + " " + parts[3], Modified: strings.Join(parts[4:], " ")})
|
|
}
|
|
entries, _ := os.ReadDir(path.Join(global.CONF.System.DataDir, "log", "AITools"))
|
|
for _, item := range entries {
|
|
if _, ok := modelMaps[item.Name()]; ok {
|
|
continue
|
|
}
|
|
if _, ok := modelMaps[item.Name()+":latest"]; ok {
|
|
continue
|
|
}
|
|
list = append(list, dto.OllamaModelInfo{Name: item.Name(), Size: "-", Modified: "-"})
|
|
}
|
|
if len(req.Info) != 0 {
|
|
length, count := len(list), 0
|
|
for count < length {
|
|
if !strings.Contains(list[count].Name, req.Info) {
|
|
list = append(list[:count], list[(count+1):]...)
|
|
length--
|
|
} else {
|
|
count++
|
|
}
|
|
}
|
|
}
|
|
|
|
var records []dto.OllamaModelInfo
|
|
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
|
if start > total {
|
|
records = make([]dto.OllamaModelInfo, 0)
|
|
} else {
|
|
if end >= total {
|
|
end = total
|
|
}
|
|
records = list[start:end]
|
|
}
|
|
return int64(total), records, err
|
|
}
|
|
|
|
func (u *AIToolService) LoadDetail(name string) (string, error) {
|
|
if cmd.CheckIllegal(name) {
|
|
return "", buserr.New(constant.ErrCmdIllegal)
|
|
}
|
|
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if ollamaBaseInfo.Status != constant.Running {
|
|
return "", nil
|
|
}
|
|
stdout, err := cmd.Execf("docker exec %s ollama show %s", ollamaBaseInfo.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)
|
|
}
|
|
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ollamaBaseInfo.Status != constant.Running {
|
|
return nil
|
|
}
|
|
fileName := strings.ReplaceAll(name, ":", "-")
|
|
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", fileName)
|
|
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 func() {
|
|
defer file.Close()
|
|
cmd := exec.Command("docker", "exec", ollamaBaseInfo.ContainerName, "ollama", "run", name)
|
|
multiWriter := io.MultiWriter(os.Stdout, file)
|
|
cmd.Stdout = multiWriter
|
|
cmd.Stderr = multiWriter
|
|
if err := cmd.Run(); err != nil {
|
|
global.LOG.Errorf("ollama pull %s failed, err: %v", name, err)
|
|
_, _ = file.WriteString("ollama pull failed!")
|
|
return
|
|
}
|
|
global.LOG.Infof("ollama pull %s successful!", name)
|
|
_, _ = file.WriteString("ollama pull successful!")
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *AIToolService) Delete(name string) error {
|
|
if cmd.CheckIllegal(name) {
|
|
return buserr.New(constant.ErrCmdIllegal)
|
|
}
|
|
ollamaBaseInfo, err := appInstallRepo.LoadBaseInfo("ollama", "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ollamaBaseInfo.Status != constant.Running {
|
|
return nil
|
|
}
|
|
stdout, err := cmd.Execf("docker exec %s ollama list", ollamaBaseInfo.ContainerName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
isExist := false
|
|
lines := strings.Split(stdout, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 5 {
|
|
continue
|
|
}
|
|
if parts[0] == "NAME" {
|
|
continue
|
|
}
|
|
if parts[0] == name {
|
|
isExist = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if isExist {
|
|
stdout, err := cmd.Execf("docker exec %s ollama rm %s", ollamaBaseInfo.ContainerName, name)
|
|
if err != nil {
|
|
return fmt.Errorf("handle ollama rm %s failed, stdout: %s, err: %v", name, stdout, err)
|
|
}
|
|
}
|
|
logItem := path.Join(global.CONF.System.DataDir, "log", "AITools", name)
|
|
_ = os.Remove(logItem)
|
|
logItem2 := path.Join(global.CONF.System.DataDir, "log", "AITools", strings.TrimSuffix(name, ":latest"))
|
|
if logItem2 != logItem {
|
|
_ = os.Remove(logItem2)
|
|
}
|
|
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
|
|
}
|