Skip to content

Commit cafa449

Browse files
committed
feat: add new llm and embedding provider JiekouAI
1 parent 67d2a6b commit cafa449

13 files changed

Lines changed: 609 additions & 7 deletions

File tree

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ result = query("Write a report about xxx.") # Your question here
9696
#### LLM Configuration
9797

9898
<pre><code>config.set_provider_config("llm", "(LLMName)", "(Arguments dict)")</code></pre>
99-
<p>The "LLMName" can be one of the following: ["DeepSeek", "OpenAI", "XAI", "SiliconFlow", "Aliyun", "PPIO", "TogetherAI", "Gemini", "Ollama", "Novita"]</p>
99+
<p>The "LLMName" can be one of the following: ["DeepSeek", "OpenAI", "XAI", "SiliconFlow", "Aliyun", "PPIO", "TogetherAI", "Gemini", "Ollama", "Novita", "JiekouAI"]</p>
100100
<p> The "Arguments dict" is a dictionary that contains the necessary arguments for the LLM class.</p>
101101

102102
<details>
@@ -173,6 +173,13 @@ result = query("Write a report about xxx.") # Your question here
173173
<p> More details about PPIO: https://ppinfra.com/docs/get-started/quickstart.html?utm_source=github_deep-searcher </p>
174174
</details>
175175

176+
<details>
177+
<summary>Example (Claude Sonnet 4.5 from JiekouAI)</summary>
178+
<p> Make sure you have prepared your JiekouAI API KEY as an env variable <code>JIEKOU_API_KEY</code>. You can create an API Key <a href="https://jiekou.ai/settings/key-management?utm_source=github_deep-searcher">here</a>. </p>
179+
<pre><code>config.set_provider_config("llm", "JiekouAI", {"model": "claude-sonnet-4-5-20250929"})</code></pre>
180+
<p> More details about JiekouAI: https://docs.jiekou.ai/docs/support/quickstart?utm_source=github_deep-searcher </p>
181+
</details>
182+
176183
<details>
177184
<summary>Example (Ollama)</summary>
178185
<p> Follow <a href="https://github.com/jmorganca/ollama">these instructions</a> to set up and run a local Ollama instance:</p>
@@ -216,7 +223,7 @@ result = query("Write a report about xxx.") # Your question here
216223

217224
#### Embedding Model Configuration
218225
<pre><code>config.set_provider_config("embedding", "(EmbeddingModelName)", "(Arguments dict)")</code></pre>
219-
<p>The "EmbeddingModelName" can be one of the following: ["MilvusEmbedding", "OpenAIEmbedding", "VoyageEmbedding", "SiliconflowEmbedding", "PPIOEmbedding", "NovitaEmbedding"]</p>
226+
<p>The "EmbeddingModelName" can be one of the following: ["MilvusEmbedding", "OpenAIEmbedding", "VoyageEmbedding", "SiliconflowEmbedding", "PPIOEmbedding", "NovitaEmbedding", "JiekouAIEmbedding"]</p>
220227
<p> The "Arguments dict" is a dictionary that contains the necessary arguments for the embedding model class.</p>
221228

222229
<details>
@@ -308,6 +315,12 @@ result = query("Write a report about xxx.") # Your question here
308315
<p> More details about PPIO: https://ppinfra.com/docs/get-started/quickstart.html?utm_source=github_deep-searcher </p>
309316
</details>
310317

318+
<details>
319+
<summary>Example (JiekouAI embedding)</summary>
320+
<p> Make sure you have prepared your JiekouAI API KEY as an env variable <code>JIEKOU_API_KEY</code>.</p>
321+
<pre><code>config.set_provider_config("embedding", "JiekouAIEmbedding", {"model": "qwen/qwen3-embedding-8b"})</code></pre>
322+
<p> More details about JiekouAI: https://docs.jiekou.ai/docs/support/quickstart?utm_source=github_deep-searcher </p>
323+
</details>
311324

312325
<details>
313326
<summary>Example (FastEmbed embedding)</summary>
@@ -548,6 +561,7 @@ nest_asyncio.apply()
548561
- [PPIO](https://ppinfra.com/model-api/product/llm-api?utm_source=github_deep-searcher) (`PPIO_API_KEY` env variable required)
549562
- [Novita AI](https://novita.ai/docs/api-reference/model-apis-llm-create-embeddings?utm_source=github_deep-searcher&utm_medium=github_readme&utm_campaign=link) (`NOVITA_API_KEY` env variable required)
550563
- [IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmembedding) (`WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` env variables required)
564+
- [JiekouAI](https://jiekou.ai/?utm_source=github_deep-searcher) (`JIEKOU_API_KEY` env variable required)
551565

552566
### 🔹 LLM Support
553567
- [OpenAI](https://platform.openai.com/docs/models) (`OPENAI_API_KEY` env variable required)
@@ -562,6 +576,7 @@ nest_asyncio.apply()
562576
- [Ollama](https://ollama.com/)
563577
- [Novita AI](https://novita.ai/docs/guides/introduction?utm_source=github_deep-searcher&utm_medium=github_readme&utm_campaign=link) (`NOVITA_API_KEY` env variable required)
564578
- [IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmfm) (`WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` env variable required)
579+
- [JiekouAI](https://jiekou.ai/?utm_source=github_deep-searcher) (`JIEKOU_API_KEY` env variable required)
565580

566581
### 🔹 Document Loader
567582
- Local File

deepsearcher/config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ provide_settings:
2424
## api_key: "sk_xxxxxx" # Uncomment to override the `PPIO_API_KEY` set in the environment variable
2525
## base_url: ""
2626

27+
# provider: "JiekouAI"
28+
# config:
29+
# model: "claude-sonnet-4-5-20250929"
30+
## api_key: "xxxx" # Uncomment to override the `JIEKOU_API_KEY` set in the environment variable
31+
## base_url: ""
32+
2733
# provider: "TogetherAI"
2834
# config:
2935
# model: "deepseek-ai/DeepSeek-R1"

deepsearcher/embedding/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .volcengine_embedding import VolcengineEmbedding
1313
from .voyage_embedding import VoyageEmbedding
1414
from .watsonx_embedding import WatsonXEmbedding
15+
from .jiekouai_embedding import JiekouAIEmbedding
1516

1617
__all__ = [
1718
"MilvusEmbedding",
@@ -28,4 +29,5 @@
2829
"NovitaEmbedding",
2930
"SentenceTransformerEmbedding",
3031
"WatsonXEmbedding",
32+
"JiekouAIEmbedding",
3133
]
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import os
2+
from typing import List, Union
3+
4+
import requests
5+
6+
from deepsearcher.embedding.base import BaseEmbedding
7+
8+
# TODO: Update with actual JiekouAI model dimensions when available
9+
JIEKOUAI_MODEL_DIM_MAP = {
10+
"qwen/qwen3-embedding-0.6b": 1024,
11+
"qwen/qwen3-embedding-8b": 1024,
12+
"baai/bge-m3": 1024,
13+
}
14+
15+
JIEKOUAI_EMBEDDING_API = "https://api.jiekou.ai/openai/v1/embeddings"
16+
17+
18+
class JiekouAIEmbedding(BaseEmbedding):
19+
"""
20+
JiekouAI embedding model implementation.
21+
22+
This class provides an interface to the JiekouAI embedding API, which offers
23+
various embedding models for text processing.
24+
"""
25+
26+
def __init__(self, model="qwen/qwen3-embedding-8b", batch_size=32, **kwargs):
27+
"""
28+
Initialize the JiekouAI embedding model.
29+
30+
Args:
31+
model (str): The model identifier to use for embeddings. Default is "baai/bge-m3".
32+
batch_size (int): Maximum number of texts to process in a single batch. Default is 32.
33+
**kwargs: Additional keyword arguments.
34+
- api_key (str, optional): The JiekouAI API key. If not provided,
35+
it will be read from the JIEKOU_API_KEY environment variable.
36+
- model_name (str, optional): Alternative way to specify the model.
37+
38+
Raises:
39+
RuntimeError: If no API key is provided or found in environment variables.
40+
"""
41+
if "model_name" in kwargs and (not model or model == "qwen/qwen3-embedding-8b"):
42+
model = kwargs.pop("model_name")
43+
self.model = model
44+
45+
if "api_key" in kwargs:
46+
api_key = kwargs.pop("api_key")
47+
else:
48+
api_key = os.getenv("JIEKOU_API_KEY")
49+
50+
if not api_key or len(api_key) == 0:
51+
raise RuntimeError("api_key is required for JiekouAIEmbedding")
52+
self.api_key = api_key
53+
self.batch_size = batch_size
54+
55+
def embed_query(self, text: str) -> List[float]:
56+
"""
57+
Embed a single query text.
58+
59+
Args:
60+
text (str): The query text to embed.
61+
62+
Returns:
63+
List[float]: A list of floats representing the embedding vector.
64+
"""
65+
return self._embed_input(text)[0]
66+
67+
def embed_documents(self, texts: List[str]) -> List[List[float]]:
68+
"""
69+
Embed a list of document texts.
70+
71+
This method handles batching of document embeddings based on the configured
72+
batch size to optimize API calls.
73+
74+
Args:
75+
texts (List[str]): A list of document texts to embed.
76+
77+
Returns:
78+
List[List[float]]: A list of embedding vectors, one for each input text.
79+
"""
80+
# batch embedding
81+
if self.batch_size > 0:
82+
if len(texts) > self.batch_size:
83+
batch_texts = [
84+
texts[i : i + self.batch_size] for i in range(0, len(texts), self.batch_size)
85+
]
86+
embeddings = []
87+
for batch_text in batch_texts:
88+
batch_embeddings = self._embed_input(batch_text)
89+
embeddings.extend(batch_embeddings)
90+
return embeddings
91+
return self._embed_input(texts)
92+
return [self.embed_query(text) for text in texts]
93+
94+
def _embed_input(self, input: Union[str, List[str]]) -> List[List[float]]:
95+
"""
96+
Internal method to handle the API call for embedding inputs.
97+
98+
Args:
99+
input (Union[str, List[str]]): Either a single text string or a list of text strings to embed.
100+
101+
Returns:
102+
List[List[float]]: A list of embedding vectors for the input(s).
103+
104+
Raises:
105+
HTTPError: If the API request fails.
106+
"""
107+
headers = {
108+
"Authorization": f"Bearer {self.api_key}",
109+
"Content-Type": "application/json",
110+
}
111+
112+
# Handle both single string and list of strings
113+
input_list = input if isinstance(input, list) else [input]
114+
115+
payload = {"model": self.model, "input": input_list}
116+
117+
response = requests.request("POST", JIEKOUAI_EMBEDDING_API, json=payload, headers=headers)
118+
response.raise_for_status()
119+
result = response.json()["data"]
120+
sorted_results = sorted(result, key=lambda x: x["index"])
121+
return [res["embedding"] for res in sorted_results]
122+
123+
@property
124+
def dimension(self) -> int:
125+
"""
126+
Get the dimensionality of the embeddings for the current model.
127+
128+
Returns:
129+
int: The number of dimensions in the embedding vectors.
130+
"""
131+
return JIEKOUAI_MODEL_DIM_MAP[self.model]

deepsearcher/llm/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .deepseek import DeepSeek
66
from .gemini import Gemini
77
from .glm import GLM
8+
from .jiekouai import JiekouAI
89
from .novita import Novita
910
from .ollama import Ollama
1011
from .openai_llm import OpenAI
@@ -32,4 +33,5 @@
3233
"Novita",
3334
"Aliyun",
3435
"WatsonX",
36+
"JiekouAI",
3537
]

deepsearcher/llm/jiekouai.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import os
2+
from typing import Dict, List
3+
4+
from deepsearcher.llm.base import BaseLLM, ChatResponse
5+
6+
7+
class JiekouAI(BaseLLM):
8+
"""
9+
JiekouAI language model implementation.
10+
11+
This class provides an interface to interact with language models
12+
hosted on the JiekouAI platform.
13+
14+
Attributes:
15+
model (str): The model identifier to use on JiekouAI platform.
16+
client: The OpenAI-compatible client instance for JiekouAI API.
17+
"""
18+
19+
def __init__(self, model: str = "claude-sonnet-4-5-20250929", **kwargs):
20+
"""
21+
Initialize a JiekouAI language model client.
22+
23+
Args:
24+
model (str, optional): The model identifier to use. Defaults to "claude-sonnet-4-5-20250929".
25+
**kwargs: Additional keyword arguments to pass to the OpenAI client.
26+
- api_key: JiekouAI API key. If not provided, uses JIEKOU_API_KEY environment variable.
27+
- base_url: JiekouAI API base URL. If not provided, defaults to "https://api.jiekou.ai/openai/v1".
28+
"""
29+
from openai import OpenAI as OpenAI_
30+
31+
self.model = model
32+
if "api_key" in kwargs:
33+
api_key = kwargs.pop("api_key")
34+
else:
35+
api_key = os.getenv("JIEKOU_API_KEY")
36+
if "base_url" in kwargs:
37+
base_url = kwargs.pop("base_url")
38+
else:
39+
base_url = "https://api.jiekou.ai/openai/v1"
40+
self.client = OpenAI_(api_key=api_key, base_url=base_url, **kwargs)
41+
42+
def chat(self, messages: List[Dict]) -> ChatResponse:
43+
"""
44+
Send a chat message to the JiekouAI model and get a response.
45+
46+
Args:
47+
messages (List[Dict]): A list of message dictionaries, typically in the format
48+
[{"role": "system", "content": "..."},
49+
{"role": "user", "content": "..."}]
50+
51+
Returns:
52+
ChatResponse: An object containing the model's response and token usage information.
53+
"""
54+
completion = self.client.chat.completions.create(
55+
model=self.model,
56+
messages=messages,
57+
)
58+
return ChatResponse(
59+
content=completion.choices[0].message.content,
60+
total_tokens=completion.usage.total_tokens,
61+
)

docs/configuration/embedding.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ config.set_provider_config("embedding", "(EmbeddingModelName)", "(Arguments dict
2525
| **NovitaEmbedding** | Novita AI embedding | Cost-effective |
2626
| **SentenceTransformerEmbedding** | Sentence Transfomer Embedding | Self-hosted option |
2727
| **IBM watsonx.ai** | Various options | IBM's Enterprise AI platform |
28+
| **JiekouAIEmbedding** | JiekouAI embedding | High quality, cost-effective |
2829

2930
## 🔍 Provider Examples
3031

@@ -124,3 +125,10 @@ config.set_provider_config("embedding", "VoyageEmbedding", {"model": "voyage-3"}
124125
config.set_provider_config("embedding", "WatsonXEmbedding", {"model": "ibm/slate-125m-english-rtrvr-v2"})
125126
```
126127
*Requires `pip install ibm-watsonx-ai`*
128+
129+
??? example "JiekouAI"
130+
131+
```python
132+
config.set_provider_config("embedding", "JiekouAIEmbedding", {"model": "qwen/qwen3-embedding-8b"})
133+
```
134+
*Requires `JIEKOU_API_KEY` environment variable*

docs/configuration/llm.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ config.set_provider_config("llm", "(LLMName)", "(Arguments dict)")
2626
| **Bedrock** | Amazon Bedrock LLMs | anthropic.claude, ai21.j2 |
2727
| **Novita** | Novita AI models | Various options |
2828
| **IBM watsonx.ai** | IBM Enterprise AI platform | Various options |
29+
| **JiekouAI** | JiekouAI models | Claude, OpenAI, Deepseek, Grok, Qwen, etc. |
2930

3031
## 🔍 Provider Examples
3132

@@ -190,3 +191,13 @@ config.set_provider_config("llm", "WatsonX", {"model": "ibm/granite-3-3-8b-instr
190191

191192
More details about WatsonX: [https://www.ibm.com/products/watsonx-ai/foundation-models](https://www.ibm.com/products/watsonx-ai/foundation-models)
192193
```
194+
195+
??? example "JiekouAI"
196+
197+
```python
198+
config.set_provider_config("llm", "JiekouAI", {"model": "claude-sonnet-4-5-20250929"})
199+
```
200+
*Requires `JIEKOU_API_KEY` environment variable*
201+
202+
More details about JiekouAI: [https://docs.jiekou.ai/docs/support/quickstart](https://docs.jiekou.ai/docs/support/quickstart)
203+

docs/integrations/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Support for various embedding models to convert text into vector representations
2525
| **[PPIO](https://ppinfra.com/model-api/product/llm-api)** | `PPIO_API_KEY` | Flexible cloud embeddings |
2626
| **[Novita AI](https://novita.ai/docs/api-reference/model-apis-llm-create-embeddings)** | `NOVITA_API_KEY` | Rich model selection |
2727
| **[IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmembedding)** | `WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` | IBM's Enterprise AI platform |
28+
| **[JiekouAI](https://jiekou.ai/?utm_source=github_deep-searcher)** | `JIEKOU_API_KEY` | JiekouAI's embedding models |
2829

2930
## 🧠 Large Language Models {#llm-support}
3031

@@ -44,6 +45,7 @@ Support for various large language models (LLMs) to process queries and generate
4445
| **[Ollama](https://ollama.com/)** | None | Local LLM deployment |
4546
| **[Novita AI](https://novita.ai/docs/guides/introduction)** | `NOVITA_API_KEY` | Diverse AI services |
4647
| **[IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmfm)** | `WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` | IBM's Enterprise AI platform |
48+
| **[JiekouAI](https://jiekou.ai/?utm_source=github_deep-searcher)** | `JIEKOU_API_KEY` | Various open-source and closed-source models |
4749

4850
## 📄 Document Loader {#document-loader}
4951

env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ SILICONFLOW_API_KEY=your_siliconflow_api_key_here
1212
# PPIO API Key (required if using PPIO models)
1313
PPIO_API_KEY=your_ppio_api_key_here
1414

15+
# JiekouAI API Key (required if using JiekouAI models)
16+
JIEKOU_API_KEY=your_jiekouai_api_key_here
17+
1518
# Together AI API Key (required if using Together AI models)
1619
TOGETHER_API_KEY=your_together_api_key_here
1720

0 commit comments

Comments
 (0)