feat: add FuturMix as model provider (#14419)

## Summary

Add [FuturMix](https://futurmix.ai) as a new model provider. FuturMix is
an OpenAI-compatible unified AI gateway that provides access to 22+
models (GPT, Claude, Gemini, DeepSeek, and more) through a single API
endpoint and key.

- **API Base**: `https://futurmix.ai/v1` (OpenAI-compatible)
- **Supported capabilities**: Chat, Embedding, Image2Text, TTS,
Speech2Text, Rerank

### Changes

| File | Change |
|------|--------|
| `rag/llm/__init__.py` | Add `FuturMix` to `SupportedLiteLLMProvider`
enum, `FACTORY_DEFAULT_BASE_URL`, and `LITELLM_PROVIDER_PREFIX` |
| `rag/llm/chat_model.py` | Add `FuturMixChat(Base)` — follows
Astraflow/Avian pattern |
| `rag/llm/embedding_model.py` | Add `FuturMixEmbed(OpenAIEmbed)` —
follows Astraflow pattern |
| `rag/llm/cv_model.py` | Add `FuturMixCV(GptV4)` — follows
SILICONFLOW/OpenRouter pattern |
| `rag/llm/tts_model.py` | Add `FuturMixTTS(OpenAITTS)` — follows
CometAPI/DeerAPI pattern |
| `rag/llm/sequence2txt_model.py` | Add `FuturMixSeq2txt(GPTSeq2txt)` —
follows StepFun pattern |
| `rag/llm/rerank_model.py` | Add `FuturMixRerank(OpenAI_APIRerank)` |
| `conf/llm_factories.json` | Add factory config with 8 chat, 2
embedding, 1 image2text, 2 TTS, 1 speech2text models |
| `docs/guides/models/supported_models.mdx` | Add FuturMix to supported
models table |

### Models included

- **Chat**: claude-sonnet-4-20250514, claude-3.5-haiku, gpt-4o,
gpt-4o-mini, gemini-2.5-flash, gemini-2.0-flash, deepseek-chat,
deepseek-reasoner
- **Embedding**: text-embedding-3-small, text-embedding-3-large
- **Image2Text**: gpt-4o
- **TTS**: tts-1, tts-1-hd
- **Speech2Text**: whisper-1

## Test plan

- [ ] Verify FuturMix appears in the model provider list in RAGFlow UI
- [ ] Configure FuturMix with API key and test chat completion
- [ ] Test embedding model with document indexing
- [ ] Test image2text with a sample image

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
FuturMix
2026-04-30 10:59:37 +08:00
committed by GitHub
parent ce4c782fd7
commit 2548c28d65
9 changed files with 184 additions and 1 deletions

View File

@@ -6457,6 +6457,121 @@
}
]
},
{
"name": "FuturMix",
"logo": "",
"tags": "LLM,TEXT EMBEDDING,IMAGE2TEXT,SPEECH2TEXT,TTS,TEXT RE-RANK",
"status": "1",
"rank": "248",
"url": "https://futurmix.ai/v1",
"llm": [
{
"llm_name": "claude-sonnet-4-20250514",
"tags": "LLM,CHAT,200k",
"max_tokens": 200000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "claude-3.5-haiku",
"tags": "LLM,CHAT,200k",
"max_tokens": 200000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "gpt-4o",
"tags": "LLM,CHAT,128k",
"max_tokens": 128000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "gpt-4o-mini",
"tags": "LLM,CHAT,128k",
"max_tokens": 128000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "gemini-2.5-flash",
"tags": "LLM,CHAT,1M",
"max_tokens": 1000000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "gemini-2.0-flash",
"tags": "LLM,CHAT,1M",
"max_tokens": 1000000,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "deepseek-chat",
"tags": "LLM,CHAT,64k",
"max_tokens": 65536,
"model_type": "chat",
"is_tools": true
},
{
"llm_name": "deepseek-reasoner",
"tags": "LLM,CHAT,64k",
"max_tokens": 65536,
"model_type": "chat",
"is_tools": false
},
{
"llm_name": "gpt-4o",
"tags": "IMAGE2TEXT,CHAT,128k",
"max_tokens": 128000,
"model_type": "image2text",
"is_tools": true
},
{
"llm_name": "text-embedding-3-small",
"tags": "TEXT EMBEDDING,8K",
"max_tokens": 8191,
"model_type": "embedding",
"is_tools": false
},
{
"llm_name": "text-embedding-3-large",
"tags": "TEXT EMBEDDING,8K",
"max_tokens": 8191,
"model_type": "embedding",
"is_tools": false
},
{
"llm_name": "tts-1",
"tags": "TTS",
"max_tokens": 4096,
"model_type": "tts",
"is_tools": false
},
{
"llm_name": "tts-1-hd",
"tags": "TTS",
"max_tokens": 4096,
"model_type": "tts",
"is_tools": false
},
{
"llm_name": "whisper-1",
"tags": "SPEECH2TEXT",
"max_tokens": 25000000,
"model_type": "speech2text",
"is_tools": false
},
{
"llm_name": "jina-reranker-v2-base-multilingual",
"tags": "RE-RANK,8k",
"max_tokens": 8192,
"model_type": "rerank",
"is_tools": false
}
]
},
{
"name": "Astraflow-CN",
"logo": "",
@@ -6691,4 +6806,4 @@
]
}
]
}
}

View File

@@ -28,6 +28,7 @@ A complete list of models supported by RAGFlow, which will continue to expand.
| Cohere | :heavy_check_mark: | :heavy_check_mark: | | | :heavy_check_mark: | :heavy_check_mark: | |
| DeepSeek | :heavy_check_mark: | | | | | | |
| Fish Audio | | | | :heavy_check_mark: | | | |
| FuturMix | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Gemini | :heavy_check_mark: | :heavy_check_mark: | | | :heavy_check_mark: | | |
| Google Cloud | :heavy_check_mark: | | | | | | |
| GPUStack | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |

View File

@@ -61,6 +61,7 @@ class SupportedLiteLLMProvider(StrEnum):
Avian = "Avian"
Astraflow = "Astraflow"
Astraflow_CN = "Astraflow-CN"
FuturMix = "FuturMix"
FACTORY_DEFAULT_BASE_URL = {
@@ -91,6 +92,7 @@ FACTORY_DEFAULT_BASE_URL = {
SupportedLiteLLMProvider.Avian: "https://api.avian.io/v1",
SupportedLiteLLMProvider.Astraflow: "https://api-us-ca.umodelverse.ai/v1",
SupportedLiteLLMProvider.Astraflow_CN: "https://api.modelverse.cn/v1",
SupportedLiteLLMProvider.FuturMix: "https://futurmix.ai/v1",
}
@@ -133,6 +135,7 @@ LITELLM_PROVIDER_PREFIX = {
SupportedLiteLLMProvider.Avian: "openai/",
SupportedLiteLLMProvider.Astraflow: "openai/",
SupportedLiteLLMProvider.Astraflow_CN: "openai/",
SupportedLiteLLMProvider.FuturMix: "openai/",
}
ChatModel = globals().get("ChatModel", {})

View File

@@ -1227,6 +1227,16 @@ class AstraflowCNChat(Base):
super().__init__(key, model_name, base_url, **kwargs)
class FuturMixChat(Base):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name, base_url="https://futurmix.ai/v1", **kwargs):
if not base_url:
base_url = "https://futurmix.ai/v1"
super().__init__(key, model_name, base_url, **kwargs)
logging.info("[FuturMix] Chat initialized with model %s", model_name)
class LiteLLMBase(ABC):
_FACTORY_NAME = [
"Tongyi-Qianwen",

View File

@@ -1254,6 +1254,16 @@ class MoonshotCV(GptV4):
super().__init__(key, model_name, lang=lang, base_url=base_url, **kwargs)
class FuturMixCV(GptV4):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name, lang="Chinese", base_url="https://futurmix.ai/v1", **kwargs):
if not base_url:
base_url = "https://futurmix.ai/v1"
super().__init__(key, model_name, lang=lang, base_url=base_url, **kwargs)
logging.info("[FuturMix] CV initialized with model %s", model_name)
class RAGconCV(GptV4):
"""
RAGcon CV Provider - routes through LiteLLM proxy

View File

@@ -179,6 +179,16 @@ class AstraflowCNEmbed(OpenAIEmbed):
super().__init__(key, model_name, base_url)
class FuturMixEmbed(OpenAIEmbed):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name="text-embedding-3-small", base_url="https://futurmix.ai/v1"):
if not base_url:
base_url = "https://futurmix.ai/v1"
super().__init__(key, model_name, base_url)
logging.info("[FuturMix] Embedding initialized with model %s", model_name)
class BaiChuanEmbed(OpenAIEmbed):
_FACTORY_NAME = "BaiChuan"

View File

@@ -14,6 +14,7 @@
# limitations under the License.
#
import json
import logging
from abc import ABC
from urllib.parse import urljoin
@@ -521,6 +522,17 @@ class JiekouAIRerank(JinaRerank):
base_url = "https://api.jiekou.ai/openai/v1/rerank"
super().__init__(key, model_name, base_url)
class FuturMixRerank(OpenAI_APIRerank):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name, base_url="https://futurmix.ai/v1/rerank"):
if not base_url:
base_url = "https://futurmix.ai/v1/rerank"
super().__init__(key, model_name, base_url)
logging.info("[FuturMix] Rerank initialized with model %s", model_name)
class RAGconRerank(Base):
"""
RAGcon Rerank Provider - routes through LiteLLM proxy

View File

@@ -20,6 +20,7 @@ import os
import re
from abc import ABC
import tempfile
import logging
import requests
from openai import OpenAI
@@ -68,6 +69,16 @@ class StepFunSeq2txt(GPTSeq2txt):
super().__init__(key, model_name=model_name, base_url=base_url, **kwargs)
class FuturMixSeq2txt(GPTSeq2txt):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name="whisper-1", base_url="https://futurmix.ai/v1", **kwargs):
if not base_url:
base_url = "https://futurmix.ai/v1"
super().__init__(key, model_name=model_name, base_url=base_url, **kwargs)
logging.info("[FuturMix] Speech2Text initialized with model %s", model_name)
class QWenSeq2txt(Base):
_FACTORY_NAME = "Tongyi-Qianwen"

View File

@@ -28,6 +28,7 @@ from abc import ABC
from datetime import datetime
from time import mktime
from typing import Annotated, Literal
import logging
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
@@ -450,6 +451,16 @@ class DeerAPITTS(OpenAITTS):
super().__init__(key, model_name, base_url, **kwargs)
class FuturMixTTS(OpenAITTS):
_FACTORY_NAME = "FuturMix"
def __init__(self, key, model_name, base_url="https://futurmix.ai/v1", **kwargs):
if not base_url:
base_url = "https://futurmix.ai/v1"
super().__init__(key, model_name, base_url, **kwargs)
logging.info("[FuturMix] TTS initialized with model %s", model_name)
class StepFunTTS(OpenAITTS):
_FACTORY_NAME = "StepFun"
_SUPPORTED_RESPONSE_FORMATS = {"wav", "mp3", "flac", "opus", "pcm"}