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

@@ -0,0 +1,176 @@
1
+ import os
2
+ import requests
3
+ import base64
4
+ from io import BytesIO
5
+ from pathlib import Path
6
+ from typing import Optional, List, Dict, Any, Union
7
+
8
+ from lollms_client.lollms_tti_binding import LollmsTTIBinding
9
+ from ascii_colors import trace_exception, ASCIIColors
10
+ import pipmaster as pm
11
+
12
+ pm.ensure_packages(["requests", "Pillow"])
13
+
14
+ from PIL import Image
15
+
16
+ BindingName = "StabilityAITTIBinding"
17
+
18
+ # Sourced from https://platform.stability.ai/docs/getting-started/models
19
+ STABILITY_AI_MODELS = [
20
+ # SD3
21
+ {"model_name": "stable-diffusion-3-medium", "display_name": "Stable Diffusion 3 Medium", "description": "Most advanced text-to-image model.", "owned_by": "Stability AI"},
22
+ {"model_name": "stable-diffusion-3-large", "display_name": "Stable Diffusion 3 Large", "description": "Most advanced model with higher quality.", "owned_by": "Stability AI"},
23
+ {"model_name": "stable-diffusion-3-large-turbo", "display_name": "Stable Diffusion 3 Large Turbo", "description": "Fast, high-quality generation.", "owned_by": "Stability AI"},
24
+ # SDXL
25
+ {"model_name": "stable-diffusion-xl-1024-v1-0", "display_name": "Stable Diffusion XL 1.0", "description": "High-quality 1024x1024 generation.", "owned_by": "Stability AI"},
26
+ {"model_name": "stable-diffusion-xl-beta-v2-2-2", "display_name": "SDXL Beta", "description": "Legacy anime-focused SDXL model.", "owned_by": "Stability AI"},
27
+ # SD 1.x & 2.x
28
+ {"model_name": "stable-diffusion-v1-6", "display_name": "Stable Diffusion 1.6", "description": "Improved version of SD 1.5.", "owned_by": "Stability AI"},
29
+ {"model_name": "stable-diffusion-2-1", "display_name": "Stable Diffusion 2.1", "description": "768x768 native resolution model.", "owned_by": "Stability AI"},
30
+ ]
31
+
32
+ class StabilityAITTIBinding(LollmsTTIBinding):
33
+ """Stability AI TTI binding for LoLLMS"""
34
+
35
+ def __init__(self, **kwargs):
36
+ super().__init__(binding_name=BindingName)
37
+ self.config = kwargs
38
+ self.api_key = self.config.get("api_key") or os.environ.get("STABILITY_API_KEY")
39
+ if not self.api_key:
40
+ raise ValueError("Stability AI API key is required. Please set it in the configuration or as STABILITY_API_KEY environment variable.")
41
+ self.model_name = self.config.get("model_name", "stable-diffusion-3-medium")
42
+
43
+ def listModels(self) -> list:
44
+ return STABILITY_AI_MODELS
45
+
46
+ def _get_api_url(self, task: str) -> str:
47
+ base_url = "https://api.stability.ai/v2beta/stable-image"
48
+ # SD3 models use a different endpoint structure
49
+ if "stable-diffusion-3" in self.model_name:
50
+ return f"{base_url}/generate/sd3"
51
+
52
+ task_map = {
53
+ "text2image": "generate/core",
54
+ "image2image": "edit/image-to-image",
55
+ "inpainting": "edit/in-painting",
56
+ "upscale": "edit/upscale"
57
+ }
58
+ if task not in task_map:
59
+ raise ValueError(f"Unsupported task for this model family: {task}")
60
+ return f"{base_url}/{task_map[task]}"
61
+
62
+ def _decode_image_input(self, item: Union[str, Path, bytes]) -> Image.Image:
63
+ if isinstance(item, bytes):
64
+ return Image.open(BytesIO(item))
65
+ s = str(item).strip()
66
+ if s.startswith("data:image/") and ";base64," in s:
67
+ b64 = s.split(";base64,")[-1]
68
+ return Image.open(BytesIO(base64.b64decode(b64)))
69
+ try:
70
+ p = Path(s)
71
+ if p.exists():
72
+ return Image.open(p)
73
+ except:
74
+ pass
75
+ if s.startswith("http"):
76
+ response = requests.get(s, stream=True)
77
+ response.raise_for_status()
78
+ return Image.open(response.raw)
79
+ # Fallback for raw base64
80
+ return Image.open(BytesIO(base64.b64decode(s)))
81
+
82
+ def generate_image(self, prompt: str, negative_prompt: str = "", width: int = 1024, height: int = 1024, **kwargs) -> bytes:
83
+ url = self._get_api_url("text2image")
84
+
85
+ data = {
86
+ "prompt": prompt,
87
+ "negative_prompt": negative_prompt,
88
+ "output_format": "png",
89
+ "seed": kwargs.get("seed", 0)
90
+ }
91
+
92
+ # SD3 uses aspect_ratio, older models use width/height
93
+ if "stable-diffusion-3" in self.model_name:
94
+ data["aspect_ratio"] = f"{width}:{height}"
95
+ data["model"] = self.model_name
96
+ else:
97
+ data["width"] = width
98
+ data["height"] = height
99
+ data["style_preset"] = kwargs.get("style_preset", "photographic")
100
+
101
+ headers = {"authorization": f"Bearer {self.api_key}", "accept": "image/*"}
102
+
103
+ try:
104
+ ASCIIColors.info(f"Requesting image from Stability AI ({self.model_name})...")
105
+ response = requests.post(url, headers=headers, files={"none": ''}, data=data)
106
+ response.raise_for_status()
107
+ return response.content
108
+ except Exception as e:
109
+ trace_exception(e)
110
+ try:
111
+ error_msg = response.json()
112
+ raise Exception(f"Stability AI API error: {error_msg}")
113
+ except:
114
+ raise Exception(f"Stability AI API request failed: {e}")
115
+
116
+ def edit_image(self, images: Union[str, List[str]], prompt: str, negative_prompt: Optional[str] = "", mask: Optional[str] = None, **kwargs) -> bytes:
117
+ init_image_bytes = BytesIO()
118
+ init_image = self._decode_image_input(images[0] if isinstance(images, list) else images)
119
+ init_image.save(init_image_bytes, format="PNG")
120
+
121
+ task = "inpainting" if mask else "image2image"
122
+ url = self._get_api_url(task)
123
+
124
+ files = {"image": init_image_bytes.getvalue()}
125
+ data = {
126
+ "prompt": prompt,
127
+ "negative_prompt": negative_prompt or "",
128
+ "output_format": "png",
129
+ "seed": kwargs.get("seed", 0)
130
+ }
131
+
132
+ if task == "inpainting":
133
+ mask_image_bytes = BytesIO()
134
+ mask_image = self._decode_image_input(mask)
135
+ mask_image.save(mask_image_bytes, format="PNG")
136
+ files["mask"] = mask_image_bytes.getvalue()
137
+ else: # image2image
138
+ data["strength"] = kwargs.get("strength", 0.6) # mode IMAGE_STRENGTH
139
+
140
+ headers = {"authorization": f"Bearer {self.api_key}", "accept": "image/*"}
141
+
142
+ try:
143
+ ASCIIColors.info(f"Requesting image edit from Stability AI ({self.model_name})...")
144
+ response = requests.post(url, headers=headers, files=files, data=data)
145
+ response.raise_for_status()
146
+ return response.content
147
+ except Exception as e:
148
+ trace_exception(e)
149
+ try:
150
+ error_msg = response.json()
151
+ raise Exception(f"Stability AI API error: {error_msg}")
152
+ except:
153
+ raise Exception(f"Stability AI API request failed: {e}")
154
+
155
+ if __name__ == '__main__':
156
+ ASCIIColors.magenta("--- Stability AI TTI Binding Test ---")
157
+ if "STABILITY_API_KEY" not in os.environ:
158
+ ASCIIColors.error("STABILITY_API_KEY environment variable not set. Cannot run test.")
159
+ exit(1)
160
+
161
+ try:
162
+ binding = StabilityAITTIBinding(model_name="stable-diffusion-3-medium")
163
+
164
+ ASCIIColors.cyan("\n--- Test: Text-to-Image ---")
165
+ prompt = "a cinematic photo of a robot drinking coffee in a Parisian cafe"
166
+ img_bytes = binding.generate_image(prompt, width=1024, height=1024)
167
+
168
+ assert len(img_bytes) > 1000, "Generated image bytes are too small."
169
+ output_path = Path(__file__).parent / "tmp_stability_t2i.png"
170
+ with open(output_path, "wb") as f:
171
+ f.write(img_bytes)
172
+ ASCIIColors.green(f"Text-to-Image generation OK. Image saved to {output_path}")
173
+
174
+ except Exception as e:
175
+ trace_exception(e)
176
+ ASCIIColors.error(f"Stability AI binding test failed: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lollms_client
3
- Version: 1.4.0
3
+ Version: 1.4.5
4
4
  Summary: A client library for LoLLMs generate endpoint
5
5
  Author-email: ParisNeo <parisneoai@gmail.com>
6
6
  License: Apache Software License
@@ -1,8 +1,8 @@
1
- lollms_client/__init__.py,sha256=qPZONrhBQLJOLMIGp9Z9tMt9xTQ-CulJRwCPSZwXaDY,1146
1
+ lollms_client/__init__.py,sha256=1ATuXFW5bb2NSxUu0nl6c3tXgX30-GS0pYWv6hkA8Vg,1146
2
2
  lollms_client/lollms_agentic.py,sha256=pQiMEuB_XkG29-SW6u4KTaMFPr6eKqacInggcCuCW3k,13914
3
3
  lollms_client/lollms_config.py,sha256=goEseDwDxYJf3WkYJ4IrLXwg3Tfw73CXV2Avg45M_hE,21876
4
- lollms_client/lollms_core.py,sha256=TSkwJN0mozPtCOiQQisqMUbZVVkqKKNdpjanOrKDjUM,289087
5
- lollms_client/lollms_discussion.py,sha256=7O58DCvtd3zJ_W9wbuDOb5zcU6yt27xqSFkiQEH0wpk,127903
4
+ lollms_client/lollms_core.py,sha256=aCEoxmEF6ZmkBgJgZd74lKkM4A3PVVyt2IwMvLfScWw,315053
5
+ lollms_client/lollms_discussion.py,sha256=jWw1lSq0Oz_X5pnkECf1XwdDP2Lf84im00VpwuvsXXk,123041
6
6
  lollms_client/lollms_js_analyzer.py,sha256=01zUvuO2F_lnUe_0NLxe1MF5aHE1hO8RZi48mNPv-aw,8361
7
7
  lollms_client/lollms_llm_binding.py,sha256=Dj1PI2bQBYv_JgPxCIaIC7DMUvWdFJGwXFdsP5hdGBg,25014
8
8
  lollms_client/lollms_mcp_binding.py,sha256=psb27A23VFWDfZsR2WUbQXQxiZDW5yfOak6ZtbMfszI,10222
@@ -29,10 +29,12 @@ lollms_client/llm_bindings/llamacpp/__init__.py,sha256=llPF85AzYgMp7Cpo_4OvEHKlx
29
29
  lollms_client/llm_bindings/lollms/__init__.py,sha256=XFQKtTJnkW8OwF1IoyzHqAZ8JAJ0PnAUKDdeOLGcbrE,24310
30
30
  lollms_client/llm_bindings/lollms_webui/__init__.py,sha256=iuDfhZZoLC-PDEPLHrcjk5-962S5c7OeCI7PMdJxI_A,17753
31
31
  lollms_client/llm_bindings/mistral/__init__.py,sha256=cddz9xIj8NRFLKHe2JMxzstpUrNIu5s9juci3mhiHfo,14133
32
+ lollms_client/llm_bindings/novita_ai/__init__.py,sha256=NOg6_NBCxuz9gwrijTCzrp9a78AbmBdT4k67baCTtuc,13877
32
33
  lollms_client/llm_bindings/ollama/__init__.py,sha256=a6cgzXPuo8ZLhIZHJFy8QF0n5ZTk0X4OC1JSyXG1enk,46013
33
34
  lollms_client/llm_bindings/open_router/__init__.py,sha256=cAFWtCWJx0WjIe1w2JReCf6WlAZjrXYA4jZ8l3zqxMs,14915
34
35
  lollms_client/llm_bindings/openai/__init__.py,sha256=ElLbtHLwR61Uj3W6G4g6QIhxtCqUGOCQBYwhQyN60us,26142
35
36
  lollms_client/llm_bindings/openllm/__init__.py,sha256=RC9dVeopslS-zXTsSJ7VC4iVsKgZCBwfmccmr_LCHA0,29971
37
+ lollms_client/llm_bindings/perplexity/__init__.py,sha256=lMRPdbVbGX_weByAdcsZakdxDg7nFF3uCbdzakQmBOc,15006
36
38
  lollms_client/llm_bindings/pythonllamacpp/__init__.py,sha256=ZTuVa5ngu9GPVImjs_g8ArV7Bx7a1Rze518Tz8AFJ3U,31807
37
39
  lollms_client/llm_bindings/tensor_rt/__init__.py,sha256=xiT-JAyNI_jo6CE0nle9Xoc7U8-UHAfEHrnCwmDTiOE,32023
38
40
  lollms_client/llm_bindings/transformers/__init__.py,sha256=hEonNvmrVSc9YWg_1uVwxe31rC-fsjVGh6QvyBc0TEE,37598
@@ -49,10 +51,13 @@ lollms_client/stt_bindings/lollms/__init__.py,sha256=9Vmn1sQQZKLGLe7nZnc-0LnNeSY
49
51
  lollms_client/stt_bindings/whisper/__init__.py,sha256=1Ej67GdRKBy1bba14jMaYDYHiZkxJASkWm5eF07ztDQ,15363
50
52
  lollms_client/stt_bindings/whispercpp/__init__.py,sha256=xSAQRjAhljak3vWCpkP0Vmdb6WmwTzPjXyaIB85KLGU,21439
51
53
  lollms_client/tti_bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- lollms_client/tti_bindings/diffusers/__init__.py,sha256=KKcIBIQvavAyIwuqappRqLghUOcm-XOP_Y4SL_pEcWY,40669
54
+ lollms_client/tti_bindings/diffusers/__init__.py,sha256=Pi5Zw4nHGXVc0Vcb0ib7KkoiOx__0JukWtL01BUzd7c,41692
53
55
  lollms_client/tti_bindings/gemini/__init__.py,sha256=f9fPuqnrBZ1Z-obcoP6EVvbEXNbNCSg21cd5efLCk8U,16707
56
+ lollms_client/tti_bindings/leonardo_ai/__init__.py,sha256=EvjKyV8kM7-tmLwC1agSQ-v7thrNgflrmFxhDLqzT8U,5884
54
57
  lollms_client/tti_bindings/lollms/__init__.py,sha256=5Tnsn4b17djvieQkcjtIDBm3qf0pg5ZWWov-4_2wmo0,8762
58
+ lollms_client/tti_bindings/novita_ai/__init__.py,sha256=1PZbM_R7cZwImbYxeuLqTlrc6Sfg43_YCbjw2ZJLnhc,4802
55
59
  lollms_client/tti_bindings/openai/__init__.py,sha256=YWJolJSQfIzTJvrLQVe8rQewP7rddf6z87g4rnp-lTs,4932
60
+ lollms_client/tti_bindings/stability_ai/__init__.py,sha256=GJxE0joQ0UZbheozysbN96AvQq60pjY2UjnSLFmRh4g,8025
56
61
  lollms_client/ttm_bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
62
  lollms_client/ttm_bindings/audiocraft/__init__.py,sha256=a0k6wTrHth6GaVOiNnVboeFY3oKVvCQPbQlqO38XEyc,14328
58
63
  lollms_client/ttm_bindings/bark/__init__.py,sha256=Pr3ou2a-7hNYDqbkxrAbghZpO5HvGUhz7e-7VGXIHHA,18976
@@ -71,8 +76,8 @@ lollms_client/tts_bindings/xtts/server/main.py,sha256=T-Kn5NM-u1FJMygeV8rOoZKlqn
71
76
  lollms_client/tts_bindings/xtts/server/setup_voices.py,sha256=UdHaPa5aNcw8dR-aRGkZr2OfSFFejH79lXgfwT0P3ss,1964
72
77
  lollms_client/ttv_bindings/__init__.py,sha256=UZ8o2izQOJLQgtZ1D1cXoNST7rzqW22rL2Vufc7ddRc,3141
73
78
  lollms_client/ttv_bindings/lollms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- lollms_client-1.4.0.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
75
- lollms_client-1.4.0.dist-info/METADATA,sha256=DWMUU9burfwT4loE8WrX5AUzw_TF4p282Ch7yIR-56I,58689
76
- lollms_client-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
- lollms_client-1.4.0.dist-info/top_level.txt,sha256=Bk_kz-ri6Arwsk7YG-T5VsRorV66uVhcHGvb_g2WqgE,14
78
- lollms_client-1.4.0.dist-info/RECORD,,
79
+ lollms_client-1.4.5.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
80
+ lollms_client-1.4.5.dist-info/METADATA,sha256=IJc5k53zOajOIIvuq-dhLQQ67bHpLwzNyTqxlQZNCz8,58689
81
+ lollms_client-1.4.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ lollms_client-1.4.5.dist-info/top_level.txt,sha256=Bk_kz-ri6Arwsk7YG-T5VsRorV66uVhcHGvb_g2WqgE,14
83
+ lollms_client-1.4.5.dist-info/RECORD,,