diff --git a/conf/llm_factories.json b/conf/llm_factories.json
index 8f898da90..175ebf014 100644
--- a/conf/llm_factories.json
+++ b/conf/llm_factories.json
@@ -6267,6 +6267,14 @@
"is_tools": true
}
]
+ },
+ {
+ "name": "RAGcon",
+ "logo": "",
+ "tags": "LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,IMAGE2TEXT",
+ "status": "1",
+ "rank": "100",
+ "llm": []
}
]
}
diff --git a/rag/llm/chat_model.py b/rag/llm/chat_model.py
index e763fca53..10b2fb515 100644
--- a/rag/llm/chat_model.py
+++ b/rag/llm/chat_model.py
@@ -1658,3 +1658,17 @@ class LiteLLMBase(ABC):
completion_args["extra_headers"] = extra_headers
return completion_args
+class RAGconChat(Base):
+ """
+ RAGcon Chat Provider - routes through LiteLLM proxy
+
+ All model types are handled through a unified LiteLLM endpoint.
+ Default Base URL: https://connect.ragcon.com/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name, base_url=None, **kwargs):
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ super().__init__(key, model_name, base_url, **kwargs)
diff --git a/rag/llm/cv_model.py b/rag/llm/cv_model.py
index 7543ca640..ff868d6bd 100644
--- a/rag/llm/cv_model.py
+++ b/rag/llm/cv_model.py
@@ -1252,3 +1252,26 @@ class MoonshotCV(GptV4):
if not base_url:
base_url = "https://api.moonshot.cn/v1"
super().__init__(key, model_name, lang=lang, base_url=base_url, **kwargs)
+
+
+class RAGconCV(GptV4):
+ """
+ RAGcon CV Provider - routes through LiteLLM proxy
+
+ Supports vision models through LiteLLM.
+ Default Base URL: https://connect.ragcon.ai/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name, lang="Chinese", base_url="", **kwargs):
+
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ # Initialize client
+ self.client = OpenAI(api_key=key, base_url=base_url)
+ self.async_client = AsyncOpenAI(api_key=key, base_url=base_url)
+ self.model_name = model_name
+ self.lang = lang
+
+ Base.__init__(self, **kwargs)
\ No newline at end of file
diff --git a/rag/llm/embedding_model.py b/rag/llm/embedding_model.py
index 79dc96acc..f4b58619b 100644
--- a/rag/llm/embedding_model.py
+++ b/rag/llm/embedding_model.py
@@ -1080,3 +1080,17 @@ class JiekouAIEmbed(OpenAIEmbed):
if not base_url:
base_url = "https://api.jiekou.ai/openai/v1/embeddings"
super().__init__(key, model_name, base_url)
+
+class RAGconEmbed(OpenAIEmbed):
+ """
+ RAGcon Embedding Provider - routes through LiteLLM proxy
+
+ Default Base URL: https://connect.ragcon.ai/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name="text-embedding-3-small", base_url=None):
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ super().__init__(key, model_name, base_url)
\ No newline at end of file
diff --git a/rag/llm/rerank_model.py b/rag/llm/rerank_model.py
index b8fd19dac..5002fe765 100644
--- a/rag/llm/rerank_model.py
+++ b/rag/llm/rerank_model.py
@@ -506,3 +506,47 @@ class JiekouAIRerank(JinaRerank):
if not base_url:
base_url = "https://api.jiekou.ai/openai/v1/rerank"
super().__init__(key, model_name, base_url)
+
+class RAGconRerank(Base):
+ """
+ RAGcon Rerank Provider - routes through LiteLLM proxy
+
+ Assumes LiteLLM proxy supports /rerank endpoint.
+ Default Base URL: https://connect.ragcon.ai/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name, base_url=None, **kwargs):
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ self._api_key = key
+ self._base_url = base_url
+
+ self.headers = {"Content-Type": "application/json", "Authorization": f"Bearer {key}"}
+ self.model_name = model_name
+
+
+ def similarity(self, query: str, texts: list):
+ # noway to config Ragflow , use fix setting
+ texts = [truncate(t, 500) for t in texts]
+ data = {
+ "model": self.model_name,
+ "query": query,
+ "documents": texts,
+ "top_n": len(texts),
+ }
+ token_count = 0
+ for t in texts:
+ token_count += num_tokens_from_string(t)
+ res = requests.post(self._base_url + "/rerank", headers=self.headers, json=data).json()
+ rank = np.zeros(len(texts), dtype=float)
+ try:
+ for d in res["results"]:
+ rank[d["index"]] = d["relevance_score"]
+ except Exception as _e:
+ log_exception(_e, res)
+
+ rank = Base._normalize_rank(rank)
+
+ return rank, token_count
\ No newline at end of file
diff --git a/rag/llm/sequence2txt_model.py b/rag/llm/sequence2txt_model.py
index abbdb4de3..0191482cf 100644
--- a/rag/llm/sequence2txt_model.py
+++ b/rag/llm/sequence2txt_model.py
@@ -376,3 +376,48 @@ class ZhipuSeq2txt(Base):
return f"**ERROR**: code: {error['code']}, message: {error['message']}", 0
except Exception as e:
return "**ERROR**: " + str(e), 0
+
+
+class RAGconSeq2txt(Base):
+ """
+ RAGcon Sequence2Text Provider - routes through LiteLLM proxy
+
+ Speech-to-text models routed through LiteLLM.
+ Default Base URL: https://connect.ragcon.com/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name, base_url=None, lang="English", **kwargs):
+ # Use provided base_url or fallback to default
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ self.base_url = base_url
+ self.model_name = model_name
+ self.key = key
+ self.lang = lang
+
+ self.client = OpenAI(api_key=key, base_url=self.base_url)
+
+ def transcription(self, audio_path, **kwargs):
+ """
+ Transcribe audio file using RAGcon's OpenAI-compatible API.
+ Uses Whisper's automatic language detection for German and English audio.
+
+ Args:
+ audio_path: Path to the audio file
+ **kwargs: Additional parameters (currently unused but maintained for compatibility)
+
+ Returns:
+ tuple: (transcribed_text, token_count)
+ """
+ with open(audio_path, "rb") as audio_file:
+ # Call RAGcon API - Whisper will auto-detect language
+ transcription = self.client.audio.transcriptions.create(
+ model=self.model_name,
+ file=audio_file
+ )
+
+ # Return text and token count
+ text = transcription.text.strip()
+ return text, num_tokens_from_string(text)
diff --git a/rag/llm/tts_model.py b/rag/llm/tts_model.py
index 602ea165a..b39b6a8c7 100644
--- a/rag/llm/tts_model.py
+++ b/rag/llm/tts_model.py
@@ -482,3 +482,51 @@ class StepFunTTS(OpenAITTS):
yield chunk
yield num_tokens_from_string(text)
+
+
+class RAGconTTS(Base):
+ """
+ RAGcon TTS Provider - routes through LiteLLM proxy
+
+ Text-to-speech models routed through LiteLLM.
+ Default Base URL: https://connect.ragcon.ai/v1
+ """
+ _FACTORY_NAME = "RAGcon"
+
+ def __init__(self, key, model_name, base_url=None, **kwargs):
+ if not base_url:
+ base_url = "https://connect.ragcon.com/v1"
+
+ self.base_url = base_url
+ self.api_key = key
+ self.model_name = model_name
+ self.headers = {
+ "accept": "application/json",
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {self.api_key}"
+ }
+
+ def tts(self, text, voice="English Female", stream=True):
+ """
+ Uses LiteLLM's /v1/audio/speech endpoint
+ """
+
+ payload = {
+ "model": self.model_name,
+ "input": text,
+ "voice": voice
+ }
+
+ response = requests.post(
+ f"{self.base_url}/audio/speech",
+ headers=self.headers,
+ json=payload,
+ stream=stream
+ )
+
+ if response.status_code != 200:
+ raise Exception(f"**Error**: {response.status_code}, {response.text}")
+
+ for chunk in response.iter_content(chunk_size=1024):
+ if chunk:
+ yield chunk
diff --git a/web/src/assets/svg/llm/ragcon.svg b/web/src/assets/svg/llm/ragcon.svg
new file mode 100644
index 000000000..11acb8776
--- /dev/null
+++ b/web/src/assets/svg/llm/ragcon.svg
@@ -0,0 +1,24 @@
+
+
diff --git a/web/src/components/svg-icon.tsx b/web/src/components/svg-icon.tsx
index 6a14fc64b..87cf46bf4 100644
--- a/web/src/components/svg-icon.tsx
+++ b/web/src/components/svg-icon.tsx
@@ -85,6 +85,7 @@ const svgIcons = [
LLMFactory.N1n,
// LLMFactory.DeerAPI,
LLMFactory.Avian,
+ LLMFactory.RAGcon,
];
export const LlmIcon = ({
diff --git a/web/src/constants/llm.ts b/web/src/constants/llm.ts
index 6cde18fcb..e3f1dffba 100644
--- a/web/src/constants/llm.ts
+++ b/web/src/constants/llm.ts
@@ -64,6 +64,7 @@ export enum LLMFactory {
PaddleOCR = 'PaddleOCR',
N1n = 'n1n',
Avian = 'Avian',
+ RAGcon = 'RAGcon',
}
// Please lowercase the file name
@@ -133,6 +134,7 @@ export const IconMap = {
[LLMFactory.PaddleOCR]: 'paddleocr',
[LLMFactory.N1n]: 'n1n',
[LLMFactory.Avian]: 'avian',
+ [LLMFactory.RAGcon]: 'ragcon',
};
export const APIMapUrl = {
diff --git a/web/src/pages/user-setting/constants.tsx b/web/src/pages/user-setting/constants.tsx
index 22fadbab1..1e32df753 100644
--- a/web/src/pages/user-setting/constants.tsx
+++ b/web/src/pages/user-setting/constants.tsx
@@ -39,6 +39,7 @@ export const LocalLlmFactories = [
LLMFactory.GPUStack,
LLMFactory.ModelScope,
LLMFactory.VLLM,
+ LLMFactory.RAGcon,
];
export enum TenantRole {
diff --git a/web/src/pages/user-setting/setting-model/modal/ollama-modal/index.tsx b/web/src/pages/user-setting/setting-model/modal/ollama-modal/index.tsx
index bfe7807b0..a1c00e5aa 100644
--- a/web/src/pages/user-setting/setting-model/modal/ollama-modal/index.tsx
+++ b/web/src/pages/user-setting/setting-model/modal/ollama-modal/index.tsx
@@ -27,6 +27,7 @@ const llmFactoryToUrlMap: Partial> = {
[LLMFactory.LMStudio]: 'https://lmstudio.ai/docs/basics',
[LLMFactory.OpenAiAPICompatible]:
'https://platform.openai.com/docs/models/gpt-4',
+ [LLMFactory.RAGcon]: 'https://www.ragcon.ai/erste-schritte-mit-ragflow/',
[LLMFactory.TogetherAI]: 'https://docs.together.ai/docs/deployment-options',
[LLMFactory.Replicate]: 'https://replicate.com/docs/topics/deployments',
[LLMFactory.OpenRouter]: 'https://openrouter.ai/docs',
@@ -81,6 +82,14 @@ const OllamaModal = ({
'speech2text',
'tts',
]),
+ [LLMFactory.RAGcon]: buildModelTypeOptions([
+ 'chat',
+ 'embedding',
+ 'rerank',
+ 'image2text',
+ 'speech2text',
+ 'tts',
+ ]),
[LLMFactory.ModelScope]: buildModelTypeOptions(['chat']),
[LLMFactory.GPUStack]: buildModelTypeOptions([
'chat',