fix: fix issue with enable ai https failed (#8109)

This commit is contained in:
zhengkunwang 2025-03-10 17:29:01 +08:00 committed by GitHub
parent cd019750b4
commit c3ab1bde7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 88 additions and 38 deletions

View file

@ -84,8 +84,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"`

View file

@ -3,6 +3,7 @@ package repo
import (
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
"gorm.io/gorm"
)
type GroupRepo struct{}
@ -13,12 +14,19 @@ type IGroupRepo interface {
Create(group *model.Group) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
WithByDefault(isDefault bool) DBOption
}
func NewIGroupRepo() IGroupRepo {
return &GroupRepo{}
}
func (g *GroupRepo) WithByDefault(isDefault bool) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("is_default = ?", isDefault)
}
}
func (g *GroupRepo) Get(opts ...DBOption) (model.Group, error) {
var group model.Group
db := global.DB

View file

@ -266,6 +266,8 @@ func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error {
createWebsiteReq.WebsiteSSLID = req.SSLID
createWebsiteReq.EnableSSL = true
}
res, _ := NewIGroupService().GetDefault()
createWebsiteReq.WebsiteGroupID = res.ID
websiteService := NewIWebsiteService()
if err = websiteService.CreateWebsite(createWebsiteReq); err != nil {
return err
@ -334,9 +336,9 @@ func (u *AIToolService) UpdateBindDomain(req dto.OllamaBindDomain) error {
sslReq := request.WebsiteHTTPSOp{
WebsiteID: website.ID,
Enable: true,
Type: "existed",
Type: constant.SSLExisted,
WebsiteSSLID: req.SSLID,
HttpConfig: "HTTPSOnly",
HttpConfig: constant.HTTPToHTTPS,
}
if _, err = websiteService.OpWebsiteHTTPS(context.Background(), sslReq); err != nil {
return err
@ -371,7 +373,7 @@ func loadModelSize(name string, containerName string) (string, error) {
if err != nil {
return "", err
}
lines := strings.Split(string(stdout), "\n")
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 5 {
@ -379,5 +381,5 @@ func loadModelSize(name string, containerName string) (string, error) {
}
return parts[2] + " " + parts[3], nil
}
return "", fmt.Errorf("no such model %s in ollama list, std: %s", name, string(stdout))
return "", fmt.Errorf("no such model %s in ollama list, std: %s", name, stdout)
}

View file

@ -15,6 +15,7 @@ type IGroupService interface {
Create(req dto.GroupCreate) error
Update(req dto.GroupUpdate) error
Delete(id uint) error
GetDefault() (model.Group, error)
}
func NewIGroupService() IGroupService {
@ -85,3 +86,7 @@ func (u *GroupService) Update(req dto.GroupUpdate) error {
upMap["is_default"] = req.IsDefault
return groupRepo.Update(req.ID, upMap)
}
func (u *GroupService) GetDefault() (model.Group, error) {
return groupRepo.Get(groupRepo.WithByDefault(true))
}

View file

@ -1019,6 +1019,10 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
dto.NginxParam{
Name: "http2",
},
dto.NginxParam{
Name: "add_header",
Params: []string{"Strict-Transport-Security"},
},
)
if err = deleteNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
return nil, err

View file

@ -448,7 +448,7 @@ func (w WebsiteSSLService) Delete(ids []uint) error {
if err != nil {
return err
}
if websiteSSL.Type != constant.Manual && websiteSSL.Type != constant.SelfSigned {
if websiteSSL.Provider != constant.Manual && websiteSSL.Provider != constant.SelfSigned {
acmeAccount, err := websiteAcmeRepo.GetFirst(repo.WithByID(websiteSSL.AcmeAccountID))
if err != nil {
return err

View file

@ -680,9 +680,15 @@ func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.W
}
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 {

View file

@ -596,6 +596,25 @@ const checkPhone = (rule: any, value: any, callback: any) => {
}
};
export function checkMaxLength(maxLength: number): FormItemRule {
return {
required: false,
trigger: 'blur',
type: 'string',
validator: (rule: any, value: any, callback: any) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
if (value.length > maxLength) {
callback(new Error(i18n.global.t('commons.rule.maxLength', [maxLength])));
} else {
callback();
}
}
},
};
}
interface CommonRule {
requiredInput: FormItemRule;
requiredSelect: FormItemRule;

View file

@ -249,6 +249,7 @@ const message = {
phone: 'The format of the phone number is incorrect',
authBasicPassword: 'Supports letters, numbers, and common special characters, length 1-72',
length128Err: 'Length cannot exceed 128 characters',
maxLength: 'Length cannot exceed {0} characters',
},
res: {
paramError: 'The request failed, please try again later!',

View file

@ -240,6 +240,7 @@ const message = {
phone: '電話番号の形式は正しくありません',
authBasicPassword: '英字数字一般的な特殊文字をサポート長さ1-72',
length128Err: '長さは128文字を超えることはできません',
maxLength: '長さは {0} 文字を超えることはできません',
},
res: {
paramError: 'リクエストが失敗しました後でもう一度やり直してください',

View file

@ -242,6 +242,7 @@ const message = {
phone: '전화번호 형식이 올바르지 않습니다',
authBasicPassword: '알파벳, 숫자 일반 특수 문자 지원, 길이 1-72',
length128Err: '길이는 128자를 초과할 없습니다',
maxLength: '길이는 {0}자를 초과할 없습니다',
},
res: {
paramError: '요청이 실패했습니다. 나중에 다시 시도하세요!',

View file

@ -248,6 +248,7 @@ const message = {
phone: 'Format nombor telefon tidak betul.',
authBasicPassword: 'Menyokong huruf, nombor, dan aksara khas biasa, panjang 1-72',
length128Err: 'Panjang tidak boleh melebihi 128 aksara',
maxLength: 'Panjang tidak boleh melebihi {0} aksara',
},
res: {
paramError: 'Permintaan gagal, sila cuba lagi nanti!',

View file

@ -246,6 +246,7 @@ const message = {
phone: 'O formato do número de telefone está incorreto',
authBasicPassword: 'Suporta letras, números e caracteres especiais comuns, comprimento 1-72',
length128Err: 'O comprimento não pode exceder 128 caracteres',
maxLength: 'O comprimento não pode exceder {0} caracteres',
},
res: {
paramError: 'A solicitação falhou, por favor, tente novamente mais tarde!',

View file

@ -243,6 +243,7 @@ const message = {
phone: 'Неверный формат номера телефона',
authBasicPassword: 'Поддерживает буквы, цифры и общие специальные символы, длина 1-72',
length128Err: 'Длина не может превышать 128 символов',
maxLength: 'Длина не может превышать {0} символов',
},
res: {
paramError: 'Запрос не удался, попробуйте позже!',

View file

@ -242,6 +242,7 @@ const message = {
phone: '手機號碼格式不正確',
authBasicPassword: '支持字母數字以及常見特殊字符長度1-72',
length128Err: '長度不能超過128位',
maxLength: '長度不能超過 {0} ',
},
res: {
paramError: '請求失敗,請稍後重試!',

View file

@ -240,6 +240,7 @@ const message = {
phone: '手机号码格式不正确',
authBasicPassword: '支持字母数字以及常见特殊字符长度1-72',
length128Err: '长度不能超过128位',
maxLength: '长度不能超过 {0} ',
},
res: {
paramError: '请求失败,请稍后重试!',

View file

@ -1,31 +1,27 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('aiTools.model.create')" @close="handleClose">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-alert type="info" :closable="false">
<template #title>
<span class="flx-align-center">
{{ $t('aiTools.model.ollama_doc') }}
<el-button link class="ml-5" icon="Position" @click="goSearch()" type="primary">
{{ $t('firewall.quickJump') }}
</el-button>
</span>
</template>
</el-alert>
<el-form ref="formRef" label-position="top" class="mt-5" :model="form">
<el-form-item :label="$t('commons.table.name')" :rules="Rules.requiredInput" prop="name">
<el-input v-model.trim="form.name" />
<span class="input-help" v-if="form.name">
{{
$t('aiTools.model.create_helper', [
form.name.replaceAll('ollama run ', '').replaceAll('ollama pull ', ''),
])
}}
</span>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-alert type="info" :closable="false">
<template #title>
<span class="flx-align-center">
{{ $t('aiTools.model.ollama_doc') }}
<el-button link class="ml-5" icon="Position" @click="goSearch()" type="primary">
{{ $t('firewall.quickJump') }}
</el-button>
</span>
</template>
</el-alert>
<el-form ref="formRef" label-position="top" class="mt-5" :model="form">
<el-form-item :label="$t('commons.table.name')" :rules="Rules.requiredInput" prop="name">
<el-input v-model.trim="form.name" />
<span class="input-help" v-if="form.name">
{{
$t('aiTools.model.create_helper', [
form.name.replaceAll('ollama run ', '').replaceAll('ollama pull ', ''),
])
}}
</span>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisible = false">

View file

@ -75,7 +75,7 @@
<script lang="ts" setup>
import { obtainSSLByCA } from '@/api/modules/website';
import { Rules, checkNumberRange } from '@/global/form-rules';
import { Rules, checkNumberRange, checkMaxLength } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
@ -93,6 +93,7 @@ const rules = ref({
dir: [Rules.requiredInput],
time: [Rules.integerNumber, checkNumberRange(1, 10000)],
shell: [Rules.requiredInput],
description: [checkMaxLength(128)],
});
const initData = () => ({

View file

@ -152,7 +152,7 @@
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { createSSL, listWebsites, searchAcmeAccount, searchDnsAccount, updateSSL } from '@/api/modules/website';
import { Rules } from '@/global/form-rules';
import { Rules, checkMaxLength } from '@/global/form-rules';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import { computed, reactive, ref } from 'vue';
@ -196,6 +196,7 @@ const rules = ref({
nameserver1: [Rules.ipv4],
nameserver2: [Rules.ipv4],
shell: [Rules.requiredInput],
description: [checkMaxLength(128)],
});
const websiteID = ref();

View file

@ -108,7 +108,7 @@
<template #default="{ row }">
<fu-read-write-switch>
<template #read>
<MsgInfo :info="row.description" width="180px" />
<MsgInfo :info="row.description" width="200" />
</template>
<template #default="{ read }">
<el-input v-model="row.description" @blur="updateDesc(row, read)" />

View file

@ -554,7 +554,7 @@ import { reactive, ref } from 'vue';
import Params from '@/views/app-store/detail/params/index.vue';
import Check from '../check/index.vue';
import { MsgError, MsgSuccess } from '@/utils/message';
import { getGroupList } from '@/api/modules/group';
import { getAgentGroupList } from '@/api/modules/group';
import { Group } from '@/api/interface/group';
import { SearchRuntimes } from '@/api/modules/runtime';
import { Runtime } from '@/api/interface/runtime';
@ -836,7 +836,7 @@ const acceptParams = async () => {
staticPath.value = res.data + '/sites/';
});
const res = await getGroupList('website');
const res = await getAgentGroupList('website');
groups.value = res.data;
website.value.webSiteGroupId = res.data[0].id;
website.value.type = 'deployment';