diff --git a/api/apps/llm_app.py b/api/apps/llm_app.py
index 24dfda0b3..ad963555c 100644
--- a/api/apps/llm_app.py
+++ b/api/apps/llm_app.py
@@ -21,7 +21,7 @@ from api.db import StatusEnum, LLMType
from api.db.db_models import TenantLLM
from api.utils.api_utils import get_json_result
from rag.llm import EmbeddingModel, ChatModel, RerankModel,CvModel
-
+import requests
@manager.route('/factories', methods=['GET'])
@login_required
@@ -189,9 +189,13 @@ def add_llm():
"ons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/256"
"0px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
)
- m, tc = mdl.describe(img_url)
- if not tc:
- raise Exception(m)
+ res = requests.get(img_url)
+ if res.status_code == 200:
+ m, tc = mdl.describe(res.content)
+ if not tc:
+ raise Exception(m)
+ else:
+ raise ConnectionError("fail to download the test picture")
except Exception as e:
msg += f"\nFail to access model({llm['llm_name']})." + str(e)
else:
diff --git a/conf/llm_factories.json b/conf/llm_factories.json
index 2341f3d10..f0aa28cf7 100644
--- a/conf/llm_factories.json
+++ b/conf/llm_factories.json
@@ -2208,6 +2208,13 @@
"model_type": "image2text"
}
]
+ },
+ {
+ "name": "LM-Studio",
+ "logo": "",
+ "tags": "LLM,TEXT EMBEDDING,IMAGE2TEXT",
+ "status": "1",
+ "llm": []
}
]
}
\ No newline at end of file
diff --git a/rag/llm/__init__.py b/rag/llm/__init__.py
index 1ba1e56f8..a91c18ec9 100644
--- a/rag/llm/__init__.py
+++ b/rag/llm/__init__.py
@@ -34,8 +34,9 @@ EmbeddingModel = {
"BAAI": DefaultEmbedding,
"Mistral": MistralEmbed,
"Bedrock": BedrockEmbed,
- "Gemini":GeminiEmbed,
- "NVIDIA":NvidiaEmbed
+ "Gemini": GeminiEmbed,
+ "NVIDIA": NvidiaEmbed,
+ "LM-Studio": LmStudioEmbed
}
@@ -47,10 +48,11 @@ CvModel = {
"Tongyi-Qianwen": QWenCV,
"ZHIPU-AI": Zhipu4V,
"Moonshot": LocalCV,
- 'Gemini':GeminiCV,
- 'OpenRouter':OpenRouterCV,
- "LocalAI":LocalAICV,
- "NVIDIA":NvidiaCV
+ "Gemini": GeminiCV,
+ "OpenRouter": OpenRouterCV,
+ "LocalAI": LocalAICV,
+ "NVIDIA": NvidiaCV,
+ "LM-Studio": LmStudioCV
}
@@ -69,12 +71,13 @@ ChatModel = {
"MiniMax": MiniMaxChat,
"Minimax": MiniMaxChat,
"Mistral": MistralChat,
- 'Gemini' : GeminiChat,
+ "Gemini": GeminiChat,
"Bedrock": BedrockChat,
"Groq": GroqChat,
- 'OpenRouter':OpenRouterChat,
- "StepFun":StepFunChat,
- "NVIDIA":NvidiaChat
+ "OpenRouter": OpenRouterChat,
+ "StepFun": StepFunChat,
+ "NVIDIA": NvidiaChat,
+ "LM-Studio": LmStudioChat
}
@@ -83,7 +86,8 @@ RerankModel = {
"Jina": JinaRerank,
"Youdao": YoudaoRerank,
"Xinference": XInferenceRerank,
- "NVIDIA":NvidiaRerank
+ "NVIDIA": NvidiaRerank,
+ "LM-Studio": LmStudioRerank
}
diff --git a/rag/llm/chat_model.py b/rag/llm/chat_model.py
index dc8879bdf..afb52cb95 100644
--- a/rag/llm/chat_model.py
+++ b/rag/llm/chat_model.py
@@ -976,3 +976,15 @@ class NvidiaChat(Base):
yield ans + "\n**ERROR**: " + str(e)
yield total_tokens
+
+
+class LmStudioChat(Base):
+ def __init__(self, key, model_name, base_url):
+ from os.path import join
+
+ if not base_url:
+ raise ValueError("Local llm url cannot be None")
+ if base_url.split("/")[-1] != "v1":
+ self.base_url = join(base_url, "v1")
+ self.client = OpenAI(api_key="lm-studio", base_url=self.base_url)
+ self.model_name = model_name
diff --git a/rag/llm/cv_model.py b/rag/llm/cv_model.py
index b40c0ba1c..bec862299 100644
--- a/rag/llm/cv_model.py
+++ b/rag/llm/cv_model.py
@@ -440,15 +440,8 @@ class LocalAICV(Base):
self.lang = lang
def describe(self, image, max_tokens=300):
- if not isinstance(image, bytes) and not isinstance(
- image, BytesIO
- ): # if url string
- prompt = self.prompt(image)
- for i in range(len(prompt)):
- prompt[i]["content"]["image_url"]["url"] = image
- else:
- b64 = self.image2base64(image)
- prompt = self.prompt(b64)
+ b64 = self.image2base64(image)
+ prompt = self.prompt(b64)
for i in range(len(prompt)):
for c in prompt[i]["content"]:
if "text" in c:
@@ -680,3 +673,14 @@ class NvidiaCV(Base):
"content": text + f'
',
}
]
+
+
+class LmStudioCV(LocalAICV):
+ def __init__(self, key, model_name, base_url, lang="Chinese"):
+ if not base_url:
+ raise ValueError("Local llm url cannot be None")
+ if base_url.split('/')[-1] != 'v1':
+ self.base_url = os.path.join(base_url,'v1')
+ self.client = OpenAI(api_key="lm-studio", base_url=self.base_url)
+ self.model_name = model_name
+ self.lang = lang
diff --git a/rag/llm/embedding_model.py b/rag/llm/embedding_model.py
index 8b5387308..58c5f1732 100644
--- a/rag/llm/embedding_model.py
+++ b/rag/llm/embedding_model.py
@@ -500,3 +500,24 @@ class NvidiaEmbed(Base):
def encode_queries(self, text):
embds, cnt = self.encode([text])
return np.array(embds[0]), cnt
+
+
+class LmStudioEmbed(Base):
+ def __init__(self, key, model_name, base_url):
+ if not base_url:
+ raise ValueError("Local llm url cannot be None")
+ if base_url.split("/")[-1] != "v1":
+ self.base_url = os.path.join(base_url, "v1")
+ self.client = OpenAI(api_key="lm-studio", base_url=self.base_url)
+ self.model_name = model_name
+
+ def encode(self, texts: list, batch_size=32):
+ res = self.client.embeddings.create(input=texts, model=self.model_name)
+ return (
+ np.array([d.embedding for d in res.data]),
+ 1024,
+ ) # local embedding for LmStudio donot count tokens
+
+ def encode_queries(self, text):
+ res = self.client.embeddings.create(text, model=self.model_name)
+ return np.array(res.data[0].embedding), 1024
diff --git a/rag/llm/rerank_model.py b/rag/llm/rerank_model.py
index 3a24da0b8..fb20aea69 100644
--- a/rag/llm/rerank_model.py
+++ b/rag/llm/rerank_model.py
@@ -202,3 +202,11 @@ class NvidiaRerank(Base):
}
res = requests.post(self.base_url, headers=self.headers, json=data).json()
return (np.array([d["logit"] for d in res["rankings"]]), token_count)
+
+
+class LmStudioRerank(Base):
+ def __init__(self, key, model_name, base_url):
+ pass
+
+ def similarity(self, query: str, texts: list):
+ raise NotImplementedError("The LmStudioRerank has not been implement")
diff --git a/web/src/assets/svg/llm/lm-studio.svg b/web/src/assets/svg/llm/lm-studio.svg
new file mode 100644
index 000000000..98d4c1d99
--- /dev/null
+++ b/web/src/assets/svg/llm/lm-studio.svg
@@ -0,0 +1,9704 @@
+
+
+
diff --git a/web/src/pages/user-setting/constants.tsx b/web/src/pages/user-setting/constants.tsx
index 5eb74b9a0..97df5415e 100644
--- a/web/src/pages/user-setting/constants.tsx
+++ b/web/src/pages/user-setting/constants.tsx
@@ -17,4 +17,4 @@ export const UserSettingIconMap = {
export * from '@/constants/setting';
-export const LocalLlmFactories = ['Ollama', 'Xinference','LocalAI'];
+export const LocalLlmFactories = ['Ollama', 'Xinference','LocalAI','LM-Studio'];
diff --git a/web/src/pages/user-setting/setting-model/constant.ts b/web/src/pages/user-setting/setting-model/constant.ts
index 88bb61e51..9493835d8 100644
--- a/web/src/pages/user-setting/setting-model/constant.ts
+++ b/web/src/pages/user-setting/setting-model/constant.ts
@@ -20,7 +20,8 @@ export const IconMap = {
OpenRouter: 'open-router',
LocalAI: 'local-ai',
StepFun: 'stepfun',
- NVIDIA:'nvidia'
+ NVIDIA:'nvidia',
+ 'LM-Studio':'lm-studio'
};
export const BedrockRegionList = [