Files
ragflow/internal/entity/models/aliyun.go

676 lines
18 KiB
Go
Raw Normal View History

//
// 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 (
"bufio"
"bytes"
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"ragflow/internal/common"
"strings"
"time"
)
// AliyunModel implements ModelDriver for Aliyun
type AliyunModel struct {
baseModel BaseModel
}
// NewAliyunModel creates a new Aliyun model instance
func NewAliyunModel(baseURL map[string]string, urlSuffix URLSuffix) *AliyunModel {
return &AliyunModel{
baseModel: BaseModel{
BaseURL: baseURL,
URLSuffix: urlSuffix,
httpClient: &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
DisableCompression: false,
},
},
},
}
}
func (a *AliyunModel) NewInstance(baseURL map[string]string) ModelDriver {
return NewAliyunModel(baseURL, a.baseModel.URLSuffix)
}
func (a *AliyunModel) Name() string {
return "aliyun"
}
func (a *AliyunModel) ChatWithMessages(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig) (*ChatResponse, error) {
if err := a.baseModel.APIConfigCheck(apiConfig); err != nil {
return nil, err
}
if len(messages) == 0 {
return nil, fmt.Errorf("messages is empty")
}
resolvedBaseURL, err := a.baseModel.GetBaseURL(apiConfig)
if err != nil {
return nil, err
}
baseURL := resolvedBaseURL
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), a.baseModel.URLSuffix.Chat)
// Convert messages to the format expected by API
apiMessages := make([]map[string]interface{}, len(messages))
for i, msg := range messages {
apiMessages[i] = map[string]interface{}{
"role": msg.Role,
"content": msg.Content,
}
}
// Build request body
reqBody := map[string]interface{}{
"model": modelName,
"messages": apiMessages,
"stream": false,
"temperature": 1,
}
if chatModelConfig != nil {
if chatModelConfig.Stream != nil {
reqBody["stream"] = *chatModelConfig.Stream
}
if chatModelConfig.MaxTokens != nil {
reqBody["max_tokens"] = *chatModelConfig.MaxTokens
}
if chatModelConfig.Temperature != nil {
reqBody["temperature"] = *chatModelConfig.Temperature
}
if chatModelConfig.TopP != nil {
reqBody["top_p"] = *chatModelConfig.TopP
}
if chatModelConfig.Stop != nil {
reqBody["stop"] = *chatModelConfig.Stop
}
if chatModelConfig.Thinking != nil {
if *chatModelConfig.Thinking {
reqBody["enable_thinking"] = true
} else {
reqBody["enable_thinking"] = false
}
}
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), nonStreamCallTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
resp, err := a.baseModel.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var result map[string]interface{}
if err = json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
choices, ok := result["choices"].([]interface{})
if !ok || len(choices) == 0 {
return nil, fmt.Errorf("no choices in response")
}
firstChoice, ok := choices[0].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid choice format")
}
messageMap, ok := firstChoice["message"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid message format")
}
answer, ok := messageMap["content"].(string)
if !ok {
return nil, fmt.Errorf("invalid content format")
}
var reasonContent string
if chatModelConfig != nil && chatModelConfig.Thinking != nil && *chatModelConfig.Thinking {
reasonContent, ok = messageMap["reasoning_content"].(string)
if !ok {
return nil, fmt.Errorf("invalid content format")
}
// if first char of reasonContent is \n remove the '\n'
if reasonContent != "" && reasonContent[0] == '\n' {
reasonContent = reasonContent[1:]
}
}
chatResponse := &ChatResponse{
Answer: &answer,
ReasonContent: &reasonContent,
}
return chatResponse, nil
}
// ChatStreamlyWithSender sends messages and streams response via sender function (best performance, no channel)
func (a *AliyunModel) ChatStreamlyWithSender(modelName string, messages []Message, apiConfig *APIConfig, chatModelConfig *ChatConfig, sender func(*string, *string) error) error {
if err := a.baseModel.APIConfigCheck(apiConfig); err != nil {
return err
}
if len(messages) == 0 {
return fmt.Errorf("messages is empty")
}
resolvedBaseURL, err := a.baseModel.GetBaseURL(apiConfig)
if err != nil {
return err
}
baseURL := resolvedBaseURL
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), a.baseModel.URLSuffix.Chat)
// Convert messages to API format
apiMessages := make([]map[string]interface{}, len(messages))
for i, msg := range messages {
apiMessages[i] = map[string]interface{}{
"role": msg.Role,
"content": msg.Content,
}
}
// Build request body with streaming enabled
reqBody := map[string]interface{}{
"model": modelName,
"messages": apiMessages,
"stream": true,
"temperature": 1,
}
if chatModelConfig.Stream != nil {
reqBody["stream"] = *chatModelConfig.Stream
}
if chatModelConfig.MaxTokens != nil {
reqBody["max_tokens"] = *chatModelConfig.MaxTokens
}
if chatModelConfig.Temperature != nil {
reqBody["temperature"] = *chatModelConfig.Temperature
}
if chatModelConfig.DoSample != nil {
reqBody["do_sample"] = *chatModelConfig.DoSample
}
if chatModelConfig.TopP != nil {
reqBody["top_p"] = *chatModelConfig.TopP
}
if chatModelConfig.Stop != nil {
reqBody["stop"] = *chatModelConfig.Stop
}
if chatModelConfig.Thinking != nil {
if *chatModelConfig.Thinking {
reqBody["enable_thinking"] = true
} else {
reqBody["enable_thinking"] = false
}
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), streamCallTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
resp, err := a.baseModel.httpClient.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
// SSE parsing: read line by line
scanner := bufio.NewScanner(resp.Body)
fix(go-models): raise SSE scanner buffer so large stream chunks are not dropped (#15382) ### Summary Closes #15381 Every provider in `internal/entity/models/` reads its streaming response with `bufio.NewScanner(resp.Body)` and iterates over `scanner.Scan()`. The default `bufio.Scanner` maximum token size is 64KB, so when an upstream sends a single SSE `data:` line larger than 64KB (long content deltas, large tool or function call argument blobs, bundled `reasoning_content`, or providers that emit a whole message in one event) `scanner.Scan()` returns `false` and `scanner.Err()` returns `bufio.ErrTooLong`. Streaming chat then ends with an error partway through the response. This change adds `scanner.Buffer(make([]byte, 64*1024), 1024*1024)` immediately after every SSE scanner that was still bare, raising the cap to 1MB. 1MB is the value already used for streaming chat in `openai.go`, `modelscope.go`, `groq.go`, `mistral.go`, `xai.go` and the other already patched providers (the 8MB cap in the repo is reserved for TTS and embedding paths), so this simply converges the remaining providers onto the established pattern. Nothing else changes: line parsing, `data:` prefix handling, `[DONE]` detection, JSON unmarshalling, error handling, and the existing `scanner.Err()` checks all stay the same. Providers covered (23 scanners across 22 files): 302ai, aliyun, baichuan, baidu, cohere, deepinfra, deepseek, gitee, huggingface, lmstudio, minimax (the chat scanner, whose TTS scanner was already bumped), moonshot, nvidia, ollama, openrouter, orcarouter, paddleocr, siliconflow, tokenhub, vllm, volcengine, xunfei, zhipu-ai. `jiekouai.go` is excluded because it is covered by the in flight #15337. A table driven regression test (`sse_scanner_buffer_test.go`) streams a single 128KB `data:` content delta followed by `data: [DONE]` through an `httptest` server and asserts that `ChatStreamlyWithSender` delivers the full content with no error across a representative subset of providers. Without the buffer fix the test fails with `bufio.Scanner: token too long`. This PR also removes three duplicate declarations of the package level `roundTripperFunc` test helper that several recently merged provider PRs each added independently, which had left the `internal/entity/models` test package unable to compile. The helper now lives in a single place and is shared. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
2026-05-29 07:34:00 -04:00
scanner.Buffer(make([]byte, 64*1024), 1024*1024)
for scanner.Scan() {
line := scanner.Text()
common.Info(line)
// SSE data line starts with "data:"
if !strings.HasPrefix(line, "data:") {
continue
}
// Extract JSON after "data:"
data := strings.TrimSpace(line[5:])
// [DONE] marks the end of stream
if data == "[DONE]" {
break
}
// Parse the JSON event
var event map[string]interface{}
if err = json.Unmarshal([]byte(data), &event); err != nil {
continue
}
choices, ok := event["choices"].([]interface{})
if !ok || len(choices) == 0 {
continue
}
firstChoice, ok := choices[0].(map[string]interface{})
if !ok {
continue
}
delta, ok := firstChoice["delta"].(map[string]interface{})
if !ok {
continue
}
content, ok := delta["content"].(string)
if ok && content != "" {
if err := sender(&content, nil); err != nil {
return err
}
}
reasoningContent, ok := delta["reasoning_content"].(string)
if ok && reasoningContent != "" {
if err := sender(nil, &reasoningContent); err != nil {
return err
}
}
finishReason, ok := firstChoice["finish_reason"].(string)
if ok && finishReason != "" {
break
}
}
// Send [DONE] marker for OpenAI compatibility
endOfStream := "[DONE]"
if err = sender(&endOfStream, nil); err != nil {
return err
}
return scanner.Err()
}
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
type aliyunEmbeddingResponse struct {
Data []EmbeddingData `json:"data"`
Model string `json:"model"`
Object string `json:"object"`
Usage aliyunUsage `json:"usage"`
ID string `json:"id"`
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
}
type aliyunEmbeddingData struct {
Embedding []float64 `json:"embedding"`
Index int `json:"index"`
Object string `json:"object"`
}
type aliyunUsage struct {
PromptTokens int `json:"prompt_tokens"`
TotalTokens int `json:"total_tokens"`
}
// Embed embeds a list of texts into embeddings
func (a *AliyunModel) Embed(modelName *string, texts []string, apiConfig *APIConfig, embeddingConfig *EmbeddingConfig) ([]EmbeddingData, error) {
if err := a.baseModel.APIConfigCheck(apiConfig); err != nil {
return nil, err
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
}
if len(texts) == 0 {
return []EmbeddingData{}, nil
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
}
if modelName == nil || *modelName == "" {
return nil, fmt.Errorf("model name is required")
}
resolvedBaseURL, err := a.baseModel.GetBaseURL(apiConfig)
if err != nil {
return nil, err
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
}
baseURL := resolvedBaseURL
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), a.baseModel.URLSuffix.Embedding)
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
reqBody := map[string]interface{}{
"model": *modelName,
"input": texts,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), nonStreamCallTimeout)
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
defer cancel()
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
resp, err := a.baseModel.httpClient.Do(req)
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Aliyun embeddings API error: %s, body: %s", resp.Status, string(body))
}
var parsed aliyunEmbeddingResponse
if err = json.Unmarshal(body, &parsed); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
var embeddings []EmbeddingData
for _, dataElem := range parsed.Data {
var embeddingData EmbeddingData
embeddingData.Embedding = dataElem.Embedding
embeddingData.Index = dataElem.Index
embeddings = append(embeddings, embeddingData)
Go: implement Encode (embeddings) in Aliyun driver (#14647) ### What problem does this PR solve? The Aliyun Go driver shipped with a stub \`Encode\` method that returned \`no such method\`, even though \`conf/models/aliyun.json\` already wires the OpenAI-compatible embeddings URL suffix at \`compatible-mode/v1/embeddings\`. The same config also did not list any embedding models, so the picker had nothing to select. So an Aliyun tenant who wanted to use Tongyi text-embedding-v3 or v4 in the Go layer could not, even though the upstream endpoint is public and uses the standard \`POST /v1/embeddings\` shape that the SiliconFlow and ZhipuAI drivers already support. This PR fills the gap. ### What this PR includes - \`conf/models/aliyun.json\`: add \`text-embedding-v4\` and \`text-embedding-v3\` to the \`models\` array. - \`internal/entity/models/aliyun.go\`: replace the \`Encode\` stub with a real implementation. Adds a small local response type that matches the OpenAI-compatible shape. No factory change. No interface change. ### How the driver works - Validate \`apiConfig\` and the API key, validate the model name, resolve the region with a default fallback, build the URL from \`BaseURL[region] + URLSuffix.Embedding\`. - Send all input texts in one request as the \`input\` array, the same OpenAI-compatible shape the SiliconFlow \`Encode\` uses. - 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. - Empty input returns \`[][]float64{}\` with no HTTP call. - Non-200 responses propagate the upstream status line and body. - A final pass checks every input slot got a vector and returns a clear error if any slot is still nil. ### 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 returns exit 0. - The full method set on \`AliyunModel\` still matches the \`ModelDriver\` interface. - Pattern parity with the existing SiliconFlow Encode implementation. Closes #14646 --------- Co-authored-by: Jin Hai <haijin.chn@gmail.com>
2026-05-08 07:58:25 +02:00
}
return embeddings, nil
}
type aliyunRerankRequest struct {
Model string `json:"model"`
Query string `json:"query"`
Documents []string `json:"documents"`
TopN int `json:"top_n"`
ReturnDocuments bool `json:"return_documents"`
}
type aliyunRerankResponse struct {
Results []struct {
Index int `json:"index"`
RelevanceScore float64 `json:"relevance_score"`
} `json:"results"`
}
func (a *AliyunModel) Rerank(modelName *string, query string, documents []string, apiConfig *APIConfig, rerankConfig *RerankConfig) (*RerankResponse, error) {
if err := a.baseModel.APIConfigCheck(apiConfig); err != nil {
return nil, err
}
if len(documents) == 0 {
return &RerankResponse{}, nil
}
if modelName == nil || *modelName == "" {
return nil, fmt.Errorf("model name is required")
}
resolvedBaseURL, err := a.baseModel.GetBaseURL(apiConfig)
if err != nil {
return nil, err
}
baseURL := resolvedBaseURL
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), a.baseModel.URLSuffix.Rerank)
var topN = rerankConfig.TopN
if rerankConfig.TopN == 0 {
topN = len(documents)
}
reqBody := aliyunRerankRequest{
Model: *modelName,
Query: query,
Documents: documents,
TopN: topN,
ReturnDocuments: false,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), nonStreamCallTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
resp, err := a.baseModel.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Aliyun rerank API error: %s, body: %s", resp.Status, string(body))
}
var rerankResponse RerankResponse
if err = json.Unmarshal(body, &rerankResponse); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
return &rerankResponse, nil
}
// TranscribeAudio transcribe audio
func (a *AliyunModel) TranscribeAudio(modelName *string, file *string, apiConfig *APIConfig, asrConfig *ASRConfig) (*ASRResponse, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
}
func (a *AliyunModel) TranscribeAudioWithSender(modelName *string, file *string, apiConfig *APIConfig, asrConfig *ASRConfig, sender func(*string, *string) error) error {
return fmt.Errorf("%s, no such method", a.Name())
}
Go: implement PaddleOCR provider and implement ASR for CoHere (#14954) ### What problem does this PR solve? This PR implement implement OCR for Baidu and Mistral, implement PaddleOCR provider and implement ASR for CoHere **Verified examples from the CLI:** ``` RAGFlow(user)> ocr with 'mistral-ocr-2512@test@mistral' file './internal/text.jpg' +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | text | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Parallel to these organizational innovations there were significant complementary technical innovations (e.g., improved methods of manufacturing cast-iron pipe and of coating interiors for pressure maintenance, and newer paving and construction material... | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ RAGFlow(user)> ocr with 'paddleocr-vl-0.9b@test@baidu' file './internal/text.jpg' +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | text | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Parallel to these organizational innovations there were significant complementary technical innovations (e.g., improved methods of manufacturing cast-iron pipe and of coating interiors for pressure maintenance, and newer paving and construction material... | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ # PaddleOCR RAGFlow(user)> ocr with 'PaddleOCR-VL-1.5@test@paddleocr' file './internal/test.pdf' +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | text | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | # Repurposing Diffusion-Based Image Generators for Monocular Depth Estimation Bingxin Ke Nando Metzger Photogra Anton Obukhov Rodrigo Caye Daudt netry and Remote Sensing, Shengyu Huang Konrad Schindler ETH Zürich <div style="text-align: c... | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ # Cohere RAGFlow(user)> asr with 'cohere-transcribe-03-2026@test@cohere' audio './internal/test.wav' param '{"language": "en"}' +-----------------------------------------------------------------------------------------------------------------------+ | text | +-----------------------------------------------------------------------------------------------------------------------+ | The examination and testimony of the experts enabled the Commission to conclude that five shots may have been fired. | +-----------------------------------------------------------------------------------------------------------------------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) - [x] Refactoring
2026-05-15 18:41:43 +08:00
// AudioSpeech convert text to audio
func (a *AliyunModel) AudioSpeech(modelName *string, audioContent *string, apiConfig *APIConfig, ttsConfig *TTSConfig) (*TTSResponse, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
}
func (a *AliyunModel) AudioSpeechWithSender(modelName *string, audioContent *string, apiConfig *APIConfig, ttsConfig *TTSConfig, sender func(*string, *string) error) error {
return fmt.Errorf("%s, no such method", a.Name())
}
// OCRFile OCR file
func (a *AliyunModel) OCRFile(modelName *string, content []byte, url *string, apiConfig *APIConfig, ocrConfig *OCRConfig) (*OCRFileResponse, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
Go: add file parse command (#14892) ### What problem does this PR solve? ``` RAGFlow(user)> ocr with 'hunyuanocr@test@gitee' file './picture.png' +----------------------------------------------------------+ | text | +----------------------------------------------------------+ | 生活不是等待风暴过去,而是学会在雨中翩翩起舞。 ——佚名 | +----------------------------------------------------------+ RAGFlow(user)> list 'test@gitee' tasks; +---------+----------------------------------+ | status | task_id | +---------+----------------------------------+ | success | C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5 | +---------+----------------------------------+ RAGFlow(user)> show 'test@gitee' task 'C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5'; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | content | index | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | # PDF 1: Purpose of RAGFlow RAGFlow is an open source Retrieval-Augmented Generation (RAG) engine designed to turn raw documents into reliable context for large language models.Its purpose is to make it practical to build an Al assistant that can ans... | 1 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-05-15 12:29:52 +08:00
}
// ParseFile parse file
func (a *AliyunModel) ParseFile(modelName *string, content []byte, url *string, apiConfig *APIConfig, parseFileConfig *ParseFileConfig) (*ParseFileResponse, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
}
type AliyunModelItem struct {
ModelName string `json:"model_name"`
BaseCapacity int `json:"base_capacity"`
}
type AliyunModelOutput struct {
Models []AliyunModelItem `json:"models"`
PageNo int `json:"page_no"`
PageSize int `json:"page_size"`
Total int `json:"total"`
}
type AliyunModelList struct {
RequestID string `json:"request_id"`
Output AliyunModelOutput `json:"output"`
}
func (a *AliyunModel) ListModels(apiConfig *APIConfig) ([]ListModelResponse, error) {
if err := a.baseModel.APIConfigCheck(apiConfig); err != nil {
return nil, err
}
resolvedBaseURL, err := a.baseModel.GetBaseURL(apiConfig)
if err != nil {
return nil, err
}
baseURL := resolvedBaseURL
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), a.baseModel.URLSuffix.Models)
// Build request body
reqBody := map[string]interface{}{}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), nonStreamCallTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
resp, err := a.baseModel.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var modelList AliyunModelList
if err = json.Unmarshal(body, &modelList); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
var models []ListModelResponse
for _, model := range modelList.Output.Models {
modelName := model.ModelName
models = append(models, ListModelResponse{
Name: modelName,
})
}
return models, nil
}
func (a *AliyunModel) Balance(apiConfig *APIConfig) (map[string]interface{}, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
}
func (a *AliyunModel) CheckConnection(apiConfig *APIConfig) error {
_, err := a.ListModels(apiConfig)
if err != nil {
return err
}
return nil
}
Go: add file parse command (#14892) ### What problem does this PR solve? ``` RAGFlow(user)> ocr with 'hunyuanocr@test@gitee' file './picture.png' +----------------------------------------------------------+ | text | +----------------------------------------------------------+ | 生活不是等待风暴过去,而是学会在雨中翩翩起舞。 ——佚名 | +----------------------------------------------------------+ RAGFlow(user)> list 'test@gitee' tasks; +---------+----------------------------------+ | status | task_id | +---------+----------------------------------+ | success | C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5 | +---------+----------------------------------+ RAGFlow(user)> show 'test@gitee' task 'C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5'; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | content | index | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | # PDF 1: Purpose of RAGFlow RAGFlow is an open source Retrieval-Augmented Generation (RAG) engine designed to turn raw documents into reliable context for large language models.Its purpose is to make it practical to build an Al assistant that can ans... | 1 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-05-15 12:29:52 +08:00
func (a *AliyunModel) ListTasks(apiConfig *APIConfig) ([]ListTaskStatus, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
Go: add file parse command (#14892) ### What problem does this PR solve? ``` RAGFlow(user)> ocr with 'hunyuanocr@test@gitee' file './picture.png' +----------------------------------------------------------+ | text | +----------------------------------------------------------+ | 生活不是等待风暴过去,而是学会在雨中翩翩起舞。 ——佚名 | +----------------------------------------------------------+ RAGFlow(user)> list 'test@gitee' tasks; +---------+----------------------------------+ | status | task_id | +---------+----------------------------------+ | success | C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5 | +---------+----------------------------------+ RAGFlow(user)> show 'test@gitee' task 'C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5'; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | content | index | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | # PDF 1: Purpose of RAGFlow RAGFlow is an open source Retrieval-Augmented Generation (RAG) engine designed to turn raw documents into reliable context for large language models.Its purpose is to make it practical to build an Al assistant that can ans... | 1 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-05-15 12:29:52 +08:00
}
func (a *AliyunModel) ShowTask(taskID string, apiConfig *APIConfig) (*TaskResponse, error) {
return nil, fmt.Errorf("%s, no such method", a.Name())
Go: add file parse command (#14892) ### What problem does this PR solve? ``` RAGFlow(user)> ocr with 'hunyuanocr@test@gitee' file './picture.png' +----------------------------------------------------------+ | text | +----------------------------------------------------------+ | 生活不是等待风暴过去,而是学会在雨中翩翩起舞。 ——佚名 | +----------------------------------------------------------+ RAGFlow(user)> list 'test@gitee' tasks; +---------+----------------------------------+ | status | task_id | +---------+----------------------------------+ | success | C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5 | +---------+----------------------------------+ RAGFlow(user)> show 'test@gitee' task 'C3FX4MQNKY5MGC6ZFMIXIAMJKHCEBQB5'; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | content | index | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ | # PDF 1: Purpose of RAGFlow RAGFlow is an open source Retrieval-Augmented Generation (RAG) engine designed to turn raw documents into reliable context for large language models.Its purpose is to make it practical to build an Al assistant that can ans... | 1 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-05-15 12:29:52 +08:00
}