mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-04 18:45:38 +08:00
### What problem does this PR solve? The OpenAI Go driver landed in #14605 with chat, list models, and check connection. Encode was left as a stub that returns \`not implemented\`. \`conf/models/openai.json\` already lists three embedding models out of the box: - text-embedding-ada-002 - text-embedding-3-small - text-embedding-3-large So a tenant who picked one of these in the Go layer could not actually run an embedding call. This PR fills the gap. ### What this PR includes - \`conf/models/openai.json\`: add \`\"embedding\": \"embeddings\"\` under \`url_suffix\` so the driver can build the URL from config. This matches the \`URLSuffix.Embedding\` field used by other drivers (siliconflow, zhipu-ai). - \`internal/entity/models/openai.go\`: replace the Encode stub with a real implementation that POSTs to \`/v1/embeddings\`. Adds a small local response type \`openaiEmbeddingResponse\`. No factory change. No interface change. ### How the implementation works - Validate \`apiConfig\` and the API key, validate the model name. Use the existing \`baseURLForRegion\` helper so an unknown region fails fast with a clear error. - Wrap the request with \`context.WithTimeout(nonStreamCallTimeout)\` so the call has a clear deadline. Same pattern as \`ChatWithMessages\` and \`ListModels\` already use in this file. - Send all input texts in one request. The OpenAI API accepts the \`input\` field as an array. - Parse \`data[*].embedding\` and copy each slice into a \`[][]float64\` indexed by \`data[*].index\` so the output order matches the input order even if the API returns items in a different order. - Handle both \`float64\` and \`float32\` element types, the way the SiliconFlow driver does. - An empty input slice returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks that every input slot got a vector. If any slot is still nil, return a clear error so the caller does not silently use a zero vector. ### Type of change - [x] New Feature (non-breaking change which adds functionality) ### How was this tested? - \`go build ./internal/entity/models/...\` in a clean go 1.25 image (the go.mod minimum) returns exit 0. - The full method set on \`OpenAIModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation (\`internal/entity/models/siliconflow.go\`). Closes #14629 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
74 lines
2.3 KiB
Go
74 lines
2.3 KiB
Go
//
|
|
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
package models
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
// ModelFactory creates ModelDriver instances based on provider name
|
|
type ModelFactory struct {
|
|
}
|
|
|
|
// NewModelFactory creates a new ModelFactory
|
|
func NewModelFactory() *ModelFactory {
|
|
return &ModelFactory{}
|
|
}
|
|
|
|
// CreateModelDriver creates a ModelDriver for the given provider and model
|
|
func (f *ModelFactory) CreateModelDriver(providerName string, baseURL map[string]string, urlSuffix URLSuffix) (ModelDriver, error) {
|
|
providerLower := strings.ToLower(providerName)
|
|
switch providerLower {
|
|
case "zhipu-ai":
|
|
return NewZhipuAIModel(baseURL, urlSuffix), nil
|
|
case "deepseek":
|
|
return NewDeepSeekModel(baseURL, urlSuffix), nil
|
|
case "moonshot":
|
|
return NewMoonshotModel(baseURL, urlSuffix), nil
|
|
case "minimax":
|
|
return NewMinimaxModel(baseURL, urlSuffix), nil
|
|
case "gitee":
|
|
return NewGiteeModel(baseURL, urlSuffix), nil
|
|
case "siliconflow":
|
|
return NewSiliconflowModel(baseURL, urlSuffix), nil
|
|
case "google":
|
|
return NewGoogleModel(baseURL, urlSuffix), nil
|
|
case "aliyun":
|
|
return NewAliyunModel(baseURL, urlSuffix), nil
|
|
case "volcengine":
|
|
return NewVolcEngine(baseURL, urlSuffix), nil
|
|
case "vllm":
|
|
return NewVllmModel(baseURL, urlSuffix), nil
|
|
case "xai":
|
|
return NewXAIModel(baseURL, urlSuffix), nil
|
|
case "lmstudio":
|
|
return NewLmStudioModel(baseURL, urlSuffix), nil
|
|
case "openai":
|
|
return NewOpenAIModel(baseURL, urlSuffix), nil
|
|
case "nvidia":
|
|
return NewNvidiaModel(baseURL, urlSuffix), nil
|
|
case "openrouter":
|
|
return NewOpenRouterModel(baseURL, urlSuffix), nil
|
|
case "huggingface":
|
|
return NewHuggingFaceModel(baseURL, urlSuffix), nil
|
|
case "baidu":
|
|
return NewBaiduModel(baseURL, urlSuffix), nil
|
|
default:
|
|
return NewDummyModel(baseURL, urlSuffix), nil
|
|
}
|
|
}
|