feat: model configuration and embedding configuration optimization. (#2414)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
Ryo
2025-10-30 14:05:23 +08:00
committed by GitHub
parent 7335e0a24c
commit b3d6357bbd
19 changed files with 309 additions and 112 deletions

View File

@ -132,13 +132,28 @@ func UpdateKnowledgeConfig(ctx context.Context, c *app.RequestContext) {
return
}
if req.KnowledgeConfig.EmbeddingConfig == nil {
invalidParamRequestResponse(c, "EmbeddingConfig is nil")
return
}
if req.KnowledgeConfig.EmbeddingConfig.Connection == nil {
invalidParamRequestResponse(c, "Connection is nil")
return
}
if req.KnowledgeConfig.EmbeddingConfig.Connection.EmbeddingInfo == nil {
invalidParamRequestResponse(c, "EmbeddingInfo is nil")
return
}
embedding, err := impl.GetEmbedding(ctx, req.KnowledgeConfig.EmbeddingConfig)
if err != nil {
invalidParamRequestResponse(c, fmt.Sprintf("get embedding failed: %v", err))
return
}
if req.KnowledgeConfig.EmbeddingConfig.Connection.EmbeddingInfo.Dims == 0 {
if req.KnowledgeConfig.EmbeddingConfig.Connection.EmbeddingInfo.Dims <= 0 {
req.KnowledgeConfig.EmbeddingConfig.Connection.EmbeddingInfo.Dims = int32(embedding.Dimensions())
embedding, err = impl.GetEmbedding(ctx, req.KnowledgeConfig.EmbeddingConfig)

View File

@ -59,6 +59,58 @@ func (p *ModelType) Value() (driver.Value, error) {
return int64(*p), nil
}
type ThinkingType int64
const (
ThinkingType_Default ThinkingType = 0
ThinkingType_Enable ThinkingType = 1
ThinkingType_Disable ThinkingType = 2
ThinkingType_Auto ThinkingType = 3
)
func (p ThinkingType) String() string {
switch p {
case ThinkingType_Default:
return "Default"
case ThinkingType_Enable:
return "Enable"
case ThinkingType_Disable:
return "Disable"
case ThinkingType_Auto:
return "Auto"
}
return "<UNSET>"
}
func ThinkingTypeFromString(s string) (ThinkingType, error) {
switch s {
case "Default":
return ThinkingType_Default, nil
case "Enable":
return ThinkingType_Enable, nil
case "Disable":
return ThinkingType_Disable, nil
case "Auto":
return ThinkingType_Auto, nil
}
return ThinkingType(0), fmt.Errorf("not a valid ThinkingType string")
}
func ThinkingTypePtr(v ThinkingType) *ThinkingType { return &v }
func (p *ThinkingType) Scan(value interface{}) (err error) {
var result sql.NullInt64
err = result.Scan(value)
*p = ThinkingType(result.Int64)
return
}
func (p *ThinkingType) Value() (driver.Value, error) {
if p == nil {
return nil, nil
}
return int64(*p), nil
}
type ModelStatus int64
const (
@ -2913,9 +2965,10 @@ func (p *Connection) String() string {
}
type BaseConnectionInfo struct {
BaseURL string `thrift:"base_url,1" form:"base_url" json:"base_url" query:"base_url"`
APIKey string `thrift:"api_key,2" form:"api_key" json:"api_key" query:"api_key"`
Model string `thrift:"model,3" form:"model" json:"model" query:"model"`
BaseURL string `thrift:"base_url,1" form:"base_url" json:"base_url" query:"base_url"`
APIKey string `thrift:"api_key,2" form:"api_key" json:"api_key" query:"api_key"`
Model string `thrift:"model,3" form:"model" json:"model" query:"model"`
ThinkingType ThinkingType `thrift:"thinking_type,4" form:"thinking_type" json:"thinking_type" query:"thinking_type"`
}
func NewBaseConnectionInfo() *BaseConnectionInfo {
@ -2937,10 +2990,15 @@ func (p *BaseConnectionInfo) GetModel() (v string) {
return p.Model
}
func (p *BaseConnectionInfo) GetThinkingType() (v ThinkingType) {
return p.ThinkingType
}
var fieldIDToName_BaseConnectionInfo = map[int16]string{
1: "base_url",
2: "api_key",
3: "model",
4: "thinking_type",
}
func (p *BaseConnectionInfo) Read(iprot thrift.TProtocol) (err error) {
@ -2985,6 +3043,14 @@ func (p *BaseConnectionInfo) Read(iprot thrift.TProtocol) (err error) {
} else if err = iprot.Skip(fieldTypeId); err != nil {
goto SkipFieldError
}
case 4:
if fieldTypeId == thrift.I32 {
if err = p.ReadField4(iprot); err != nil {
goto ReadFieldError
}
} else if err = iprot.Skip(fieldTypeId); err != nil {
goto SkipFieldError
}
default:
if err = iprot.Skip(fieldTypeId); err != nil {
goto SkipFieldError
@ -3047,6 +3113,17 @@ func (p *BaseConnectionInfo) ReadField3(iprot thrift.TProtocol) error {
p.Model = _field
return nil
}
func (p *BaseConnectionInfo) ReadField4(iprot thrift.TProtocol) error {
var _field ThinkingType
if v, err := iprot.ReadI32(); err != nil {
return err
} else {
_field = ThinkingType(v)
}
p.ThinkingType = _field
return nil
}
func (p *BaseConnectionInfo) Write(oprot thrift.TProtocol) (err error) {
var fieldId int16
@ -3066,6 +3143,10 @@ func (p *BaseConnectionInfo) Write(oprot thrift.TProtocol) (err error) {
fieldId = 3
goto WriteFieldError
}
if err = p.writeField4(oprot); err != nil {
fieldId = 4
goto WriteFieldError
}
}
if err = oprot.WriteFieldStop(); err != nil {
goto WriteFieldStopError
@ -3132,6 +3213,22 @@ WriteFieldBeginError:
WriteFieldEndError:
return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err)
}
func (p *BaseConnectionInfo) writeField4(oprot thrift.TProtocol) (err error) {
if err = oprot.WriteFieldBegin("thinking_type", thrift.I32, 4); err != nil {
goto WriteFieldBeginError
}
if err := oprot.WriteI32(int32(p.ThinkingType)); err != nil {
return err
}
if err = oprot.WriteFieldEnd(); err != nil {
goto WriteFieldEndError
}
return nil
WriteFieldBeginError:
return thrift.PrependError(fmt.Sprintf("%T write field 4 begin error: ", p), err)
WriteFieldEndError:
return thrift.PrependError(fmt.Sprintf("%T write field 4 end error: ", p), err)
}
func (p *BaseConnectionInfo) String() string {
if p == nil {
@ -3465,9 +3562,8 @@ func (p *ArkConnInfo) String() string {
}
type OpenAIConnInfo struct {
RequestDims int32 `thrift:"request_dims,5" form:"request_dims" json:"request_dims" query:"request_dims"`
ByAzure bool `thrift:"by_azure,6" form:"by_azure" json:"by_azure" query:"by_azure"`
APIVersion string `thrift:"api_version,7" form:"api_version" json:"api_version" query:"api_version"`
ByAzure bool `thrift:"by_azure,6" form:"by_azure" json:"by_azure" query:"by_azure"`
APIVersion string `thrift:"api_version,7" form:"api_version" json:"api_version" query:"api_version"`
}
func NewOpenAIConnInfo() *OpenAIConnInfo {
@ -3477,10 +3573,6 @@ func NewOpenAIConnInfo() *OpenAIConnInfo {
func (p *OpenAIConnInfo) InitDefault() {
}
func (p *OpenAIConnInfo) GetRequestDims() (v int32) {
return p.RequestDims
}
func (p *OpenAIConnInfo) GetByAzure() (v bool) {
return p.ByAzure
}
@ -3490,7 +3582,6 @@ func (p *OpenAIConnInfo) GetAPIVersion() (v string) {
}
var fieldIDToName_OpenAIConnInfo = map[int16]string{
5: "request_dims",
6: "by_azure",
7: "api_version",
}
@ -3513,14 +3604,6 @@ func (p *OpenAIConnInfo) Read(iprot thrift.TProtocol) (err error) {
}
switch fieldId {
case 5:
if fieldTypeId == thrift.I32 {
if err = p.ReadField5(iprot); err != nil {
goto ReadFieldError
}
} else if err = iprot.Skip(fieldTypeId); err != nil {
goto SkipFieldError
}
case 6:
if fieldTypeId == thrift.BOOL {
if err = p.ReadField6(iprot); err != nil {
@ -3566,17 +3649,6 @@ ReadStructEndError:
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
}
func (p *OpenAIConnInfo) ReadField5(iprot thrift.TProtocol) error {
var _field int32
if v, err := iprot.ReadI32(); err != nil {
return err
} else {
_field = v
}
p.RequestDims = _field
return nil
}
func (p *OpenAIConnInfo) ReadField6(iprot thrift.TProtocol) error {
var _field bool
@ -3606,10 +3678,6 @@ func (p *OpenAIConnInfo) Write(oprot thrift.TProtocol) (err error) {
goto WriteStructBeginError
}
if p != nil {
if err = p.writeField5(oprot); err != nil {
fieldId = 5
goto WriteFieldError
}
if err = p.writeField6(oprot); err != nil {
fieldId = 6
goto WriteFieldError
@ -3636,22 +3704,6 @@ WriteStructEndError:
return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err)
}
func (p *OpenAIConnInfo) writeField5(oprot thrift.TProtocol) (err error) {
if err = oprot.WriteFieldBegin("request_dims", thrift.I32, 5); err != nil {
goto WriteFieldBeginError
}
if err := oprot.WriteI32(p.RequestDims); err != nil {
return err
}
if err = oprot.WriteFieldEnd(); err != nil {
goto WriteFieldEndError
}
return nil
WriteFieldBeginError:
return thrift.PrependError(fmt.Sprintf("%T write field 5 begin error: ", p), err)
WriteFieldEndError:
return thrift.PrependError(fmt.Sprintf("%T write field 5 end error: ", p), err)
}
func (p *OpenAIConnInfo) writeField6(oprot thrift.TProtocol) (err error) {
if err = oprot.WriteFieldBegin("by_azure", thrift.BOOL, 6); err != nil {
goto WriteFieldBeginError

View File

@ -1,4 +1,4 @@
// Code generated by thriftgo (0.4.1). DO NOT EDIT.
// Code generated by thriftgo (0.4.2). DO NOT EDIT.
package conversation

View File

@ -1,4 +1,4 @@
// Code generated by thriftgo (0.4.1). DO NOT EDIT.
// Code generated by thriftgo (0.4.2). DO NOT EDIT.
package conversation

View File

@ -82,9 +82,8 @@ func getKnowledgeConfigurationFromOldConfig() *config.KnowledgeConfig {
APIType: envkey.GetStringD("ARK_EMBEDDING_API_TYPE", "text_api"),
},
Openai: &config.OpenAIConnInfo{
ByAzure: envkey.GetBoolD("OPENAI_EMBEDDING_BY_AZURE", false),
APIVersion: envkey.GetString("OPENAI_EMBEDDING_API_VERSION"),
RequestDims: envkey.GetI32D("OPENAI_EMBEDDING_REQUEST_DIMS", 1024),
ByAzure: envkey.GetBoolD("OPENAI_EMBEDDING_BY_AZURE", false),
APIVersion: envkey.GetString("OPENAI_EMBEDDING_API_VERSION"),
},
Gemini: &config.GeminiConnInfo{

View File

@ -33,7 +33,7 @@ type arkModelBuilder struct {
cfg *config.Model
}
func newArkModelBuilder(cfg *config.Model) *arkModelBuilder {
func newArkModelBuilder(cfg *config.Model) Service {
return &arkModelBuilder{
cfg: cfg,
}
@ -84,6 +84,21 @@ func (b *arkModelBuilder) Build(ctx context.Context, params *LLMParams) (ToolCal
chatModelConf.BaseURL = base.BaseURL
}
switch base.ThinkingType {
case config.ThinkingType_Enable:
chatModelConf.Thinking = &model.Thinking{
Type: model.ThinkingTypeEnabled,
}
case config.ThinkingType_Disable:
chatModelConf.Thinking = &model.Thinking{
Type: model.ThinkingTypeDisabled,
}
case config.ThinkingType_Auto:
chatModelConf.Thinking = &model.Thinking{
Type: model.ThinkingTypeAuto,
}
}
arkConn := b.cfg.Connection.Ark
if arkConn != nil {
chatModelConf.Region = arkConn.Region

View File

@ -28,7 +28,7 @@ type claudeModelBuilder struct {
cfg *config.Model
}
func newClaudeModelBuilder(cfg *config.Model) *claudeModelBuilder {
func newClaudeModelBuilder(cfg *config.Model) Service {
return &claudeModelBuilder{
cfg: cfg,
}
@ -71,6 +71,17 @@ func (c *claudeModelBuilder) Build(ctx context.Context, params *LLMParams) (Tool
conf.BaseURL = &base.BaseURL
}
switch base.ThinkingType {
case config.ThinkingType_Enable:
conf.Thinking = &claude.Thinking{
Enable: true,
}
case config.ThinkingType_Disable:
conf.Thinking = &claude.Thinking{
Enable: false,
}
}
c.applyParamsToChatModelConfig(conf, params)
return claude.NewChatModel(ctx, conf)

View File

@ -29,7 +29,7 @@ type deepseekModelBuilder struct {
cfg *config.Model
}
func newDeepseekModelBuilder(cfg *config.Model) *deepseekModelBuilder {
func newDeepseekModelBuilder(cfg *config.Model) Service {
return &deepseekModelBuilder{
cfg: cfg,
}

View File

@ -30,7 +30,7 @@ type geminiModelBuilder struct {
cfg *config.Model
}
func newGeminiModelBuilder(cfg *config.Model) *geminiModelBuilder {
func newGeminiModelBuilder(cfg *config.Model) Service {
return &geminiModelBuilder{
cfg: cfg,
}
@ -67,7 +67,6 @@ func (g *geminiModelBuilder) applyParamsToGeminiConfig(conf *gemini.Config, para
if params.EnableThinking != nil {
conf.ThinkingConfig = &genai.ThinkingConfig{
IncludeThoughts: *params.EnableThinking,
ThinkingBudget: nil,
}
}
}
@ -96,6 +95,17 @@ func (g *geminiModelBuilder) Build(ctx context.Context, params *LLMParams) (Tool
conf.Client = client
conf.Model = base.Model
switch base.ThinkingType {
case config.ThinkingType_Enable:
conf.ThinkingConfig = &genai.ThinkingConfig{
IncludeThoughts: true,
}
case config.ThinkingType_Disable:
conf.ThinkingConfig = &genai.ThinkingConfig{
IncludeThoughts: false,
}
}
g.applyParamsToGeminiConfig(conf, params)
return gemini.NewChatModel(ctx, conf)

View File

@ -39,6 +39,16 @@ type Service interface {
Build(ctx context.Context, params *LLMParams) (ToolCallingChatModel, error)
}
var modelClass2NewModelBuilder = map[developer_api.ModelClass]func(*config.Model) Service{
developer_api.ModelClass_SEED: newArkModelBuilder,
developer_api.ModelClass_GPT: newOpenaiModelBuilder,
developer_api.ModelClass_Claude: newClaudeModelBuilder,
developer_api.ModelClass_DeekSeek: newDeepseekModelBuilder,
developer_api.ModelClass_Gemini: newGeminiModelBuilder,
developer_api.ModelClass_Llama: newOllamaModelBuilder,
developer_api.ModelClass_QWen: newQwenModelBuilder,
}
func NewModelBuilder(modelClass developer_api.ModelClass, cfg *config.Model) (Service, error) {
if cfg == nil {
return nil, fmt.Errorf("model config is nil")
@ -52,37 +62,18 @@ func NewModelBuilder(modelClass developer_api.ModelClass, cfg *config.Model) (Se
return nil, fmt.Errorf("model base connection is nil")
}
switch modelClass {
case developer_api.ModelClass_SEED:
return newArkModelBuilder(cfg), nil
case developer_api.ModelClass_GPT:
return newOpenaiModelBuilder(cfg), nil
case developer_api.ModelClass_Claude:
return newClaudeModelBuilder(cfg), nil
case developer_api.ModelClass_DeekSeek:
return newDeepseekModelBuilder(cfg), nil
case developer_api.ModelClass_Gemini:
return newGeminiModelBuilder(cfg), nil
case developer_api.ModelClass_Llama:
return newOllamaModelBuilder(cfg), nil
case developer_api.ModelClass_QWen:
return newQwenModelBuilder(cfg), nil
default:
buildFn, ok := modelClass2NewModelBuilder[modelClass]
if !ok {
return nil, fmt.Errorf("model class %v not supported", modelClass)
}
return buildFn(cfg), nil
}
func SupportProtocol(modelClass developer_api.ModelClass) bool {
if modelClass == developer_api.ModelClass_GPT ||
modelClass == developer_api.ModelClass_Claude ||
modelClass == developer_api.ModelClass_DeekSeek ||
modelClass == developer_api.ModelClass_SEED ||
modelClass == developer_api.ModelClass_Gemini ||
modelClass == developer_api.ModelClass_Llama ||
modelClass == developer_api.ModelClass_QWen {
return true
}
return false
_, ok := modelClass2NewModelBuilder[modelClass]
return ok
}
// BuildModelWithConf for create model scene, params is nil

View File

@ -30,7 +30,7 @@ type ollamaModelBuilder struct {
cfg *config.Model
}
func newOllamaModelBuilder(cfg *config.Model) *ollamaModelBuilder {
func newOllamaModelBuilder(cfg *config.Model) Service {
return &ollamaModelBuilder{
cfg: cfg,
}
@ -84,6 +84,17 @@ func (o *ollamaModelBuilder) Build(ctx context.Context, params *LLMParams) (Tool
}
conf.Model = base.Model
switch base.ThinkingType {
case config.ThinkingType_Enable:
conf.Thinking = &api.ThinkValue{
Value: ptr.Of(true),
}
case config.ThinkingType_Disable:
conf.Thinking = &api.ThinkValue{
Value: ptr.Of(false),
}
}
o.applyParamsToOllamaConfig(conf, params)
return ollama.NewChatModel(ctx, conf)

View File

@ -30,7 +30,7 @@ type openaiModelBuilder struct {
cfg *config.Model
}
func newOpenaiModelBuilder(cfg *config.Model) *openaiModelBuilder {
func newOpenaiModelBuilder(cfg *config.Model) Service {
return &openaiModelBuilder{
cfg: cfg,
}

View File

@ -30,7 +30,7 @@ type qwenModelBuilder struct {
cfg *config.Model
}
func newQwenModelBuilder(cfg *config.Model) *qwenModelBuilder {
func newQwenModelBuilder(cfg *config.Model) Service {
return &qwenModelBuilder{
cfg: cfg,
}
@ -82,6 +82,13 @@ func (q *qwenModelBuilder) Build(ctx context.Context, params *LLMParams) (ToolCa
conf.BaseURL = base.BaseURL
conf.Model = base.Model
switch base.ThinkingType {
case config.ThinkingType_Enable:
conf.EnableThinking = ptr.Of(true)
case config.ThinkingType_Disable:
conf.EnableThinking = ptr.Of(false)
}
q.applyParamsToQwenConfig(conf, params)
return qwen.NewChatModel(ctx, conf)

View File

@ -653,6 +653,11 @@
'model.field.azure': 'By Azure',
'model.field.api_version': 'API Version',
'model.field.endpoint': '接口地址',
'model.field.thinking_type': 'Thinking Type',
'model.thinking_type.default': 'Default',
'model.thinking_type.enable': 'Enable',
'model.thinking_type.disable': 'Disable',
'model.thinking_type.auto': 'Auto',
'model.error.load_list_failed': '加载模型列表失败',
'model.error.render_page_failed': '渲染模型页面失败',
@ -694,6 +699,10 @@
'model.modal.gemini_project.placeholder': '选填例如my-project',
'model.modal.gemini_location.label': 'Location',
'model.modal.gemini_location.placeholder': '选填例如us-central1',
'model.modal.thinking_type.label': 'Thinking Type',
'model.modal.thinking_type.enable': 'Enable',
'model.modal.thinking_type.disable': 'Disable',
'model.modal.thinking_type.auto': 'Auto',
// 知识库配置
'knowledge.error.load_failed_json': '加载知识库配置失败: 返回结果不是有效 JSON',
@ -868,6 +877,11 @@
'model.field.azure': 'By Azure',
'model.field.api_version': 'API Version',
'model.field.endpoint': 'Endpoint',
'model.field.thinking_type': 'Thinking Type',
'model.thinking_type.default': 'Default',
'model.thinking_type.enable': 'Enable',
'model.thinking_type.disable': 'Disable',
'model.thinking_type.auto': 'Auto',
'model.error.load_list_failed': 'Failed to load model list',
'model.error.render_page_failed': 'Failed to render model page',
@ -909,6 +923,10 @@
'model.modal.gemini_project.placeholder': 'Optional, e.g., my-project',
'model.modal.gemini_location.label': 'Location',
'model.modal.gemini_location.placeholder': 'Optional, e.g., us-central1',
'model.modal.thinking_type.label': 'Thinking Type',
'model.modal.thinking_type.enable': 'Enable',
'model.modal.thinking_type.disable': 'Disable',
'model.modal.thinking_type.auto': 'Auto',
// Knowledge Config
'knowledge.error.load_failed_json': 'Load knowledge config failed: invalid JSON response',
@ -2014,6 +2032,17 @@
return s.slice(0, 6) + '***' + s.slice(-4);
}
function getThinkingTypeText(thinkingTypeValue) {
const thinkingType = Number(thinkingTypeValue);
switch (thinkingType) {
case 0: return t('model.thinking_type.default');
case 1: return t('model.thinking_type.enable');
case 2: return t('model.thinking_type.disable');
case 3: return t('model.thinking_type.auto');
default: return '-';
}
}
function renderModelManagement(payload) {
try {
const providers = Array.isArray(payload?.provider_model_list) ? payload.provider_model_list : [];
@ -2070,6 +2099,12 @@
<input id="newModelGeminiProject" type="text" style="padding:8px;border:1px solid #e1e8ed;border-radius:8px;width:100%;display:none;" placeholder="${t('model.modal.gemini_project.placeholder')}">
<label id="newModelGeminiLocationLabel" style="font-size:12px;color:#374151;display:none;">${t('model.modal.gemini_location.label')}</label>
<input id="newModelGeminiLocation" type="text" style="padding:8px;border:1px solid #e1e8ed;border-radius:8px;width:100%;display:none;" placeholder="${t('model.modal.gemini_location.placeholder')}">
<label id="newModelThinkingTypeLabel" style="font-size:12px;color:#374151;display:none;">${t('model.modal.thinking_type.label')}</label>
<select id="newModelThinkingType" style="padding:8px;border:1px solid #e1e8ed;border-radius:8px;width:100%;display:none;">
<option value="2" selected>${t('model.modal.thinking_type.disable')}</option>
<option value="1">${t('model.modal.thinking_type.enable')}</option>
<option id="thinkingTypeAutoOption" value="3" style="display:none;">${t('model.modal.thinking_type.auto')}</option>
</select>
</div>
<div style="padding:12px 20px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #f1f3f4;">
<button onclick="closeAddModelModal()" style="background:#ecf0f1;color:#2c3e50;border:none;padding:8px 12px;border-radius:6px;cursor:pointer;">${t('common.cancel')}</button>
@ -2124,6 +2159,7 @@
<div>${t('model.field.model')}${conn.model || '-'}</div>
${p?.model_class === 20 ? '' : `<div>${t('model.field.api_key')}${apiKeyMasked}</div>`}
<div>${t('model.field.base64_url')}${m.enable_base64_url ? t('common.on') : t('common.off')}</div>
${[2, 3, 11, 15, 20].includes(p?.model_class) ? `<div>${t('model.field.thinking_type')}${getThinkingTypeText(conn.thinking_type ?? 0)}</div>` : ''}
${p?.model_class === 2 ? `<div>${t('model.field.region')}${m?.connection?.ark?.region || ''}</div>` : ''}
${p?.model_class === 11 ? `<div>${t('model.field.backend')}${m?.connection?.gemini?.backend ?? ''}</div><div>${t('model.field.project')}${m?.connection?.gemini?.project || ''}</div><div>${t('model.field.location')}${m?.connection?.gemini?.location || ''}</div>` : ''}
${p?.model_class === 1 ? `<div>${t('model.field.azure')}${(m?.connection?.openai?.by_azure === undefined) ? '' : (m?.connection?.openai?.by_azure ? 'true' : 'false')}</div><div>${t('model.field.api_version')}${m?.connection?.openai?.api_version || ''}</div>` : ''}
@ -2241,6 +2277,20 @@
if (geminiProjectInput) geminiProjectInput.style.display = isGemini ? '' : 'none';
if (geminiLocationLabel) geminiLocationLabel.style.display = isGemini ? '' : 'none';
if (geminiLocationInput) geminiLocationInput.style.display = isGemini ? '' : 'none';
// Show/hide ThinkingType dropdown
const thinkingTypeLabel = document.getElementById('newModelThinkingTypeLabel');
const thinkingTypeSelect = document.getElementById('newModelThinkingType');
const thinkingTypeAutoOption = document.getElementById('thinkingTypeAutoOption');
const hasThinkingType = [2, 3, 11, 15, 20].includes(providerClass); // Ark, Claude, Gemini, Qwen, Ollama
const isArkProvider = providerClass === 2;
if (thinkingTypeLabel) thinkingTypeLabel.style.display = hasThinkingType ? '' : 'none';
if (thinkingTypeSelect) {
thinkingTypeSelect.style.display = hasThinkingType ? '' : 'none';
thinkingTypeSelect.value = '2'; // Reset to Disable
}
if (thinkingTypeAutoOption) thinkingTypeAutoOption.style.display = isArkProvider ? '' : 'none';
modal.style.display = 'flex';
}
function closeAddModelModal() {
@ -2286,6 +2336,16 @@
const baseConn = { model: model };
if (baseUrl) baseConn.base_url = baseUrl;
if (requireApiKey && apiKey) baseConn.api_key = apiKey;
// 读取 ThinkingType仅 Ark, Claude, Gemini, Qwen, Ollama
const thinkingTypeSelect = document.getElementById('newModelThinkingType');
const hasThinkingType = [2, 3, 11, 15, 20].includes(providerClass);
if (hasThinkingType && thinkingTypeSelect) {
const thinkingTypeValue = parseInt(thinkingTypeSelect.value, 10);
if (!Number.isNaN(thinkingTypeValue)) {
baseConn.thinking_type = thinkingTypeValue;
}
}
// 读取“启用 Base64 URL”复选框默认 false
const enableBase64UrlEl = document.getElementById('newModelEnableBase64Url');
const enableBase64Url = !!(enableBase64UrlEl && enableBase64UrlEl.checked);
@ -2463,7 +2523,6 @@
openai_api_key: baseConn?.api_key || '',
openai_model: baseConn?.model || '',
openai_embedding_dims: embeddingInfo?.dims ?? '0',
openai_embedding_request_dims: conn?.openai?.embedding_request_dims ?? conn?.openai?.request_dims ?? '',
openai_embedding_by_azure: Boolean(conn?.openai?.embedding_by_azure ?? conn?.openai?.by_azure),
openai_embedding_api_version: conn?.openai?.embedding_api_version ?? conn?.openai?.api_version ?? '',
ollama_base_url: baseConn?.base_url || '',
@ -2623,7 +2682,7 @@
</div>
<div>
<div style="${labelStyle}">Dims</div>
<input id="kb_ark_embedding_dims" type="number" style="${inputStyle}" value="${initial.ark_embedding_dims}" />
<input id="kb_ark_embedding_dims" type="number" min="0" style="${inputStyle}" value="${initial.ark_embedding_dims}" />
</div>
<div>
<div style="${labelStyle}">API Type</div>
@ -2653,7 +2712,7 @@
</div>
<div>
<div style="${labelStyle}">Dims</div>
<input id="kb_openai_embedding_dims" type="number" style="${inputStyle}" value="${initial.openai_embedding_dims}" />
<input id="kb_openai_embedding_dims" type="number" min="0" style="${inputStyle}" value="${initial.openai_embedding_dims}" />
</div>
<!-- 选填字段靠后显示By Azure、API Version、Request Dims -->
<div>
@ -2664,10 +2723,6 @@
<div style="${labelStyle}">Embedding API Version</div>
<input id="kb_openai_embedding_api_version" type="text" style="${inputStyle}" value="${initial.openai_embedding_api_version}" />
</div>
<div>
<div style="${labelStyle}">Embedding Request Dims</div>
<input id="kb_openai_embedding_request_dims" type="number" style="${inputStyle}" value="${initial.openai_embedding_request_dims}" />
</div>
</div>
</div>
@ -2684,7 +2739,7 @@
</div>
<div>
<div style="${labelStyle}">Dims</div>
<input id="kb_ollama_embedding_dims" type="number" style="${inputStyle}" value="${initial.ollama_embedding_dims}" />
<input id="kb_ollama_embedding_dims" type="number" min="0" style="${inputStyle}" value="${initial.ollama_embedding_dims}" />
</div>
</div>
</div>
@ -2711,7 +2766,7 @@
</div>
<div>
<div style="${labelStyle}">Dims</div>
<input id="kb_gemini_embedding_dims" type="number" style="${inputStyle}" value="${initial.gemini_embedding_dims}" />
<input id="kb_gemini_embedding_dims" type="number" min="0" style="${inputStyle}" value="${initial.gemini_embedding_dims}" />
</div>
<div>
<div style="${labelStyle}">Project</div>
@ -2733,7 +2788,7 @@
</div>
<div>
<div style="${labelStyle}">Dims</div>
<input id="kb_http_dims" type="number" style="${inputStyle}" value="${initial.http_dims}" />
<input id="kb_http_dims" type="number" min="0" style="${inputStyle}" value="${initial.http_dims}" />
</div>
</div>
</div>
@ -3065,7 +3120,6 @@
api_type: val('kb_ark_embedding_api_type')
},
openai: {
request_dims: toNum(val('kb_openai_embedding_request_dims')),
by_azure: checked('kb_openai_embedding_by_azure'),
api_version: val('kb_openai_embedding_api_version')
},
@ -3113,13 +3167,22 @@
// Embedding 必填项校验(不同类型不同必填要求)
const typeVal = Number(document.getElementById('kb_embedding_type')?.value);
const get = (id) => (document.getElementById(id)?.value || '').trim();
const getDims = (id) => {
const el = document.getElementById(id);
return el ? Number(el.value) : 0;
};
if (typeVal === 0) {
// Ark: Base URL、API Key、Model、Dims 必填API Type 可选
const dimsVal = Number(document.getElementById('kb_ark_embedding_dims')?.value);
const dimsVal = getDims('kb_ark_embedding_dims');
const missing = [];
if (!get('kb_ark_base_url')) missing.push('Base URL');
if (!get('kb_ark_api_key')) missing.push('API Key');
if (!get('kb_ark_model')) missing.push('Model');
if (dimsVal < 0) {
showError('Dims must be >= 0');
return;
}
if (missing.length > 0) {
showError(t('error.missing_required', { list: missing.join(', ') }));
@ -3127,43 +3190,59 @@
}
} else if (typeVal === 1) {
// OpenAI: Base URL、Model、API Key、Dims 必填
const dimsVal = Number(document.getElementById('kb_openai_embedding_dims')?.value);
const dimsVal = getDims('kb_openai_embedding_dims');
const missing = [];
if (!get('kb_openai_base_url')) missing.push('Base URL');
if (!get('kb_openai_model')) missing.push('Model');
if (!get('kb_openai_api_key')) missing.push('API Key');
if (dimsVal < 0) {
showError('Dims must be >= 0');
return;
}
if (missing.length > 0) {
showError(t('error.missing_required', { list: missing.join(', ') }));
return;
}
} else if (typeVal === 2) {
// Ollama: Base URL、Model、Dims 必填
const dimsVal = Number(document.getElementById('kb_ollama_embedding_dims')?.value);
const dimsVal = getDims('kb_ollama_embedding_dims');
const missing = [];
if (!get('kb_ollama_base_url')) missing.push('Base URL');
if (!get('kb_ollama_model')) missing.push('Model');
if (dimsVal < 0) {
showError('Dims must be >= 0');
return;
}
if (missing.length > 0) {
showError(t('error.missing_required', { list: missing.join(', ') }));
return;
}
} else if (typeVal === 3) {
// Gemini: Base URL、API Key、Model、Dims、Backend 必填Project、Location 选填
const dimsVal = Number(document.getElementById('kb_gemini_embedding_dims')?.value);
const dimsVal = getDims('kb_gemini_embedding_dims');
const backendStr = (document.getElementById('kb_gemini_embedding_backend')?.value || '').trim();
const missing = [];
if (!get('kb_gemini_base_url')) missing.push('Base URL');
if (!get('kb_gemini_api_key')) missing.push('API Key');
if (!get('kb_gemini_model')) missing.push('Model');
if (!backendStr) missing.push('Backend');
if (dimsVal < 0) {
showError('Dims must be >= 0');
return;
}
if (missing.length > 0) {
showError(t('error.missing_required', { list: missing.join(', ') }));
return;
}
} else if (typeVal === 4) {
// HTTP: Address、Dims 必填
const dimsVal = Number(document.getElementById('kb_http_dims')?.value);
const dimsVal = getDims('kb_http_dims');
const missing = [];
if (!get('kb_http_address')) missing.push('Address');
if (dimsVal < 0) {
showError('Dims must be >= 0');
return;
}
if (missing.length > 0) {
showError(t('error.missing_required', { list: missing.join(', ') }));
return;

View File

@ -92,7 +92,7 @@ func (d *embWrap) EmbedStringsHybrid(ctx context.Context, texts []string, opts .
}
func (d *embWrap) Dimensions() int64 {
if d.dims == 0 {
if d.dims <= 0 {
embeddings, err := d.Embedder.EmbedStrings(context.Background(), []string{"test"})
if err != nil {
return 0

View File

@ -195,7 +195,7 @@ func (e *embedder) do(req *http.Request) (*embedResp, error) {
}
func (e *embedder) Dimensions() int64 {
if e.dim == 0 {
if e.dim <= 0 {
embeddings, err := e.EmbedStrings(context.Background(), []string{"test"})
if err != nil {
return 0

View File

@ -52,9 +52,9 @@ func GetEmbedding(ctx context.Context, cfg *config.EmbeddingConfig) (embedding.E
APIVersion: openaiConnCfg.APIVersion,
}
if openaiConnCfg.RequestDims > 0 {
if embeddingInfo.Dims > 0 {
// some openai model not support request dims
openAICfg.Dimensions = ptr.Of(int(openaiConnCfg.RequestDims))
openAICfg.Dimensions = ptr.Of(int(embeddingInfo.Dims))
}
emb, err = wrap.NewOpenAIEmbedder(ctx, openAICfg, int64(embeddingInfo.Dims), int(cfg.MaxBatchSize))

View File

@ -49,7 +49,7 @@ func (d *denseOnlyWrap) EmbedStringsHybrid(ctx context.Context, texts []string,
}
func (d *denseOnlyWrap) Dimensions() int64 {
if d.dims == 0 {
if d.dims <= 0 {
embeddings, err := d.Embedder.EmbedStrings(context.Background(), []string{"test"})
if err != nil {
return 0