lollms-client 0.12.6__py3-none-any.whl → 0.13.1__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.

Files changed (34) hide show
  1. examples/article_summary/article_summary.py +58 -0
  2. examples/deep_analyze/deep_analyse.py +30 -0
  3. examples/deep_analyze/deep_analyze_multiple_files.py +32 -0
  4. examples/function_call/functions_call_with images.py +52 -0
  5. examples/personality_test/chat_test.py +37 -0
  6. examples/personality_test/chat_with_aristotle.py +42 -0
  7. examples/personality_test/tesks_test.py +62 -0
  8. examples/simple_text_gen_test.py +173 -0
  9. examples/simple_text_gen_with_image_test.py +166 -0
  10. examples/test_local_models/local_chat.py +9 -0
  11. examples/text_2_audio.py +77 -0
  12. examples/text_2_image.py +140 -0
  13. examples/text_and_image_2_audio.py +59 -0
  14. examples/text_gen.py +28 -0
  15. lollms_client/__init__.py +3 -2
  16. lollms_client/llm_bindings/lollms/__init__.py +13 -11
  17. lollms_client/llm_bindings/ollama/__init__.py +44 -60
  18. lollms_client/llm_bindings/openai/__init__.py +69 -29
  19. lollms_client/llm_bindings/tensor_rt/__init__.py +603 -0
  20. lollms_client/llm_bindings/transformers/__init__.py +7 -11
  21. lollms_client/llm_bindings/vllm/__init__.py +603 -0
  22. lollms_client/lollms_core.py +14 -4
  23. lollms_client/lollms_llm_binding.py +5 -25
  24. {lollms_client-0.12.6.dist-info → lollms_client-0.13.1.dist-info}/METADATA +19 -12
  25. lollms_client-0.13.1.dist-info/RECORD +52 -0
  26. {lollms_client-0.12.6.dist-info → lollms_client-0.13.1.dist-info}/WHEEL +1 -1
  27. {lollms_client-0.12.6.dist-info → lollms_client-0.13.1.dist-info}/top_level.txt +1 -0
  28. lollms_client/lollms_personality.py +0 -403
  29. lollms_client/lollms_personality_worker.py +0 -1485
  30. lollms_client/lollms_stt.py +0 -35
  31. lollms_client/lollms_tti.py +0 -35
  32. lollms_client/lollms_tts.py +0 -39
  33. lollms_client-0.12.6.dist-info/RECORD +0 -41
  34. {lollms_client-0.12.6.dist-info → lollms_client-0.13.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,77 @@
1
+ from lollms_client import LollmsClient # Removed LollmsTTS import
2
+ from lollms_client.lollms_types import MSG_TYPE # Import MSG_TYPE if callback uses it
3
+ import random
4
+ from ascii_colors import ASCIIColors # Assuming this might be used for better output
5
+
6
+ # Initialize the LollmsClient instance, enabling the TTS binding
7
+ # We'll use the 'lollms' tts binding by default.
8
+ # The host_address in LollmsClient will be used by the lollms tts binding.
9
+ lc = LollmsClient(
10
+ tts_binding_name="lollms" # Explicitly enable the lollms TTS binding
11
+ )
12
+
13
+ if not lc.tts:
14
+ ASCIIColors.error("TTS binding could not be initialized. Please check your LollmsClient setup and server.")
15
+ exit()
16
+
17
+ voices = lc.tts.list_voices() # Use the new method via lc.tts
18
+
19
+ # Pick a voice randomly
20
+ if voices:
21
+ random_voice = random.choice(voices)
22
+ ASCIIColors.info(f"Selected voice: {random_voice}")
23
+ else:
24
+ ASCIIColors.warning("No voices found. Using server default.")
25
+ random_voice = None # Or a known default like "main_voice"
26
+
27
+ # Generate Text
28
+ # response = lc.generate_text(prompt="Once upon a time", stream=False, temperature=0.5)
29
+ # print(response)
30
+
31
+ # # Generate Completion
32
+ # response = lc.generate_completion(prompt="What is the capital of France", stream=False, temperature=0.5)
33
+ # print(response)
34
+
35
+
36
+ def cb(chunk, msg_type: MSG_TYPE, params=None, metadata=None): # Added params and metadata for full signature
37
+ print(chunk,end="",flush=True)
38
+ return True # Callback should return True to continue streaming
39
+
40
+ response_text = lc.generate_text(prompt="One plus one equals ", stream=False, temperature=0.5, streaming_callback=cb)
41
+ print() # For newline after streaming
42
+ ASCIIColors.green(f"Generated text: {response_text}")
43
+ print()
44
+
45
+ if response_text and not isinstance(response_text, dict): # Check if generation was successful
46
+ try:
47
+ # Assuming generate_audio now might return status or file path rather than direct audio bytes for 'lollms' binding
48
+ # based on its current server behavior.
49
+ # If generate_audio for 'lollms' binding is expected to save a file and return status:
50
+ audio_generation_status = lc.tts.generate_audio(response_text, voice=random_voice, fn="output_example_text_2_audio.wav") # Example filename
51
+ ASCIIColors.info(f"Audio generation request status: {audio_generation_status}")
52
+ ASCIIColors.yellow(f"Audio should be saved as 'output_example_text_2_audio.wav' by the server in its default output path.")
53
+
54
+ except Exception as e:
55
+ ASCIIColors.error(f"Error during text to audio conversion: {e}")
56
+ else:
57
+ ASCIIColors.error(f"Text generation failed or returned an error: {response_text}")
58
+
59
+
60
+ # List Mounted Personalities (This is an LLM feature, specific to 'lollms' LLM binding)
61
+ if lc.binding and hasattr(lc.binding, 'lollms_listMountedPersonalities'):
62
+ personalities_response = lc.listMountedPersonalities()
63
+ ASCIIColors.blue("\nMounted Personalities:")
64
+ print(personalities_response)
65
+ else:
66
+ ASCIIColors.yellow("\nlistMountedPersonalities not available for the current LLM binding.")
67
+
68
+
69
+ # List Models (This is an LLM feature)
70
+ models_response = lc.listModels()
71
+ ASCIIColors.blue("\nAvailable LLM Models:")
72
+ print(models_response)
73
+
74
+ # List available TTS bindings (for demonstration)
75
+ if hasattr(lc, 'tts_binding_manager'):
76
+ available_tts_bindings = lc.tts_binding_manager.get_available_bindings()
77
+ ASCIIColors.cyan(f"\nAvailable TTS bindings in client: {available_tts_bindings}")
@@ -0,0 +1,140 @@
1
+ from lollms_client import LollmsClient
2
+ from lollms_client.lollms_types import MSG_TYPE # If using callbacks
3
+ from ascii_colors import ASCIIColors, trace_exception
4
+ from PIL import Image
5
+ from pathlib import Path
6
+ import io
7
+ import os
8
+
9
+ # --- Configuration ---
10
+ # This client_id should match one known by your LoLLMs WebUI if security is enabled for these endpoints.
11
+ # For a default local setup, it might not be strictly checked for /generate_image,
12
+ # but IS required for /list_tti_services, /get_active_tti_settings, /set_active_tti_settings.
13
+ LOLLMS_CLIENT_ID = "my_lollms_client_id" # Replace with your actual client ID or a test one
14
+
15
+ # Initialize LollmsClient, enabling the TTI 'lollms' binding
16
+ # The service_key here is used as client_id by the TTI binding for lollms
17
+ lc = LollmsClient(
18
+ host_address="http://localhost:9600",
19
+ tti_binding_name="lollms"
20
+ )
21
+
22
+ if not lc.tti:
23
+ ASCIIColors.error("TTI binding could not be initialized. Please check LollmsClient setup.")
24
+ exit()
25
+
26
+ def test_list_tti_services():
27
+ ASCIIColors.cyan("\n--- Testing List TTI Services ---")
28
+ try:
29
+ # client_id is taken from lc.service_key by the binding
30
+ services = lc.tti.list_services()
31
+ if services:
32
+ ASCIIColors.green("Available TTI Services:")
33
+ for i, service in enumerate(services):
34
+ print(f" {i+1}. Name: {service.get('name')}, Caption: {service.get('caption')}")
35
+ else:
36
+ ASCIIColors.yellow("No TTI services listed or an empty list was returned.")
37
+ except Exception as e:
38
+ ASCIIColors.error(f"Error listing TTI services: {e}")
39
+ trace_exception(e)
40
+
41
+ def test_get_tti_settings():
42
+ ASCIIColors.cyan("\n--- Testing Get Active TTI Settings ---")
43
+ try:
44
+ # client_id is taken from lc.service_key by the binding
45
+ settings = lc.tti.get_settings()
46
+ if settings: # Server returns a list for settings template
47
+ ASCIIColors.green("Current Active TTI Settings/Template:")
48
+ # Assuming settings is a list of dicts (template format)
49
+ for setting_item in settings:
50
+ print(f" - Name: {setting_item.get('name')}, Type: {setting_item.get('type')}, Value: {setting_item.get('value')}, Help: {setting_item.get('help')}")
51
+ elif isinstance(settings, dict) and not settings: # Empty dict if no TTI active
52
+ ASCIIColors.yellow("No active TTI service or settings configured on the server.")
53
+ else:
54
+ ASCIIColors.yellow("Could not retrieve TTI settings or format unexpected.")
55
+ print(f"Received: {settings}")
56
+ except Exception as e:
57
+ ASCIIColors.error(f"Error getting TTI settings: {e}")
58
+ trace_exception(e)
59
+
60
+ def test_set_tti_settings():
61
+ ASCIIColors.cyan("\n--- Testing Set Active TTI Settings (Illustrative) ---")
62
+ ASCIIColors.yellow("Note: This test requires knowing the exact settings structure of your active TTI service.")
63
+ ASCIIColors.yellow("Skipping actual setting change to avoid misconfiguration.")
64
+ # Example: If you knew your TTI service had a 'quality' setting:
65
+ # example_settings_to_set = [
66
+ # {"name": "quality", "value": "high", "type": "str", "help": "Image quality"},
67
+ # # ... other settings from get_settings()
68
+ # ]
69
+ # try:
70
+ # # client_id is taken from lc.service_key
71
+ # success = lc.tti.set_settings(example_settings_to_set)
72
+ # if success:
73
+ # ASCIIColors.green("Successfully sent settings update request.")
74
+ # else:
75
+ # ASCIIColors.red("Failed to set TTI settings (server indicated failure or no change).")
76
+ # except Exception as e:
77
+ # ASCIIColors.error(f"Error setting TTI settings: {e}")
78
+
79
+ def test_generate_image():
80
+ ASCIIColors.cyan("\n--- Testing Generate Image ---")
81
+ prompt = "A futuristic cityscape at sunset, neon lights, flying vehicles"
82
+ negative_prompt = "blurry, low quality, ugly, text, watermark"
83
+ width = 512
84
+ height = 512
85
+ home_dir = Path.home()
86
+ documents_dir = home_dir / "Documents"
87
+ output_filename = documents_dir/"generated_lollms_image.jpg"
88
+
89
+ ASCIIColors.info(f"Prompt: {prompt}")
90
+ ASCIIColors.info(f"Negative Prompt: {negative_prompt}")
91
+ ASCIIColors.info(f"Dimensions: {width}x{height}")
92
+
93
+ try:
94
+ image_bytes = lc.tti.generate_image(
95
+ prompt=prompt,
96
+ negative_prompt=negative_prompt,
97
+ width=width,
98
+ height=height
99
+ # You can add other kwargs here if your TTI service supports them, e.g., seed=12345
100
+ )
101
+
102
+ if image_bytes:
103
+ ASCIIColors.green(f"Image generated successfully ({len(image_bytes)} bytes).")
104
+ try:
105
+ image = Image.open(io.BytesIO(image_bytes))
106
+ image.save(output_filename)
107
+ ASCIIColors.green(f"Image saved as {output_filename}")
108
+ # Attempt to show image if possible (platform dependent)
109
+ if os.name == 'nt': # Windows
110
+ os.startfile(output_filename)
111
+ elif os.name == 'posix': # MacOS/Linux
112
+ try:
113
+ import subprocess
114
+ opener = "open" if platform.system() == "Darwin" else "xdg-open"
115
+ subprocess.call([opener, output_filename])
116
+ except:
117
+ ASCIIColors.yellow(f"Could not auto-open image. Please find it at {output_filename}")
118
+
119
+ except Exception as e:
120
+ ASCIIColors.error(f"Error processing or saving image: {e}")
121
+ # Save raw bytes if PIL fails, for debugging
122
+ with open("generated_lollms_image_raw.data", "wb") as f_raw:
123
+ f_raw.write(image_bytes)
124
+ ASCIIColors.yellow("Raw image data saved as generated_lollms_image_raw.data for inspection.")
125
+
126
+ else:
127
+ ASCIIColors.red("Image generation returned empty bytes.")
128
+
129
+ except Exception as e:
130
+ ASCIIColors.error(f"Error during image generation: {e}")
131
+ trace_exception(e)
132
+
133
+ if __name__ == "__main__":
134
+ # Test management functions first
135
+ test_list_tti_services()
136
+ test_get_tti_settings()
137
+ test_set_tti_settings() # Currently illustrative
138
+
139
+ # Then test image generation
140
+ test_generate_image()
@@ -0,0 +1,59 @@
1
+ """
2
+ Author: ParisNeo, a computer geek passionate about AI
3
+
4
+ This example code demonstrates how to use the LoLLMs (Lord of Large Language Models) system to capture an image from a webcam, send it to the LollmsClient for analysis, and receive a descriptive response. The response is then converted to audio using the LollmsXTTS service.
5
+
6
+ Requirements:
7
+ - LoLLMs should be up and running.
8
+ - The XTTS service within LoLLMs must be working.
9
+
10
+ Steps:
11
+ 1. Initialize the LollmsClient instance.
12
+ 2. Fetch available voices and randomly select one.
13
+ 3. Capture an image from the webcam and save it to a file.
14
+ 4. Generate a descriptive text for the captured image using the LollmsClient.
15
+ 5. Convert the generated text to audio using the selected voice.
16
+
17
+ Make sure you have the necessary dependencies installed and your webcam is accessible.
18
+ """
19
+ import cv2
20
+ from lollms_client import LollmsClient
21
+ from lollms_client.lollms_tts_binding import LollmsTTS
22
+ import random
23
+
24
+ # Initialize the LollmsClient instance
25
+ lc = LollmsClient("http://localhost:9600")
26
+ tts = LollmsTTS(lc)
27
+ voices = tts.get_voices()
28
+
29
+ # Pick a voice randomly
30
+ random_voice = random.choice(voices)
31
+ print(f"Selected voice: {random_voice}")
32
+
33
+ # Capture image from webcam and save it to a file
34
+ def capture_image(file_path):
35
+ cap = cv2.VideoCapture(0)
36
+ if not cap.isOpened():
37
+ raise Exception("Could not open webcam")
38
+
39
+ ret, frame = cap.read()
40
+ if not ret:
41
+ raise Exception("Failed to capture image")
42
+
43
+ cv2.imwrite(file_path, frame)
44
+ cap.release()
45
+
46
+ # File path to save the captured image
47
+ image_path = "captured_image.jpg"
48
+
49
+ # Capture and save the image
50
+ capture_image(image_path)
51
+
52
+ # Function to handle streaming callback
53
+ def cb(chunk, type):
54
+ print(chunk, end="", flush=True)
55
+
56
+ # Generate text with image
57
+ response = lc.generate_with_images(prompt="user: describe the content of the image.\nassistant: ", images=[image_path], stream=False, temperature=0.5, streaming_callback=cb)
58
+ print(f"response: {response}")
59
+ tts.text2Audio(response, random_voice)
examples/text_gen.py ADDED
@@ -0,0 +1,28 @@
1
+ from lollms_client import LollmsClient
2
+
3
+ # Initialize the LollmsClient instance
4
+ lc = LollmsClient("http://localhost:9600")
5
+ # Generate Text
6
+ # response = lc.generate_text(prompt="Once upon a time", stream=False, temperature=0.5)
7
+ # print(response)
8
+
9
+ # # Generate Completion
10
+ # response = lc.generate_completion(prompt="What is the capital of France", stream=False, temperature=0.5)
11
+ # print(response)
12
+
13
+ def cb(chunk, type):
14
+ print(chunk,end="",flush=True)
15
+
16
+ response = lc.generate_text(prompt="One plus one equals ", stream=False, temperature=0.5, streaming_callback=cb)
17
+ print()
18
+ print(response)
19
+ print()
20
+
21
+
22
+ # List Mounted Personalities
23
+ response = lc.listMountedPersonalities()
24
+ print(response)
25
+
26
+ # List Models
27
+ response = lc.listModels()
28
+ print(response)
lollms_client/__init__.py CHANGED
@@ -6,15 +6,16 @@ from lollms_client.lollms_discussion import LollmsDiscussion, LollmsMessage
6
6
  from lollms_client.lollms_utilities import PromptReshaper # Keep general utilities
7
7
  from lollms_client.lollms_functions import FunctionCalling_Library
8
8
 
9
+ __version__ = "0.13.1"
10
+
9
11
  # Optionally, you could define __all__ if you want to be explicit about exports
10
12
  __all__ = [
11
13
  "LollmsClient",
12
14
  "ELF_COMPLETION_FORMAT",
13
15
  "TasksLibrary",
14
16
  "MSG_TYPE",
15
- "LollmsPersonality",
16
17
  "LollmsDiscussion",
17
18
  "LollmsMessage",
18
19
  "PromptReshaper",
19
20
  "FunctionCalling_Library"
20
- ]
21
+ ]
@@ -21,8 +21,9 @@ class LollmsLLMBinding(LollmsLLMBinding):
21
21
  model_name: str = "",
22
22
  service_key: str = None,
23
23
  verify_ssl_certificate: bool = True,
24
- personality: Optional[int] = None,
25
- default_completion_format: ELF_COMPLETION_FORMAT = ELF_COMPLETION_FORMAT.Chat):
24
+ personality: Optional[int] = None,
25
+ **kwargs
26
+ ):
26
27
  """
27
28
  Initialize the LOLLMS binding.
28
29
 
@@ -34,13 +35,14 @@ class LollmsLLMBinding(LollmsLLMBinding):
34
35
  personality (Optional[int]): Personality ID for generation. Defaults to None.
35
36
  """
36
37
  super().__init__(
37
- binding_name = "lollms",
38
- host_address=host_address if host_address is not None else self.DEFAULT_HOST_ADDRESS,
39
- model_name=model_name,
40
- service_key=service_key,
41
- verify_ssl_certificate=verify_ssl_certificate,
42
- default_completion_format=default_completion_format
38
+ binding_name = "lollms"
43
39
  )
40
+
41
+ self.host_address=host_address if host_address is not None else self.DEFAULT_HOST_ADDRESS
42
+ self.model_name=model_name
43
+ self.service_key=service_key
44
+ self.verify_ssl_certificate=verify_ssl_certificate
45
+ self.default_completion_format=kwargs.get("default_completion_format",ELF_COMPLETION_FORMAT.Chat)
44
46
  self.personality = personality
45
47
  self.model = None
46
48
 
@@ -133,7 +135,7 @@ class LollmsLLMBinding(LollmsLLMBinding):
133
135
  if not stream:
134
136
  if response.status_code == 200:
135
137
  try:
136
- text = response.text.strip().rstrip('!')
138
+ text = response.text.strip()
137
139
  return text
138
140
  except Exception as ex:
139
141
  return {"status": False, "error": str(ex)}
@@ -276,8 +278,8 @@ class LollmsLLMBinding(LollmsLLMBinding):
276
278
 
277
279
  if response.status_code == 200:
278
280
  try:
279
- text = json.loads(response.content.decode("utf-8"))
280
- return text
281
+ models = json.loads(response.content.decode("utf-8"))
282
+ return [{"model_name":m} for m in models]
281
283
  except Exception as ex:
282
284
  return {"status": False, "error": str(ex)}
283
285
  else:
@@ -20,62 +20,44 @@ BindingName = "OllamaBinding"
20
20
  def count_tokens_ollama(
21
21
  text_to_tokenize: str,
22
22
  model_name: str,
23
- ollama_host: str = "http://localhost:11434",
24
- timeout: int = 30,
25
- verify_ssl_certificate: bool = True,
26
- headers: Optional[Dict[str, str]] = None
23
+ ollama_client: ollama.Client,
27
24
  ) -> int:
28
25
  """
29
- Counts the number of tokens in a given text using a specified Ollama model
30
- by calling the Ollama server's /api/tokenize endpoint.
26
+ Counts the number of tokens in a given text for a specified Ollama model
27
+ by making a minimal request to the /api/generate endpoint and extracting
28
+ the 'prompt_eval_count' from the response.
29
+
30
+ This method is generally more accurate for the specific Ollama model instance
31
+ than using an external tokenizer, but it incurs the overhead of an API call
32
+ and model processing for the prompt.
31
33
 
32
34
  Args:
33
- text_to_tokenize (str): The text to be tokenized.
34
- model_name (str): The name of the Ollama model to use (e.g., "llama3", "mistral").
35
- ollama_host (str): The base URL of the Ollama server (default: "http://localhost:11434").
36
- timeout (int): Timeout for the request in seconds (default: 30).
37
- verify_ssl_certificate (bool): Whether to verify SSL.
38
- headers (Optional[Dict[str, str]]): Optional headers for the request.
35
+ text_to_tokenize: The string to tokenize.
36
+ model_name: The name of the Ollama model (e.g., "llama3:8b", "mistral").
37
+ ollama_host: The URL of the Ollama API host.
38
+ timeout: Timeout for the request to Ollama.
39
+ verify_ssl_certificate: Whether to verify SSL certificates for the Ollama host.
40
+ headers: Optional custom headers for the request to Ollama.
41
+ num_predict_for_eval: How many tokens to ask the model to "predict" to get
42
+ the prompt evaluation count. 0 is usually sufficient and most efficient.
43
+ If 0 doesn't consistently yield `prompt_eval_count`, try 1.
39
44
 
40
45
  Returns:
41
- int: The number of tokens. Returns -1 if an error occurs.
42
- """
43
- api_url = f"{ollama_host.rstrip('/')}/api/tokenize"
44
- payload = {
45
- "model": model_name,
46
- "prompt": text_to_tokenize
47
- }
48
- request_headers = headers if headers else {}
49
-
50
- try:
51
- response = requests.post(api_url, json=payload, timeout=timeout, verify=verify_ssl_certificate, headers=request_headers)
52
- response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
53
-
54
- response_data = response.json()
55
-
56
- if "tokens" in response_data and isinstance(response_data["tokens"], list):
57
- return len(response_data["tokens"])
58
- else:
59
- ASCIIColors.warning(
60
- f"Ollama response for token count did not contain a 'tokens' list. Response: {response_data}"
61
- )
62
- return -1 # Or raise ValueError
63
-
64
- except requests.exceptions.HTTPError as http_err:
65
- ASCIIColors.error(f"HTTP error occurred during token count: {http_err} - {http_err.response.text if http_err.response else 'No response text'}")
66
- return -1
67
- except requests.exceptions.RequestException as req_err:
68
- ASCIIColors.error(f"Request error occurred during token count: {req_err}")
69
- return -1
70
- except json.JSONDecodeError as json_err:
71
- ASCIIColors.error(
72
- f"Failed to decode JSON response from Ollama during token count: {json_err}. Response text: {response.text if hasattr(response, 'text') else 'No response object'}"
73
- )
74
- return -1
75
- except Exception as e:
76
- ASCIIColors.error(f"An unexpected error occurred during token count: {e}")
77
- return -1
46
+ The number of tokens as reported by 'prompt_eval_count'.
78
47
 
48
+ Raises:
49
+ requests.exceptions.RequestException: If the API request fails.
50
+ KeyError: If 'prompt_eval_count' is not found in the response.
51
+ json.JSONDecodeError: If the response is not valid JSON.
52
+ RuntimeError: For other operational errors.
53
+ """
54
+ res = ollama_client.chat(
55
+ model=model_name,
56
+ messages=[{"role":"system","content":""},{"role":"user", "content":text_to_tokenize}],
57
+ stream=False,options={"num_predict":1}
58
+ )
59
+
60
+ return res.prompt_eval_count-5
79
61
  class OllamaBinding(LollmsLLMBinding):
80
62
  """Ollama-specific binding implementation using the ollama-python library."""
81
63
 
@@ -85,8 +67,8 @@ class OllamaBinding(LollmsLLMBinding):
85
67
  host_address: str = None,
86
68
  model_name: str = "",
87
69
  service_key: str = None,
88
- verify_ssl_certificate: bool = True,
89
- default_completion_format: ELF_COMPLETION_FORMAT = ELF_COMPLETION_FORMAT.Chat
70
+ default_completion_format: ELF_COMPLETION_FORMAT = ELF_COMPLETION_FORMAT.Chat,
71
+ verify_ssl_certificate: bool = True
90
72
  ):
91
73
  """
92
74
  Initialize the Ollama binding.
@@ -101,12 +83,13 @@ class OllamaBinding(LollmsLLMBinding):
101
83
  _host_address = host_address if host_address is not None else self.DEFAULT_HOST_ADDRESS
102
84
  super().__init__(
103
85
  binding_name=BindingName, # Use the module-level BindingName
104
- host_address=_host_address,
105
- model_name=model_name,
106
- service_key=service_key,
107
- verify_ssl_certificate=verify_ssl_certificate,
108
- default_completion_format=default_completion_format
109
86
  )
87
+ self.host_address=_host_address
88
+ self.model_name=model_name
89
+ self.service_key=service_key
90
+ self.verify_ssl_certificate=verify_ssl_certificate
91
+ self.default_completion_format=default_completion_format
92
+
110
93
  if ollama is None:
111
94
  raise ImportError("Ollama library is not installed. Please run 'pip install ollama'.")
112
95
 
@@ -131,6 +114,7 @@ class OllamaBinding(LollmsLLMBinding):
131
114
  images: Optional[List[str]] = None, # List of image file paths
132
115
  n_predict: Optional[int] = None,
133
116
  stream: bool = False,
117
+ system_prompt = '',
134
118
  temperature: float = 0.7, # Ollama default is 0.8, common default 0.7
135
119
  top_k: int = 40, # Ollama default is 40
136
120
  top_p: float = 0.9, # Ollama default is 0.9
@@ -190,7 +174,7 @@ class OllamaBinding(LollmsLLMBinding):
190
174
  # If images were base64 strings, they would need decoding to bytes first.
191
175
  processed_images.append(img_path)
192
176
 
193
- messages = [{'role': 'user', 'content': prompt, 'images': processed_images if processed_images else None}]
177
+ messages = [{'role': 'system', 'content':system_prompt},{'role': 'user', 'content': prompt, 'images': processed_images if processed_images else None}]
194
178
 
195
179
  if stream:
196
180
  response_stream = self.ollama_client.chat(
@@ -313,7 +297,7 @@ class OllamaBinding(LollmsLLMBinding):
313
297
  if not self.model_name:
314
298
  ASCIIColors.warning("Cannot count tokens, model_name is not set.")
315
299
  return -1
316
- return count_tokens_ollama(text, self.model_name, self.host_address, verify_ssl_certificate=self.verify_ssl_certificate, headers=self.ollama_client_headers)
300
+ return count_tokens_ollama(text, self.model_name, self.ollama_client)
317
301
 
318
302
  def embed(self, text: str, **kwargs) -> List[float]:
319
303
  """
@@ -333,7 +317,7 @@ class OllamaBinding(LollmsLLMBinding):
333
317
  if not self.ollama_client:
334
318
  raise Exception("Ollama client not initialized.")
335
319
 
336
- model_to_use = kwargs.get("model", self.model_name)
320
+ model_to_use = kwargs.get("model", "bge-m3")
337
321
  if not model_to_use:
338
322
  raise ValueError("Model name for embedding must be specified either in init or via kwargs.")
339
323
 
@@ -573,4 +557,4 @@ if __name__ == '__main__':
573
557
  ASCIIColors.error(f"An error occurred during testing: {e}")
574
558
  trace_exception(e)
575
559
 
576
- ASCIIColors.yellow("\nOllamaBinding test finished.")
560
+ ASCIIColors.yellow("\nOllamaBinding test finished.")
@@ -7,6 +7,8 @@ from lollms_client.lollms_utilities import encode_image
7
7
  from lollms_client.lollms_types import ELF_COMPLETION_FORMAT
8
8
  from typing import Optional, Callable, List, Union
9
9
  from ascii_colors import ASCIIColors, trace_exception
10
+ from typing import List, Dict
11
+
10
12
  import pipmaster as pm
11
13
 
12
14
  pm.ensure_packages(["openai","tiktoken"])
@@ -40,14 +42,16 @@ class OpenAIBinding(LollmsLLMBinding):
40
42
  """
41
43
  super().__init__(
42
44
  binding_name = "openai",
43
- host_address=host_address if host_address is not None else self.DEFAULT_HOST_ADDRESS,
44
- model_name=model_name,
45
- service_key=service_key,
46
- verify_ssl_certificate=verify_ssl_certificate,
47
- default_completion_format=default_completion_format
48
45
  )
49
- self.service_key = os.getenv("OPENAI_API_KEY","")
50
- self.client = openai.OpenAI(base_url=host_address)
46
+ self.host_address=host_address
47
+ self.model_name=model_name
48
+ self.service_key=service_key
49
+ self.verify_ssl_certificate=verify_ssl_certificate
50
+ self.default_completion_format=default_completion_format
51
+
52
+ if not self.service_key:
53
+ self.service_key = os.getenv("OPENAI_API_KEY", self.service_key)
54
+ self.client = openai.OpenAI(api_key=self.service_key, base_url=host_address)
51
55
  self.completion_format = ELF_COMPLETION_FORMAT.Chat
52
56
 
53
57
 
@@ -134,7 +138,7 @@ class OpenAIBinding(LollmsLLMBinding):
134
138
  except Exception as ex:
135
139
  word = ""
136
140
  if streaming_callback is not None:
137
- if not streaming_callback(word, "MSG_TYPE_CHUNK"):
141
+ if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
138
142
  break
139
143
  if word:
140
144
  output += word
@@ -238,28 +242,64 @@ class OpenAIBinding(LollmsLLMBinding):
238
242
  "host_address": self.host_address,
239
243
  "model_name": self.model_name
240
244
  }
241
- def listModels(self):
242
- """ Lists available models """
243
- url = f'{self.host_address}/v1/models'
244
- headers = {
245
- 'accept': 'application/json',
246
- 'Authorization': f'Bearer {self.service_key}'
247
- }
248
- response = requests.get(url, headers=headers, verify= self.verify_ssl_certificate)
245
+
246
+ def listModels(self) -> List[Dict]:
247
+ # Known context lengths
248
+ known_context_lengths = {
249
+ "gpt-4o": 128000,
250
+ "gpt-4": 8192,
251
+ "gpt-4-0613": 8192,
252
+ "gpt-4-1106-preview": 128000,
253
+ "gpt-4-0125-preview": 128000,
254
+ "gpt-4-turbo": 128000,
255
+ "gpt-3.5-turbo": 4096,
256
+ "gpt-3.5-turbo-16k": 16000,
257
+ "gpt-3.5-turbo-1106": 16385,
258
+ "gpt-3.5-turbo-0125": 16385,
259
+ "text-davinci-003": 4097,
260
+ "text-davinci-002": 4097,
261
+ "davinci": 2049,
262
+ "curie": 2049,
263
+ "babbage": 2049,
264
+ "ada": 2049,
265
+ }
266
+
267
+ generation_prefixes = (
268
+ "gpt-",
269
+ "text-davinci",
270
+ "davinci",
271
+ "curie",
272
+ "babbage",
273
+ "ada"
274
+ )
275
+
276
+ models_info = []
277
+ prompt_buffer = 500
278
+
249
279
  try:
250
- data = response.json()
251
- model_info = []
252
-
253
- for model in data["data"]:
254
- model_name = model['id']
255
- owned_by = model['owned_by']
256
- created_datetime = model["created"]
257
- model_info.append({'model_name': model_name, 'owned_by': owned_by, 'created_datetime': created_datetime})
258
-
259
- return model_info
260
- except Exception as ex:
261
- trace_exception(ex)
262
- return []
280
+ models = self.client.models.list()
281
+ for model in models.data:
282
+ model_id = model.id
283
+ if model_id.startswith(generation_prefixes):
284
+ context_length = known_context_lengths.get(model_id, "unknown")
285
+ max_generation = (
286
+ context_length - prompt_buffer
287
+ if isinstance(context_length, int)
288
+ else "unknown"
289
+ )
290
+ models_info.append({
291
+ "model_name": model_id,
292
+ "owned_by": getattr(model, "owned_by", "N/A"),
293
+ "created": getattr(model, "created", "N/A"),
294
+ "context_length": context_length,
295
+ "max_generation": max_generation,
296
+ })
297
+ except Exception as e:
298
+ print(f"Failed to list models: {e}")
299
+
300
+ return models_info
301
+
302
+
263
303
  def load_model(self, model_name: str) -> bool:
264
304
  """
265
305
  Load a specific model into the OpenAI binding.