lollms-client 0.32.1__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lollms-client might be problematic. Click here for more details.
- lollms_client/__init__.py +1 -1
- lollms_client/llm_bindings/azure_openai/__init__.py +6 -10
- lollms_client/llm_bindings/claude/__init__.py +4 -7
- lollms_client/llm_bindings/gemini/__init__.py +3 -7
- lollms_client/llm_bindings/grok/__init__.py +3 -7
- lollms_client/llm_bindings/groq/__init__.py +4 -7
- lollms_client/llm_bindings/hugging_face_inference_api/__init__.py +4 -6
- lollms_client/llm_bindings/litellm/__init__.py +15 -6
- lollms_client/llm_bindings/llamacpp/__init__.py +214 -388
- lollms_client/llm_bindings/lollms/__init__.py +24 -14
- lollms_client/llm_bindings/lollms_webui/__init__.py +6 -12
- lollms_client/llm_bindings/mistral/__init__.py +58 -29
- lollms_client/llm_bindings/ollama/__init__.py +6 -11
- lollms_client/llm_bindings/open_router/__init__.py +45 -14
- lollms_client/llm_bindings/openai/__init__.py +7 -14
- lollms_client/llm_bindings/openllm/__init__.py +12 -12
- lollms_client/llm_bindings/pythonllamacpp/__init__.py +1 -1
- lollms_client/llm_bindings/tensor_rt/__init__.py +8 -13
- lollms_client/llm_bindings/transformers/__init__.py +14 -6
- lollms_client/llm_bindings/vllm/__init__.py +16 -12
- lollms_client/lollms_core.py +296 -487
- lollms_client/lollms_discussion.py +436 -78
- lollms_client/lollms_llm_binding.py +223 -11
- lollms_client/lollms_mcp_binding.py +33 -2
- lollms_client/mcp_bindings/local_mcp/__init__.py +3 -2
- lollms_client/mcp_bindings/remote_mcp/__init__.py +6 -5
- lollms_client/mcp_bindings/standard_mcp/__init__.py +3 -5
- lollms_client/stt_bindings/lollms/__init__.py +6 -8
- lollms_client/stt_bindings/whisper/__init__.py +2 -4
- lollms_client/stt_bindings/whispercpp/__init__.py +15 -16
- lollms_client/tti_bindings/dalle/__init__.py +29 -28
- lollms_client/tti_bindings/diffusers/__init__.py +25 -21
- lollms_client/tti_bindings/gemini/__init__.py +215 -0
- lollms_client/tti_bindings/lollms/__init__.py +8 -9
- lollms_client-1.0.0.dist-info/METADATA +1214 -0
- lollms_client-1.0.0.dist-info/RECORD +69 -0
- {lollms_client-0.32.1.dist-info → lollms_client-1.0.0.dist-info}/top_level.txt +0 -2
- examples/article_summary/article_summary.py +0 -58
- examples/console_discussion/console_app.py +0 -266
- examples/console_discussion.py +0 -448
- examples/deep_analyze/deep_analyse.py +0 -30
- examples/deep_analyze/deep_analyze_multiple_files.py +0 -32
- examples/function_calling_with_local_custom_mcp.py +0 -250
- examples/generate_a_benchmark_for_safe_store.py +0 -89
- examples/generate_and_speak/generate_and_speak.py +0 -251
- examples/generate_game_sfx/generate_game_fx.py +0 -240
- examples/generate_text_with_multihop_rag_example.py +0 -210
- examples/gradio_chat_app.py +0 -228
- examples/gradio_lollms_chat.py +0 -259
- examples/internet_search_with_rag.py +0 -226
- examples/lollms_chat/calculator.py +0 -59
- examples/lollms_chat/derivative.py +0 -48
- examples/lollms_chat/test_openai_compatible_with_lollms_chat.py +0 -12
- examples/lollms_discussions_test.py +0 -155
- examples/mcp_examples/external_mcp.py +0 -267
- examples/mcp_examples/local_mcp.py +0 -171
- examples/mcp_examples/openai_mcp.py +0 -203
- examples/mcp_examples/run_remote_mcp_example_v2.py +0 -290
- examples/mcp_examples/run_standard_mcp_example.py +0 -204
- examples/simple_text_gen_test.py +0 -173
- examples/simple_text_gen_with_image_test.py +0 -178
- examples/test_local_models/local_chat.py +0 -9
- examples/text_2_audio.py +0 -77
- examples/text_2_image.py +0 -144
- examples/text_2_image_diffusers.py +0 -274
- examples/text_and_image_2_audio.py +0 -59
- examples/text_gen.py +0 -30
- examples/text_gen_system_prompt.py +0 -29
- lollms_client-0.32.1.dist-info/METADATA +0 -854
- lollms_client-0.32.1.dist-info/RECORD +0 -101
- test/test_lollms_discussion.py +0 -368
- {lollms_client-0.32.1.dist-info → lollms_client-1.0.0.dist-info}/WHEEL +0 -0
- {lollms_client-0.32.1.dist-info → lollms_client-1.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,11 +12,42 @@ from lollms_client.lollms_types import MSG_TYPE
|
|
|
12
12
|
from lollms_client.lollms_discussion import LollmsDiscussion
|
|
13
13
|
from lollms_client.lollms_utilities import ImageTokenizer
|
|
14
14
|
import re
|
|
15
|
+
import yaml
|
|
16
|
+
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
def load_known_contexts():
|
|
21
|
+
"""
|
|
22
|
+
Loads the known_contexts data from a JSON file.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
file_path (str): The path to the JSON file.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
dict: A dictionary containing the known_contexts data, or None if an error occurs.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
file_path = Path(__file__).parent / "assets" / "models_ctx_sizes.json"
|
|
32
|
+
with open(file_path, "r") as f:
|
|
33
|
+
known_contexts = json.load(f)
|
|
34
|
+
return known_contexts
|
|
35
|
+
except FileNotFoundError:
|
|
36
|
+
print(f"Error: File not found at {file_path}")
|
|
37
|
+
return None
|
|
38
|
+
except json.JSONDecodeError:
|
|
39
|
+
print(f"Error: Could not decode JSON from {file_path}")
|
|
40
|
+
return None
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"An unexpected error occurred: {e}")
|
|
43
|
+
return None
|
|
44
|
+
|
|
15
45
|
class LollmsLLMBinding(ABC):
|
|
16
46
|
"""Abstract base class for all LOLLMS LLM bindings"""
|
|
17
47
|
|
|
18
48
|
def __init__(self,
|
|
19
|
-
binding_name: Optional[str] ="unknown"
|
|
49
|
+
binding_name: Optional[str] ="unknown",
|
|
50
|
+
**kwargs
|
|
20
51
|
):
|
|
21
52
|
"""
|
|
22
53
|
Initialize the LollmsLLMBinding base class.
|
|
@@ -26,6 +57,18 @@ class LollmsLLMBinding(ABC):
|
|
|
26
57
|
"""
|
|
27
58
|
self.binding_name=binding_name
|
|
28
59
|
self.model_name = None #Must be set by the instance
|
|
60
|
+
self.default_ctx_size = kwargs.get("ctx_size")
|
|
61
|
+
self.default_n_predict = kwargs.get("n_predict")
|
|
62
|
+
self.default_stream = kwargs.get("stream")
|
|
63
|
+
self.default_temperature = kwargs.get("temperature")
|
|
64
|
+
self.default_top_k = kwargs.get("top_k")
|
|
65
|
+
self.default_top_p = kwargs.get("top_p")
|
|
66
|
+
self.default_repeat_penalty = kwargs.get("repeat_penalty")
|
|
67
|
+
self.default_repeat_last_n = kwargs.get("repeat_last_n")
|
|
68
|
+
self.default_seed = kwargs.get("seed")
|
|
69
|
+
self.default_n_threads = kwargs.get("n_threads")
|
|
70
|
+
self.default_streaming_callback = kwargs.get("streaming_callback")
|
|
71
|
+
|
|
29
72
|
|
|
30
73
|
@abstractmethod
|
|
31
74
|
def generate_text(self,
|
|
@@ -154,8 +197,38 @@ class LollmsLLMBinding(ABC):
|
|
|
154
197
|
"""
|
|
155
198
|
pass
|
|
156
199
|
|
|
157
|
-
def get_ctx_size(self, model_name:str
|
|
158
|
-
|
|
200
|
+
def get_ctx_size(self, model_name: Optional[str] = None) -> Optional[int]:
|
|
201
|
+
"""
|
|
202
|
+
Retrieves context size for a model from a hardcoded list.
|
|
203
|
+
|
|
204
|
+
This method checks if the model name contains a known base model identifier
|
|
205
|
+
(e.g., 'llama3.1', 'gemma2') to determine its context length. It's intended
|
|
206
|
+
as a failsafe when the context size cannot be retrieved directly from the
|
|
207
|
+
Ollama API.
|
|
208
|
+
"""
|
|
209
|
+
if model_name is None:
|
|
210
|
+
model_name = self.model_name
|
|
211
|
+
|
|
212
|
+
# Hardcoded context sizes for popular models. More specific names (e.g., 'llama3.1')
|
|
213
|
+
# should appear, as they will be checked first due to the sorting logic below.
|
|
214
|
+
known_contexts = load_known_contexts()
|
|
215
|
+
|
|
216
|
+
normalized_model_name = model_name.lower().strip()
|
|
217
|
+
|
|
218
|
+
# Sort keys by length in descending order. This ensures that a more specific
|
|
219
|
+
# name like 'llama3.1' is checked before a less specific name like 'llama3'.
|
|
220
|
+
sorted_base_models = sorted(known_contexts.keys(), key=len, reverse=True)
|
|
221
|
+
|
|
222
|
+
for base_name in sorted_base_models:
|
|
223
|
+
if base_name in normalized_model_name:
|
|
224
|
+
context_size = known_contexts[base_name]
|
|
225
|
+
ASCIIColors.warning(
|
|
226
|
+
f"Using hardcoded context size for model '{model_name}' "
|
|
227
|
+
f"based on base name '{base_name}': {context_size}"
|
|
228
|
+
)
|
|
229
|
+
return context_size
|
|
230
|
+
|
|
231
|
+
ASCIIColors.warning(f"Context size not found for model '{model_name}' in the hardcoded list.")
|
|
159
232
|
return None
|
|
160
233
|
|
|
161
234
|
|
|
@@ -349,16 +422,155 @@ class LollmsLLMBindingManager:
|
|
|
349
422
|
if binding_class:
|
|
350
423
|
return binding_class(**kwargs)
|
|
351
424
|
return None
|
|
352
|
-
|
|
353
|
-
def
|
|
425
|
+
@staticmethod
|
|
426
|
+
def _get_fallback_description(binding_name: str) -> Dict:
|
|
427
|
+
"""
|
|
428
|
+
Generates a default description dictionary for a binding without a description.yaml file.
|
|
429
|
+
"""
|
|
430
|
+
return {
|
|
431
|
+
"binding_name": binding_name,
|
|
432
|
+
"title": binding_name.replace("_", " ").title(),
|
|
433
|
+
"author": "Unknown",
|
|
434
|
+
"creation_date": "N/A",
|
|
435
|
+
"last_update_date": "N/A",
|
|
436
|
+
"description": f"A binding for {binding_name}. No description.yaml file was found, so common parameters are shown as a fallback.",
|
|
437
|
+
"input_parameters": [
|
|
438
|
+
{
|
|
439
|
+
"name": "model_name",
|
|
440
|
+
"type": "str",
|
|
441
|
+
"description": "The model name, ID, or filename to be used.",
|
|
442
|
+
"mandatory": False,
|
|
443
|
+
"default": ""
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"name": "host_address",
|
|
447
|
+
"type": "str",
|
|
448
|
+
"description": "The host address of the service (for API-based bindings).",
|
|
449
|
+
"mandatory": False,
|
|
450
|
+
"default": ""
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"name": "models_path",
|
|
454
|
+
"type": "str",
|
|
455
|
+
"description": "The path to the models directory (for local bindings).",
|
|
456
|
+
"mandatory": False,
|
|
457
|
+
"default": ""
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"name": "service_key",
|
|
461
|
+
"type": "str",
|
|
462
|
+
"description": "The API key or service key for authentication (if applicable).",
|
|
463
|
+
"mandatory": False,
|
|
464
|
+
"default": ""
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@staticmethod
|
|
470
|
+
def get_bindings_list(llm_bindings_dir: Union[str, Path]) -> List[Dict]:
|
|
354
471
|
"""
|
|
355
|
-
|
|
472
|
+
Lists all available LLM bindings by scanning a directory, loading their
|
|
473
|
+
description.yaml file if present, or providing a default description.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
llm_bindings_dir (Union[str, Path]): The path to the directory containing LLM binding folders.
|
|
356
477
|
|
|
357
478
|
Returns:
|
|
358
|
-
|
|
479
|
+
List[Dict]: A list of dictionaries, each describing a binding.
|
|
359
480
|
"""
|
|
360
|
-
|
|
481
|
+
bindings_dir = Path(llm_bindings_dir)
|
|
482
|
+
if not bindings_dir.is_dir():
|
|
483
|
+
return []
|
|
484
|
+
|
|
485
|
+
bindings_list = []
|
|
486
|
+
for binding_folder in bindings_dir.iterdir():
|
|
487
|
+
if binding_folder.is_dir() and (binding_folder / "__init__.py").exists():
|
|
488
|
+
binding_name = binding_folder.name
|
|
489
|
+
description_file = binding_folder / "description.yaml"
|
|
490
|
+
|
|
491
|
+
binding_info = {}
|
|
492
|
+
if description_file.exists():
|
|
493
|
+
try:
|
|
494
|
+
with open(description_file, 'r', encoding='utf-8') as f:
|
|
495
|
+
binding_info = yaml.safe_load(f)
|
|
496
|
+
binding_info['binding_name'] = binding_name
|
|
497
|
+
except Exception as e:
|
|
498
|
+
print(f"Error loading description.yaml for {binding_name}: {e}")
|
|
499
|
+
binding_info = LollmsLLMBindingManager._get_fallback_description(binding_name)
|
|
500
|
+
else:
|
|
501
|
+
binding_info = LollmsLLMBindingManager._get_fallback_description(binding_name)
|
|
502
|
+
|
|
503
|
+
bindings_list.append(binding_info)
|
|
361
504
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
505
|
+
return sorted(bindings_list, key=lambda b: b.get('title', b['binding_name']))
|
|
506
|
+
|
|
507
|
+
def get_available_bindings(self) -> List[Dict]:
|
|
508
|
+
"""
|
|
509
|
+
Retrieves a list of all available LLM bindings with their full descriptions.
|
|
510
|
+
|
|
511
|
+
This method scans the configured `llm_bindings_dir`, parsing the `description.yaml`
|
|
512
|
+
file for each valid binding. If a `description.yaml` is missing, a fallback
|
|
513
|
+
description with common parameters is generated. This is the primary method
|
|
514
|
+
for discovering available bindings and their configuration requirements.
|
|
515
|
+
|
|
516
|
+
Returns:
|
|
517
|
+
List[Dict]:
|
|
518
|
+
A list of dictionaries, where each dictionary represents the
|
|
519
|
+
full description of an available binding.
|
|
520
|
+
|
|
521
|
+
Each dictionary contains the following keys:
|
|
522
|
+
- ``binding_name`` (str): The programmatic name of the binding (its folder name).
|
|
523
|
+
- ``title`` (str): A user-friendly title for the binding.
|
|
524
|
+
- ``author`` (str): The creator of the binding.
|
|
525
|
+
- ``creation_date`` (str): The date the binding was created.
|
|
526
|
+
- ``last_update_date`` (str): The date of the last major update.
|
|
527
|
+
- ``description`` (str): A detailed explanation of the binding's purpose.
|
|
528
|
+
- ``input_parameters`` (List[Dict]): A list of parameters required to
|
|
529
|
+
configure the binding. Each parameter is a dictionary with:
|
|
530
|
+
- ``name`` (str): The parameter's name (e.g., 'model_name').
|
|
531
|
+
- ``type`` (str): The expected data type ('str', 'int', 'float', 'bool').
|
|
532
|
+
- ``description`` (str): A user-friendly description of the parameter.
|
|
533
|
+
- ``mandatory`` (bool): True if the parameter must be provided.
|
|
534
|
+
- ``default``: The default value for the parameter.
|
|
535
|
+
|
|
536
|
+
Example of a returned dictionary in the list:
|
|
537
|
+
.. code-block:: python
|
|
538
|
+
|
|
539
|
+
{
|
|
540
|
+
"binding_name": "ollama",
|
|
541
|
+
"title": "Ollama",
|
|
542
|
+
"author": "ParisNeo",
|
|
543
|
+
...
|
|
544
|
+
"input_parameters": [
|
|
545
|
+
{
|
|
546
|
+
"name": "host_address",
|
|
547
|
+
"type": "str",
|
|
548
|
+
"description": "The URL of the Ollama server.",
|
|
549
|
+
"mandatory": True,
|
|
550
|
+
"default": "http://localhost:11434"
|
|
551
|
+
},
|
|
552
|
+
...
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
"""
|
|
556
|
+
return LollmsLLMBindingManager.get_bindings_list(self.llm_bindings_dir)
|
|
557
|
+
|
|
558
|
+
def get_available_bindings(llm_bindings_dir: Union[str, Path] = None) -> List[Dict]:
|
|
559
|
+
"""
|
|
560
|
+
Lists all available LLM bindings with their detailed descriptions.
|
|
561
|
+
|
|
562
|
+
This function serves as a primary entry point for discovering what bindings
|
|
563
|
+
are available and how to configure them.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
llm_bindings_dir (Union[str, Path], optional):
|
|
567
|
+
The path to the LLM bindings directory. If None, it defaults to the
|
|
568
|
+
'llm_bindings' subdirectory relative to this file.
|
|
569
|
+
Defaults to None.
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
List[Dict]: A list of dictionaries, each describing a binding.
|
|
573
|
+
"""
|
|
574
|
+
if llm_bindings_dir is None:
|
|
575
|
+
llm_bindings_dir = Path(__file__).parent / "llm_bindings"
|
|
576
|
+
return LollmsLLMBindingManager.get_bindings_list(llm_bindings_dir)
|
|
@@ -4,7 +4,7 @@ import importlib
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Optional, List, Dict, Any, Union
|
|
6
6
|
from ascii_colors import trace_exception, ASCIIColors
|
|
7
|
-
|
|
7
|
+
import yaml
|
|
8
8
|
class LollmsMCPBinding(ABC):
|
|
9
9
|
"""
|
|
10
10
|
Abstract Base Class for LOLLMS Model Context Protocol (MCP) Bindings.
|
|
@@ -185,6 +185,7 @@ class LollmsMCPBindingManager:
|
|
|
185
185
|
return None
|
|
186
186
|
return None
|
|
187
187
|
|
|
188
|
+
|
|
188
189
|
def get_available_bindings(self) -> List[str]:
|
|
189
190
|
"""
|
|
190
191
|
Return list of available MCP binding names based on subdirectories.
|
|
@@ -195,4 +196,34 @@ class LollmsMCPBindingManager:
|
|
|
195
196
|
for item in self.mcp_bindings_dir.iterdir():
|
|
196
197
|
if item.is_dir() and (item / "__init__.py").exists():
|
|
197
198
|
available.append(item.name)
|
|
198
|
-
return available
|
|
199
|
+
return available
|
|
200
|
+
|
|
201
|
+
def get_binding_description(self, binding_name: str) -> Optional[Dict[str, Any]]:
|
|
202
|
+
"""
|
|
203
|
+
Loads and returns the content of the description.yaml file for a given binding.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
binding_name (str): The name of the binding.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Optional[Dict[str, Any]]: A dictionary with the parsed YAML content, or None if the file doesn't exist or is invalid.
|
|
210
|
+
"""
|
|
211
|
+
binding_dir = self.mcp_bindings_dir / binding_name
|
|
212
|
+
description_file = binding_dir / "description.yaml"
|
|
213
|
+
|
|
214
|
+
if not description_file.exists():
|
|
215
|
+
ASCIIColors.warning(f"No description.yaml found for MCP binding '{binding_name}'.")
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
with open(description_file, 'r', encoding='utf-8') as f:
|
|
220
|
+
description = yaml.safe_load(f)
|
|
221
|
+
return description
|
|
222
|
+
except yaml.YAMLError as e:
|
|
223
|
+
ASCIIColors.error(f"Error parsing description.yaml for MCP binding '{binding_name}': {e}")
|
|
224
|
+
trace_exception(e)
|
|
225
|
+
return None
|
|
226
|
+
except Exception as e:
|
|
227
|
+
ASCIIColors.error(f"Error reading description.yaml for MCP binding '{binding_name}': {e}")
|
|
228
|
+
trace_exception(e)
|
|
229
|
+
return None
|
|
@@ -21,15 +21,16 @@ class LocalMCPBinding(LollmsMCPBinding):
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
def __init__(self,
|
|
24
|
-
|
|
24
|
+
**kwargs: Any
|
|
25
|
+
):
|
|
25
26
|
"""
|
|
26
27
|
Initialize the LocalMCPBinding.
|
|
27
28
|
|
|
28
29
|
Args:
|
|
29
|
-
binding_name (str): The name of this binding.
|
|
30
30
|
tools_folder_path (str|Path) a folder where to find tools
|
|
31
31
|
"""
|
|
32
32
|
super().__init__(binding_name="LocalMCP")
|
|
33
|
+
tools_folder_path = kwargs.get("tools_folder_path")
|
|
33
34
|
if tools_folder_path:
|
|
34
35
|
try:
|
|
35
36
|
self.tools_folder_path: Optional[Path] = Path(tools_folder_path)
|
|
@@ -27,8 +27,8 @@ class RemoteMCPBinding(LollmsMCPBinding):
|
|
|
27
27
|
Tools from all connected servers are aggregated and prefixed with the server's alias.
|
|
28
28
|
"""
|
|
29
29
|
def __init__(self,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
**kwargs: Any
|
|
31
|
+
):
|
|
32
32
|
"""
|
|
33
33
|
Initializes the binding to connect to multiple MCP servers.
|
|
34
34
|
|
|
@@ -41,10 +41,11 @@ class RemoteMCPBinding(LollmsMCPBinding):
|
|
|
41
41
|
"main_server": {"server_url": "http://localhost:8787", "auth_config": {}},
|
|
42
42
|
"experimental_server": {"server_url": "http://test.server:9000"}
|
|
43
43
|
}
|
|
44
|
-
**
|
|
44
|
+
**kwargs (Any): Additional configuration parameters.
|
|
45
45
|
"""
|
|
46
46
|
super().__init__(binding_name="remote_mcp")
|
|
47
47
|
# initialization in case no servers are present
|
|
48
|
+
servers_infos: Dict[str, Dict[str, Any]] = kwargs.get("servers_infos", {})
|
|
48
49
|
self.servers = None
|
|
49
50
|
if not MCP_LIBRARY_AVAILABLE:
|
|
50
51
|
ASCIIColors.error(f"{self.binding_name}: MCP library not available. This binding will be disabled.")
|
|
@@ -56,8 +57,8 @@ class RemoteMCPBinding(LollmsMCPBinding):
|
|
|
56
57
|
|
|
57
58
|
### NEW: Store the overall configuration
|
|
58
59
|
self.config = {
|
|
59
|
-
"servers_infos": servers_infos,
|
|
60
|
-
**
|
|
60
|
+
"servers_infos": kwargs.get("servers_infos"),
|
|
61
|
+
**kwargs
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
### NEW: State management for multiple servers.
|
|
@@ -48,12 +48,10 @@ class StandardMCPBinding(LollmsMCPBinding):
|
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
50
|
def __init__(self,
|
|
51
|
-
|
|
52
|
-
**other_config_params: Any):
|
|
51
|
+
**kwargs: Any):
|
|
53
52
|
super().__init__(binding_name="standard_mcp")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
self.config.update(other_config_params)
|
|
53
|
+
self.config = kwargs
|
|
54
|
+
initial_servers = kwargs.get("initial_servers", {})
|
|
57
55
|
|
|
58
56
|
self._server_configs: Dict[str, Dict[str, Any]] = {}
|
|
59
57
|
# Type hint with ClientSession, actual obj if MCP_LIBRARY_AVAILABLE
|
|
@@ -14,10 +14,8 @@ class LollmsSTTBinding_Impl(LollmsSTTBinding):
|
|
|
14
14
|
"""Concrete implementation of the LollmsSTTBinding for the standard LOLLMS server."""
|
|
15
15
|
|
|
16
16
|
def __init__(self,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
service_key: Optional[str] = None,
|
|
20
|
-
verify_ssl_certificate: bool = True):
|
|
17
|
+
**kwargs
|
|
18
|
+
):
|
|
21
19
|
"""
|
|
22
20
|
Initialize the LOLLMS STT binding.
|
|
23
21
|
|
|
@@ -28,10 +26,10 @@ class LollmsSTTBinding_Impl(LollmsSTTBinding):
|
|
|
28
26
|
verify_ssl_certificate (bool): Whether to verify SSL certificates.
|
|
29
27
|
"""
|
|
30
28
|
super().__init__("lollms")
|
|
31
|
-
self.host_address=host_address
|
|
32
|
-
self.model_name=model_name
|
|
33
|
-
self.service_key=service_key
|
|
34
|
-
self.verify_ssl_certificate=verify_ssl_certificate
|
|
29
|
+
self.host_address=kwargs.get("host_address")
|
|
30
|
+
self.model_name=kwargs.get("model_name")
|
|
31
|
+
self.service_key=kwargs.get("service_key")
|
|
32
|
+
self.verify_ssl_certificate=kwargs.get("verify_ssl_certificate")
|
|
35
33
|
|
|
36
34
|
def transcribe_audio(self, audio_path: Union[str, Path], model: Optional[str] = None, **kwargs) -> str:
|
|
37
35
|
"""
|
|
@@ -70,8 +70,6 @@ class WhisperSTTBinding(LollmsSTTBinding):
|
|
|
70
70
|
WHISPER_MODEL_SIZES = ["tiny", "tiny.en", "base", "base.en", "small", "small.en", "medium", "medium.en", "large", "large-v1", "large-v2", "large-v3"]
|
|
71
71
|
|
|
72
72
|
def __init__(self,
|
|
73
|
-
model_name: str = "base", # Default Whisper model size
|
|
74
|
-
device: Optional[str] = None, # "cpu", "cuda", "mps", or None for auto
|
|
75
73
|
**kwargs # To catch any other LollmsSTTBinding standard args
|
|
76
74
|
):
|
|
77
75
|
"""
|
|
@@ -88,7 +86,7 @@ class WhisperSTTBinding(LollmsSTTBinding):
|
|
|
88
86
|
if not _whisper_installed:
|
|
89
87
|
raise ImportError(f"Whisper STT binding dependencies not met. Please ensure 'openai-whisper' and 'torch' are installed. Error: {_whisper_installation_error}")
|
|
90
88
|
|
|
91
|
-
self.device = device
|
|
89
|
+
self.device = kwargs.get("device",None)
|
|
92
90
|
if self.device is None: # Auto-detect if not specified
|
|
93
91
|
if torch.cuda.is_available():
|
|
94
92
|
self.device = "cuda"
|
|
@@ -101,7 +99,7 @@ class WhisperSTTBinding(LollmsSTTBinding):
|
|
|
101
99
|
|
|
102
100
|
self.loaded_model_name = None
|
|
103
101
|
self.model = None
|
|
104
|
-
self._load_whisper_model(model_name)
|
|
102
|
+
self._load_whisper_model(kwargs.get("model_name", "base")) # Default to "base" if not specified
|
|
105
103
|
|
|
106
104
|
|
|
107
105
|
def _load_whisper_model(self, model_name_to_load: str):
|
|
@@ -18,20 +18,19 @@ DEFAULT_WHISPERCPP_EXE_NAMES = ["main", "whisper-cli", "whisper"] # Common names
|
|
|
18
18
|
|
|
19
19
|
class WhisperCppSTTBinding(LollmsSTTBinding):
|
|
20
20
|
def __init__(self,
|
|
21
|
-
model_path: Union[str, Path], # Path to the GGUF Whisper model
|
|
22
|
-
whispercpp_exe_path: Optional[Union[str, Path]] = None, # Path to whisper.cpp executable
|
|
23
|
-
ffmpeg_path: Optional[Union[str, Path]] = None, # Path to ffmpeg executable (if not in PATH)
|
|
24
|
-
models_search_path: Optional[Union[str, Path]] = None, # Optional dir to scan for more models
|
|
25
|
-
default_language: str = "auto",
|
|
26
|
-
n_threads: int = 4,
|
|
27
|
-
# Catch LollmsSTTBinding standard args even if not directly used by this local binding
|
|
28
|
-
host_address: Optional[str] = None, # Not used for local binding
|
|
29
|
-
service_key: Optional[str] = None, # Not used for local binding
|
|
30
|
-
verify_ssl_certificate: bool = True, # Not used for local binding
|
|
31
21
|
**kwargs): # Catch-all for future compatibility or specific whisper.cpp params
|
|
32
22
|
|
|
33
|
-
super().__init__(binding_name="whispercpp")
|
|
34
|
-
|
|
23
|
+
super().__init__(binding_name="whispercpp")
|
|
24
|
+
|
|
25
|
+
# --- Extract values from kwargs with defaults ---
|
|
26
|
+
model_path = kwargs.get("model_path")
|
|
27
|
+
whispercpp_exe_path = kwargs.get("whispercpp_exe_path")
|
|
28
|
+
ffmpeg_path = kwargs.get("ffmpeg_path")
|
|
29
|
+
models_search_path = kwargs.get("models_search_path")
|
|
30
|
+
default_language = kwargs.get("default_language", "auto")
|
|
31
|
+
n_threads = kwargs.get("n_threads", 4)
|
|
32
|
+
extra_whisper_args = kwargs.get("extra_whisper_args", []) # e.g. ["--no-timestamps"]
|
|
33
|
+
|
|
35
34
|
# --- Validate FFMPEG ---
|
|
36
35
|
self.ffmpeg_exe = None
|
|
37
36
|
if ffmpeg_path:
|
|
@@ -42,7 +41,7 @@ class WhisperCppSTTBinding(LollmsSTTBinding):
|
|
|
42
41
|
raise FileNotFoundError(f"Provided ffmpeg_path '{ffmpeg_path}' not found or not executable.")
|
|
43
42
|
else:
|
|
44
43
|
self.ffmpeg_exe = shutil.which("ffmpeg")
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
if not self.ffmpeg_exe:
|
|
47
46
|
ASCIIColors.warning("ffmpeg not found in PATH or explicitly provided. Audio conversion will not be possible for non-WAV files or incompatible WAV files.")
|
|
48
47
|
ASCIIColors.warning("Please install ffmpeg and ensure it's in your system's PATH, or provide ffmpeg_path argument.")
|
|
@@ -63,7 +62,7 @@ class WhisperCppSTTBinding(LollmsSTTBinding):
|
|
|
63
62
|
self.whispercpp_exe = found_path
|
|
64
63
|
ASCIIColors.info(f"Found whisper.cpp executable via PATH: {self.whispercpp_exe}")
|
|
65
64
|
break
|
|
66
|
-
|
|
65
|
+
|
|
67
66
|
if not self.whispercpp_exe:
|
|
68
67
|
raise FileNotFoundError(
|
|
69
68
|
f"Whisper.cpp executable (tried: {', '.join(DEFAULT_WHISPERCPP_EXE_NAMES)}) not found in PATH or explicitly provided. "
|
|
@@ -79,11 +78,11 @@ class WhisperCppSTTBinding(LollmsSTTBinding):
|
|
|
79
78
|
self.model_path = Path(models_search_path, self.model_path).resolve()
|
|
80
79
|
else:
|
|
81
80
|
raise FileNotFoundError(f"Whisper GGUF model file not found at '{self.model_path}'. Also checked in models_search_path if applicable.")
|
|
82
|
-
|
|
81
|
+
|
|
83
82
|
self.models_search_path = Path(models_search_path).resolve() if models_search_path else None
|
|
84
83
|
self.default_language = default_language
|
|
85
84
|
self.n_threads = n_threads
|
|
86
|
-
self.extra_whisper_args =
|
|
85
|
+
self.extra_whisper_args = extra_whisper_args
|
|
87
86
|
|
|
88
87
|
ASCIIColors.green(f"WhisperCppSTTBinding initialized with model: {self.model_path}")
|
|
89
88
|
|
|
@@ -35,22 +35,11 @@ DALLE_MODELS = {
|
|
|
35
35
|
"max_prompt_length": 4000 # Characters
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
|
|
39
38
|
class DalleTTIBinding_Impl(LollmsTTIBinding):
|
|
40
39
|
"""
|
|
41
40
|
Concrete implementation of LollmsTTIBinding for OpenAI's DALL-E API.
|
|
42
41
|
"""
|
|
43
|
-
|
|
44
|
-
def __init__(self,
|
|
45
|
-
api_key: Optional[str] = None, # Can be None to check env var
|
|
46
|
-
model_name: str = "dall-e-3", # Default to DALL-E 3
|
|
47
|
-
default_size: Optional[str] = None, # e.g. "1024x1024"
|
|
48
|
-
default_quality: Optional[str] = None, # "standard" or "hd" (DALL-E 3)
|
|
49
|
-
default_style: Optional[str] = None, # "vivid" or "natural" (DALL-E 3)
|
|
50
|
-
host_address: str = DALLE_API_HOST, # OpenAI API host
|
|
51
|
-
verify_ssl_certificate: bool = True,
|
|
52
|
-
**kwargs # To catch any other lollms_client specific params like service_key/client_id
|
|
53
|
-
):
|
|
42
|
+
def __init__(self, **kwargs):
|
|
54
43
|
"""
|
|
55
44
|
Initialize the DALL-E TTI binding.
|
|
56
45
|
|
|
@@ -70,44 +59,56 @@ class DalleTTIBinding_Impl(LollmsTTIBinding):
|
|
|
70
59
|
"""
|
|
71
60
|
super().__init__(binding_name="dalle")
|
|
72
61
|
|
|
73
|
-
|
|
62
|
+
# Extract parameters from kwargs, providing defaults
|
|
63
|
+
self.api_key = kwargs.get("api_key")
|
|
64
|
+
self.model_name = kwargs.get("model_name")
|
|
65
|
+
self.default_size = kwargs.get("default_size")
|
|
66
|
+
self.default_quality = kwargs.get("default_quality")
|
|
67
|
+
self.default_style = kwargs.get("default_style")
|
|
68
|
+
self.host_address = kwargs.get("host_address", DALLE_API_HOST) # Provide default
|
|
69
|
+
self.verify_ssl_certificate = kwargs.get("verify_ssl_certificate", True) # Provide default
|
|
70
|
+
|
|
71
|
+
# Resolve API key from kwargs or environment variable
|
|
72
|
+
resolved_api_key = self.api_key
|
|
74
73
|
if not resolved_api_key:
|
|
75
74
|
ASCIIColors.info(f"API key not provided directly, checking environment variable '{OPENAI_API_KEY_ENV_VAR}'...")
|
|
76
75
|
resolved_api_key = os.environ.get(OPENAI_API_KEY_ENV_VAR)
|
|
77
76
|
|
|
78
77
|
if not resolved_api_key:
|
|
79
78
|
raise ValueError(f"OpenAI API key is required. Provide it directly or set the '{OPENAI_API_KEY_ENV_VAR}' environment variable.")
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
self.api_key = resolved_api_key
|
|
82
|
-
self.host_address = host_address
|
|
83
|
-
self.verify_ssl_certificate = verify_ssl_certificate
|
|
84
81
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
# Model name validation
|
|
83
|
+
if not self.model_name:
|
|
84
|
+
raise ValueError("Model name is required.")
|
|
85
|
+
if self.model_name not in DALLE_MODELS:
|
|
86
|
+
raise ValueError(f"Unsupported DALL-E model: {self.model_name}. Supported models: {list(DALLE_MODELS.keys())}")
|
|
87
|
+
|
|
89
88
|
model_props = DALLE_MODELS[self.model_name]
|
|
90
89
|
|
|
91
|
-
#
|
|
92
|
-
self.current_size = default_size or model_props["default_size"]
|
|
90
|
+
# Size
|
|
91
|
+
self.current_size = self.default_size or model_props["default_size"]
|
|
93
92
|
if self.current_size not in model_props["sizes"]:
|
|
94
93
|
raise ValueError(f"Unsupported size '{self.current_size}' for model '{self.model_name}'. Supported sizes: {model_props['sizes']}")
|
|
95
94
|
|
|
95
|
+
# Quality
|
|
96
96
|
if model_props["supports_quality"]:
|
|
97
|
-
self.current_quality = default_quality or model_props["default_quality"]
|
|
97
|
+
self.current_quality = self.default_quality or model_props["default_quality"]
|
|
98
98
|
if self.current_quality not in model_props["qualities"]:
|
|
99
99
|
raise ValueError(f"Unsupported quality '{self.current_quality}' for model '{self.model_name}'. Supported qualities: {model_props['qualities']}")
|
|
100
100
|
else:
|
|
101
|
-
self.current_quality = None
|
|
101
|
+
self.current_quality = None # Explicitly None if not supported
|
|
102
102
|
|
|
103
|
+
# Style
|
|
103
104
|
if model_props["supports_style"]:
|
|
104
|
-
self.current_style = default_style or model_props["default_style"]
|
|
105
|
+
self.current_style = self.default_style or model_props["default_style"]
|
|
105
106
|
if self.current_style not in model_props["styles"]:
|
|
106
107
|
raise ValueError(f"Unsupported style '{self.current_style}' for model '{self.model_name}'. Supported styles: {model_props['styles']}")
|
|
107
108
|
else:
|
|
108
|
-
self.current_style = None
|
|
109
|
-
|
|
110
|
-
#
|
|
109
|
+
self.current_style = None # Explicitly None if not supported
|
|
110
|
+
|
|
111
|
+
# Client ID
|
|
111
112
|
self.client_id = kwargs.get("service_key", kwargs.get("client_id", "dalle_client_user"))
|
|
112
113
|
|
|
113
114
|
|