lemonade-sdk 8.1.10__py3-none-any.whl → 8.1.12__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 lemonade-sdk might be problematic. Click here for more details.

Files changed (37) hide show
  1. lemonade/cache.py +6 -1
  2. lemonade/common/status.py +4 -4
  3. lemonade/tools/bench.py +22 -1
  4. lemonade/tools/flm/__init__.py +1 -0
  5. lemonade/tools/flm/utils.py +255 -0
  6. lemonade/tools/llamacpp/bench.py +111 -23
  7. lemonade/tools/llamacpp/load.py +20 -1
  8. lemonade/tools/llamacpp/utils.py +210 -17
  9. lemonade/tools/oga/bench.py +0 -26
  10. lemonade/tools/report/table.py +6 -0
  11. lemonade/tools/server/flm.py +133 -0
  12. lemonade/tools/server/llamacpp.py +23 -5
  13. lemonade/tools/server/serve.py +260 -135
  14. lemonade/tools/server/static/js/chat.js +165 -82
  15. lemonade/tools/server/static/js/models.js +87 -54
  16. lemonade/tools/server/static/js/shared.js +9 -6
  17. lemonade/tools/server/static/logs.html +57 -0
  18. lemonade/tools/server/static/styles.css +159 -8
  19. lemonade/tools/server/static/webapp.html +28 -10
  20. lemonade/tools/server/tray.py +94 -38
  21. lemonade/tools/server/utils/macos_tray.py +226 -0
  22. lemonade/tools/server/utils/{system_tray.py → windows_tray.py} +13 -0
  23. lemonade/tools/server/webapp.py +4 -1
  24. lemonade/tools/server/wrapped_server.py +91 -25
  25. lemonade/version.py +1 -1
  26. lemonade_install/install.py +25 -2
  27. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/METADATA +10 -6
  28. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/RECORD +37 -32
  29. lemonade_server/cli.py +103 -14
  30. lemonade_server/model_manager.py +186 -45
  31. lemonade_server/pydantic_models.py +25 -1
  32. lemonade_server/server_models.json +175 -62
  33. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/WHEEL +0 -0
  34. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/entry_points.txt +0 -0
  35. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/licenses/LICENSE +0 -0
  36. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/licenses/NOTICE.md +0 -0
  37. {lemonade_sdk-8.1.10.dist-info → lemonade_sdk-8.1.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,226 @@
1
+ import platform
2
+ import subprocess
3
+ from typing import Callable, Optional
4
+
5
+ # Check if we're on macOS and import accordingly
6
+ if platform.system() == "Darwin":
7
+ try:
8
+ import rumps
9
+
10
+ RUMPS_AVAILABLE = True
11
+ except ImportError:
12
+ RUMPS_AVAILABLE = False
13
+ print("Warning: rumps not available. Install with: pip install rumps")
14
+ else:
15
+ RUMPS_AVAILABLE = False
16
+
17
+
18
+ class MenuItem:
19
+ """
20
+ Cross-platform menu item representation.
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ text: str,
26
+ callback: Optional[Callable] = None,
27
+ enabled: bool = True,
28
+ submenu=None,
29
+ checked: bool = False,
30
+ ):
31
+ self.text = text
32
+ self.callback = callback
33
+ self.enabled = enabled
34
+ self.submenu = submenu
35
+ self.checked = checked
36
+
37
+
38
+ class Menu:
39
+ """
40
+ Cross-platform menu representation.
41
+ """
42
+
43
+ SEPARATOR = "SEPARATOR"
44
+
45
+ def __init__(self, *items):
46
+ self.items = list(items)
47
+
48
+
49
+ class MacOSSystemTray:
50
+ """
51
+ macOS-specific system tray implementation using rumps.
52
+ """
53
+
54
+ def __init__(self, app_name: str, icon_path: str):
55
+ self._check_rumps_availability()
56
+
57
+ self.app_name = app_name
58
+ self.icon_path = icon_path
59
+ self.app = None
60
+ self.menu_callbacks = {}
61
+ self._menu_update_timer = None
62
+
63
+ def _check_rumps_availability(self):
64
+ """Check if rumps is available and raise error if not."""
65
+ if not RUMPS_AVAILABLE:
66
+ raise ImportError("rumps library is required for macOS tray support")
67
+
68
+ def create_menu(self):
69
+ """
70
+ Create the context menu based on current state. Override in subclass.
71
+ """
72
+ return Menu(MenuItem("Exit", self.exit_app))
73
+
74
+ def build_rumps_menu(self, menu_items):
75
+ """
76
+ Convert our menu structure to rumps menu items.
77
+ """
78
+ rumps_items = []
79
+
80
+ for item in menu_items:
81
+ if item == Menu.SEPARATOR:
82
+ rumps_items.append(rumps.separator)
83
+ elif isinstance(item, MenuItem):
84
+ if item.submenu:
85
+ # Create submenu
86
+ submenu_items = self.build_rumps_menu(item.submenu.items)
87
+ submenu = rumps.MenuItem(item.text)
88
+ for sub_item in submenu_items:
89
+ submenu.add(sub_item)
90
+ rumps_items.append(submenu)
91
+ else:
92
+ # Create regular menu item
93
+ menu_item = rumps.MenuItem(
94
+ item.text,
95
+ callback=(
96
+ self._create_callback_wrapper(item)
97
+ if item.callback
98
+ else None
99
+ ),
100
+ )
101
+
102
+ # Set enabled state
103
+ if not item.enabled:
104
+ menu_item.set_callback(None)
105
+
106
+ # Set checked state
107
+ if item.checked:
108
+ menu_item.state = 1
109
+ else:
110
+ menu_item.state = 0
111
+
112
+ rumps_items.append(menu_item)
113
+
114
+ return rumps_items
115
+
116
+ def _create_callback_wrapper(self, item):
117
+ """Create a callback wrapper that matches our interface."""
118
+
119
+ def wrapper(sender): # pylint: disable=unused-argument
120
+ if item.callback:
121
+ item.callback(None, item)
122
+
123
+ return wrapper
124
+
125
+ def show_balloon_notification(
126
+ self, title, message, timeout=5000
127
+ ): # pylint: disable=unused-argument
128
+ """
129
+ Show a notification on macOS using the Notification Center.
130
+ Falls back to console output if AppleScript fails.
131
+ """
132
+ try:
133
+ # Escape quotes in message and title for AppleScript
134
+ escaped_title = title.replace('"', '\\"')
135
+ escaped_message = message.replace('"', '\\"')
136
+ escaped_app_name = self.app_name.replace('"', '\\"')
137
+
138
+ # Use AppleScript to show notification
139
+ script = (
140
+ f'display notification "{escaped_message}" '
141
+ f'with title "{escaped_title}" subtitle "{escaped_app_name}"'
142
+ )
143
+ subprocess.run(
144
+ ["osascript", "-e", script], check=True, capture_output=True, text=True
145
+ )
146
+ except FileNotFoundError:
147
+ # osascript not available, fallback to console
148
+ print(f"[{self.app_name}] {title}: {message}")
149
+ except subprocess.CalledProcessError as e:
150
+ # AppleScript failed, fallback to console
151
+ print(f"[{self.app_name}] {title}: {message}")
152
+ print(f"Warning: Failed to show notification via AppleScript: {e}")
153
+ except Exception as e: # pylint: disable=broad-exception-caught
154
+ # Any other error, fallback to console
155
+ print(f"[{self.app_name}] {title}: {message}")
156
+ print(f"Warning: Failed to show notification: {e}")
157
+
158
+ def exit_app(self, _, __):
159
+ """Exit the application."""
160
+ if self.app:
161
+ rumps.quit_application()
162
+
163
+ def run(self):
164
+ """
165
+ Run the tray application.
166
+ """
167
+ self._check_rumps_availability()
168
+
169
+ try:
170
+ # Create the rumps app
171
+ self.app = rumps.App(self.app_name, icon=self.icon_path, quit_button=None)
172
+
173
+ # Build the initial menu
174
+ self.refresh_menu()
175
+
176
+ # Set up a timer to refresh menu periodically (every 3 seconds)
177
+ # This provides a good balance between responsiveness and performance
178
+ self._setup_menu_refresh_timer()
179
+
180
+ # Call the on_ready hook if available (for compatibility with tray.py)
181
+ if hasattr(self, "on_ready") and callable(getattr(self, "on_ready", None)):
182
+ getattr(self, "on_ready")()
183
+
184
+ # Start the app
185
+ self.app.run()
186
+ except Exception as e:
187
+ raise RuntimeError(f"Failed to start macOS tray application: {e}") from e
188
+
189
+ def refresh_menu(self):
190
+ """
191
+ Refresh the menu by rebuilding it with current state.
192
+ """
193
+ if not self.app:
194
+ return
195
+
196
+ # Clear existing menu
197
+ self.app.menu.clear()
198
+
199
+ # Build fresh menu with current state
200
+ menu = self.create_menu()
201
+ menu_items = self.build_rumps_menu(menu.items)
202
+
203
+ # Add updated menu items
204
+ for item in menu_items:
205
+ self.app.menu.add(item)
206
+
207
+ def _setup_menu_refresh_timer(self):
208
+ """
209
+ Set up a timer to periodically refresh the menu.
210
+ """
211
+ if not self.app:
212
+ return
213
+
214
+ # Create a timer that refreshes the menu every 3 seconds
215
+ @rumps.timer(3)
216
+ def refresh_menu_timer(sender): # pylint: disable=unused-argument
217
+ self.refresh_menu()
218
+
219
+ # Store reference to prevent garbage collection
220
+ self._menu_update_timer = refresh_menu_timer
221
+
222
+ def update_menu(self):
223
+ """
224
+ Update the menu by rebuilding it.
225
+ """
226
+ self.refresh_menu()
@@ -25,12 +25,14 @@ class MenuItem:
25
25
  enabled: bool = True,
26
26
  submenu=None,
27
27
  bitmap_path: Optional[str] = None,
28
+ checked: bool = False,
28
29
  ):
29
30
  self.text = text
30
31
  self.callback = callback
31
32
  self.enabled = enabled
32
33
  self.submenu = submenu
33
34
  self.bitmap_path = bitmap_path
35
+ self.checked = checked
34
36
  self.id = None # Will be set when menu is created
35
37
  self.bitmap_handle = None
36
38
 
@@ -358,9 +360,20 @@ class SystemTray:
358
360
  self.register_window_class()
359
361
  self.create_window()
360
362
 
363
+ # Set up Windows console control handler for CTRL+C
364
+ self.console_handler = self.setup_console_control_handler(self.logger)
365
+
361
366
  # Add tray icon
362
367
  self.add_tray_icon()
363
368
 
369
+ # Notify subclasses that the tray is ready (hwnd and icon created)
370
+ # Allows showing initial notifications after initialization
371
+ try:
372
+ if hasattr(self, "on_ready") and callable(getattr(self, "on_ready")):
373
+ self.on_ready()
374
+ except Exception:
375
+ pass
376
+
364
377
  # Run the message loop in the main thread
365
378
  self.message_loop()
366
379
 
@@ -1,5 +1,6 @@
1
1
  from pathlib import Path
2
2
  import json
3
+ import platform
3
4
  from fastapi.responses import HTMLResponse
4
5
  from lemonade_server.model_manager import ModelManager
5
6
 
@@ -14,10 +15,11 @@ def get_webapp_html(port=8000):
14
15
  # Use shared filter function from model_manager.py
15
16
  filtered_models = ModelManager().filter_models_by_backend(server_models)
16
17
 
17
- # Pass filtered server_models to JS
18
+ # Pass filtered server_models and platform info to JS
18
19
  server_models_js = (
19
20
  f"<script>window.SERVER_MODELS = {json.dumps(filtered_models)};</script>"
20
21
  )
22
+ platform_js = f"<script>window.PLATFORM = '{platform.system()}';</script>"
21
23
 
22
24
  # Load HTML template
23
25
  template_path = Path(__file__).parent / "static" / "webapp.html"
@@ -27,5 +29,6 @@ def get_webapp_html(port=8000):
27
29
  # Replace template variables
28
30
  html_content = html_template.replace("{{SERVER_PORT}}", str(port))
29
31
  html_content = html_content.replace("{{SERVER_MODELS_JS}}", server_models_js)
32
+ html_content = html_content.replace("{{PLATFORM_JS}}", platform_js)
30
33
 
31
34
  return HTMLResponse(content=html_content)
@@ -58,8 +58,22 @@ class WrappedServerTelemetry(ABC):
58
58
  telemetry = [
59
59
  ["Input tokens", self.input_tokens],
60
60
  ["Output tokens", self.output_tokens],
61
- ["TTFT (s)", f"{self.time_to_first_token:.2f}"],
62
- ["TPS", f"{self.tokens_per_second:.2f}"],
61
+ [
62
+ "TTFT (s)",
63
+ (
64
+ f"{self.time_to_first_token:.2f}"
65
+ if self.time_to_first_token is not None
66
+ else "N/A"
67
+ ),
68
+ ],
69
+ [
70
+ "TPS",
71
+ (
72
+ f"{self.tokens_per_second:.2f}"
73
+ if self.tokens_per_second is not None
74
+ else "N/A"
75
+ ),
76
+ ],
63
77
  ]
64
78
 
65
79
  table = tabulate(
@@ -83,7 +97,7 @@ class WrappedServer(ABC):
83
97
  self.telemetry: WrappedServerTelemetry = telemetry
84
98
  self.log_thread_exception = None
85
99
 
86
- def choose_port(self):
100
+ def _choose_port(self):
87
101
  """
88
102
  Users probably don't care what port we start the wrapped server on, so let's
89
103
  search for an empty port
@@ -318,18 +332,44 @@ class WrappedServer(ABC):
318
332
  if chat_completion_request.stream:
319
333
 
320
334
  def event_stream():
321
- try:
322
- # Enable streaming
323
- # pylint: disable=missing-kwoa
324
- for chunk in client.chat.completions.create(**openai_client_params):
325
- yield f"data: {chunk.model_dump_json()}\n\n"
326
- yield "data: [DONE]\n\n"
327
-
328
- # Show telemetry after completion
329
- self.telemetry.show_telemetry()
335
+ # Ensure streaming is enabled in params
336
+ stream_params = dict(openai_client_params)
337
+ stream_params["stream"] = True
330
338
 
331
- except Exception as e: # pylint: disable=broad-exception-caught
332
- yield f'data: {{"error": "{str(e)}"}}\n\n'
339
+ # Use streaming context so we can explicitly close on cancellation
340
+ with client.chat.completions.with_streaming_response.create(
341
+ # pylint: disable=missing-kwoa
342
+ **stream_params,
343
+ ) as response:
344
+ try:
345
+ for line in response.iter_lines():
346
+ # Preserve SSE event boundaries: blank line separates events
347
+ if line == b"" or line == "":
348
+ yield "\n"
349
+ continue
350
+ if isinstance(line, bytes):
351
+ try:
352
+ line = line.decode("utf-8", errors="ignore")
353
+ except (UnicodeDecodeError, LookupError):
354
+ # Skip lines that fail decoding due to encoding issues
355
+ continue
356
+ # Forward SSE lines as-is
357
+ if not line.endswith("\n"):
358
+ line += "\n"
359
+ yield line
360
+
361
+ # Show telemetry after completion
362
+ self.telemetry.show_telemetry()
363
+
364
+ except GeneratorExit:
365
+ # Client disconnected/cancelled; close upstream stream and stop
366
+ try:
367
+ response.close()
368
+ except Exception: # pylint: disable=broad-exception-caught
369
+ pass
370
+ raise
371
+ except Exception as e: # pylint: disable=broad-exception-caught
372
+ yield f'data: {{"error": "{str(e)}"}}\n\n'
333
373
 
334
374
  return StreamingResponse(
335
375
  event_stream(),
@@ -387,18 +427,44 @@ class WrappedServer(ABC):
387
427
  if completion_request.stream:
388
428
 
389
429
  def event_stream():
390
- try:
391
- # Enable streaming
392
- # pylint: disable=missing-kwoa
393
- for chunk in client.completions.create(**openai_client_params):
394
- yield f"data: {chunk.model_dump_json()}\n\n"
395
- yield "data: [DONE]\n\n"
396
-
397
- # Show telemetry after completion
398
- self.telemetry.show_telemetry()
430
+ # Ensure streaming is enabled in params
431
+ stream_params = dict(openai_client_params)
432
+ stream_params["stream"] = True
399
433
 
400
- except Exception as e: # pylint: disable=broad-exception-caught
401
- yield f'data: {{"error": "{str(e)}"}}\n\n'
434
+ # Use streaming context so we can explicitly close on cancellation
435
+ with client.completions.with_streaming_response.create(
436
+ # pylint: disable=missing-kwoa
437
+ **stream_params,
438
+ ) as response:
439
+ try:
440
+ for line in response.iter_lines():
441
+ # Preserve SSE event boundaries: blank line separates events
442
+ if line == b"" or line == "":
443
+ yield "\n"
444
+ continue
445
+ if isinstance(line, bytes):
446
+ try:
447
+ line = line.decode("utf-8", errors="ignore")
448
+ except (UnicodeDecodeError, LookupError):
449
+ # Skip lines that fail decoding due to encoding issues
450
+ continue
451
+ # Forward SSE lines as-is
452
+ if not line.endswith("\n"):
453
+ line += "\n"
454
+ yield line
455
+
456
+ # Show telemetry after completion
457
+ self.telemetry.show_telemetry()
458
+
459
+ except GeneratorExit:
460
+ # Client disconnected/cancelled; close upstream stream and stop
461
+ try:
462
+ response.close()
463
+ except Exception: # pylint: disable=broad-exception-caught
464
+ pass
465
+ raise
466
+ except Exception as e: # pylint: disable=broad-exception-caught
467
+ yield f'data: {{"error": "{str(e)}"}}\n\n'
402
468
 
403
469
  return StreamingResponse(
404
470
  event_stream(),
lemonade/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "8.1.10"
1
+ __version__ = "8.1.12"
@@ -447,6 +447,12 @@ class Install:
447
447
  choices=["rocm", "vulkan"],
448
448
  )
449
449
 
450
+ parser.add_argument(
451
+ "--flm",
452
+ action="store_true",
453
+ help="Install FLM (FastFlowLM) for running local language models",
454
+ )
455
+
450
456
  parser.add_argument(
451
457
  "--override",
452
458
  action="store_true",
@@ -727,19 +733,33 @@ class Install:
727
733
 
728
734
  install_llamacpp(backend)
729
735
 
736
+ @staticmethod
737
+ def _install_flm():
738
+ """
739
+ Install FLM (FastFlowLM) for running local language models.
740
+ """
741
+
742
+ # Check if the processor is supported before proceeding
743
+ check_ryzen_ai_processor()
744
+
745
+ from lemonade.tools.flm.utils import install_flm
746
+
747
+ install_flm()
748
+
730
749
  def run(
731
750
  self,
732
751
  ryzenai: Optional[str] = None,
733
752
  build_model: Optional[str] = None,
734
753
  llamacpp: Optional[str] = None,
754
+ flm: Optional[bool] = None,
735
755
  yes: bool = False,
736
756
  token: Optional[str] = None,
737
757
  override: bool = False,
738
758
  ):
739
- if ryzenai is None and llamacpp is None:
759
+ if ryzenai is None and llamacpp is None and flm is None:
740
760
  raise ValueError(
741
761
  "You must select something to install, "
742
- "for example `--ryzenai` or `--llamacpp`"
762
+ "for example `--llamacpp`, `--flm`, or `--ryzenai`"
743
763
  )
744
764
 
745
765
  if ryzenai is not None:
@@ -748,6 +768,9 @@ class Install:
748
768
  if llamacpp is not None:
749
769
  self._install_llamacpp(llamacpp)
750
770
 
771
+ if flm:
772
+ self._install_flm()
773
+
751
774
 
752
775
  def main():
753
776
  installer = Install()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lemonade-sdk
3
- Version: 8.1.10
3
+ Version: 8.1.12
4
4
  Summary: Lemonade SDK: Your LLM Aide for Validation and Deployment
5
5
  Author-email: lemonade@amd.com
6
6
  Requires-Python: >=3.10, <3.14
@@ -29,6 +29,7 @@ Requires-Dist: tabulate
29
29
  Requires-Dist: sentencepiece
30
30
  Requires-Dist: huggingface-hub[hf_xet]==0.33.0
31
31
  Requires-Dist: python-dotenv
32
+ Requires-Dist: rumps>=0.4.0; sys_platform == "darwin"
32
33
  Provides-Extra: oga-ryzenai
33
34
  Requires-Dist: onnxruntime-genai-directml-ryzenai==0.7.0.2.1; extra == "oga-ryzenai"
34
35
  Requires-Dist: protobuf>=6.30.1; extra == "oga-ryzenai"
@@ -65,6 +66,8 @@ Dynamic: summary
65
66
  <img src="https://img.shields.io/badge/Windows-11-0078D6?logo=windows&logoColor=white" alt="Windows 11" /></a>
66
67
  <a href="https://lemonade-server.ai/#linux" title="Ubuntu 24.04 & 25.04 Supported">
67
68
  <img src="https://img.shields.io/badge/Ubuntu-24.04%20%7C%2025.04-E95420?logo=ubuntu&logoColor=white" alt="Ubuntu 24.04 | 25.04" /></a>
69
+ <a href="https://lemonade-server.ai/" title="macOS 14+ with Apple Silicon">
70
+ <img src="https://img.shields.io/badge/macOS-14%2B-000000?logo=apple&logoColor=white" alt="macOS 14+" /></a>
68
71
  <a href="docs/README.md#installation" title="Check out our instructions">
69
72
  <img src="https://img.shields.io/badge/Python-3.10--3.13-blue?logo=python&logoColor=white" alt="Made with Python" /></a>
70
73
  <a href="https://github.com/lemonade-sdk/lemonade/blob/main/docs/contribute.md" title="Contribution Guide">
@@ -152,11 +155,11 @@ You can also import custom GGUF and ONNX models from Hugging Face by using our [
152
155
 
153
156
  Lemonade supports the following configurations, while also making it easy to switch between them at runtime. Find more information about it [here](./docs/README.md#software-and-hardware-overview).
154
157
 
155
- | Hardware | Engine: OGA | Engine: llamacpp | Engine: HF | Windows | Linux |
156
- |----------|-------------|------------------|------------|---------|-------|
157
- | **🧠 CPU** | All platforms | All platforms | All platforms | ✅ | ✅ |
158
- | **🎮 GPU** | — | Vulkan: All platforms<br>ROCm: Selected AMD platforms* | — | ✅ | ✅ |
159
- | **🤖 NPU** | AMD Ryzen™ AI 300 series | — | | ✅ | — |
158
+ | Hardware | Engine: OGA | Engine: llamacpp | Engine: FLM | Windows | Linux | macOS |
159
+ |----------|-------------|------------------|------------|---------|-------|-------|
160
+ | **🧠 CPU** | All platforms | All platforms | - | | ✅ | ✅ |
161
+ | **🎮 GPU** | — | Vulkan: All platforms<br>ROCm: Selected AMD platforms*<br>Metal: Apple Silicon | — | ✅ | ✅ | ✅ |
162
+ | **🤖 NPU** | AMD Ryzen™ AI 300 series | — | Ryzen™ AI 300 series | ✅ | — | — |
160
163
 
161
164
  <details>
162
165
  <summary><small><i>* See supported AMD ROCm platforms</i></small></summary>
@@ -261,6 +264,7 @@ This project is:
261
264
  - [OnnxRuntime GenAI](https://github.com/microsoft/onnxruntime-genai)
262
265
  - [Hugging Face Hub](https://github.com/huggingface/huggingface_hub)
263
266
  - [OpenAI API](https://github.com/openai/openai-python)
267
+ - [IRON/MLIR-AIE](https://github.com/Xilinx/mlir-aie)
264
268
  - and more...
265
269
  - Accelerated by mentorship from the OCV Catalyst program.
266
270
  - Licensed under the [Apache 2.0 License](https://github.com/lemonade-sdk/lemonade/blob/main/LICENSE).
@@ -1,10 +1,10 @@
1
1
  lemonade/__init__.py,sha256=W1Qk7r0rnQqFhPNHp6BIBT_q-OH3s-8Q_POoVfAmKW0,117
2
2
  lemonade/api.py,sha256=Oc4yBA3LZg8FrTsbuDq1p9-XE74pqNnIEUhXyKa7qg8,5786
3
- lemonade/cache.py,sha256=5iZbk273TiTMqK_vdzPOPYTo6VsWW2gNByOISA9zi1w,3002
3
+ lemonade/cache.py,sha256=fUjtHYkRdHTULjNMrDNOFDGW_QMVUg54ZE1NukBP2oM,3314
4
4
  lemonade/cli.py,sha256=qU5bW7RQAUKNSpvrhVyzn68NMxyi-336Ke_JU4bsv1Q,5708
5
5
  lemonade/sequence.py,sha256=KSH7BPsiyDKsOsg_ziQKEGsDwMmuO_YbgPRBxkZd0pw,13267
6
6
  lemonade/state.py,sha256=sdSezla7Cd7KYL90xY3p9kcNV4ndSyN6UvNLOr3vBMA,5261
7
- lemonade/version.py,sha256=BSj3P5N0EwzL0-jahgtLzMLFGfZHooaYa76BeUiW2wc,23
7
+ lemonade/version.py,sha256=IzX_CD-LCNW8UO9z0HHoCrMMPsTBn-2q8Vqxoe3H6hQ,23
8
8
  lemonade/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  lemonade/common/build.py,sha256=zTb0m1-kuUx6zw5QHp2SNnVuN6jOTMQ2FCdj9iH374U,6140
10
10
  lemonade/common/cli_helpers.py,sha256=hjBfXrTtFl8gmCFlL-ksviXR0mOcdPtTWVNKoEp3PG4,4993
@@ -13,7 +13,7 @@ lemonade/common/filesystem.py,sha256=QV3cHhKNu-7W2rr8wZ4JQfD2rP_5T2Js7jiDQBYWHVQ
13
13
  lemonade/common/inference_engines.py,sha256=3bUGQe9wtfTiwt8kvI_ry077uyc9lid2G1fJX95kN1A,12969
14
14
  lemonade/common/network.py,sha256=qXpUjDYQEYM_gH3JwTtU-pu_yCKcaa1IeohJRPy91-A,2903
15
15
  lemonade/common/printing.py,sha256=GFFzrXIineIOMa9yu0lo5sL4j6A5BBg_T9aUCdP-juw,3229
16
- lemonade/common/status.py,sha256=xSOZN508cdRtrs1HVyr9zmASYg69EsZBLSs0lroLoCM,16519
16
+ lemonade/common/status.py,sha256=dxAahChPGVmfT91DJW949Xjgm9r5E-Y9KOLPEw7BMh8,16562
17
17
  lemonade/common/system_info.py,sha256=Msa0pCSj3ZN3nerjY8wdqjjJLg6GPhbWf2htSNcFIHc,49607
18
18
  lemonade/common/test_helpers.py,sha256=Gwk-pa_6xYAo2oro-2EJNfuouAfw8k_brCbcMC-E-r0,758
19
19
  lemonade/profilers/__init__.py,sha256=JKVonvJ4XZ9_6sKXPWsiMLQCNyzQOxhQw5BEHR1qOfU,31
@@ -24,54 +24,59 @@ lemonade/profilers/profiler.py,sha256=Y5FSbc386bMlTVbqCuya9pYrso5aTthxahR1V_ZKQ9
24
24
  lemonade/tools/__init__.py,sha256=_6xRc-FHxmujoLjLjWtpYrWYEXtCSneSy-5ya01kyPk,53
25
25
  lemonade/tools/accuracy.py,sha256=9HCmczDngkBUuUrt49d2CkRo4J0qyWoFYs5cj20bGkg,11714
26
26
  lemonade/tools/adapter.py,sha256=Ex63Y1SPCOSV4M_QtzEn3YVd39d3yew0lpmEFgp8aH4,3169
27
- lemonade/tools/bench.py,sha256=aN5LMA_EH6-ZhAH3Gf26JYL7s0eKpUd3j-bReRhzvEY,10016
27
+ lemonade/tools/bench.py,sha256=AZP1UGn2dZD61XshxO67tMUgOKTLEBqO3C872lKLzNQ,10903
28
28
  lemonade/tools/humaneval.py,sha256=JbxuoOzvR4iyxZv4R6MI7a3gUt5ef_Jj6Ie-9VP2wzY,9531
29
29
  lemonade/tools/management_tools.py,sha256=HQBcr7LYuMqVRYQtvnkNpfutBTA7lblszyoAjjVGu1Y,10201
30
30
  lemonade/tools/mmlu.py,sha256=c2QaIMDzjqxCvgHlMXmy_dP1sAFkwkDxL7RO2nogI6s,11071
31
31
  lemonade/tools/perplexity.py,sha256=eiaTZ3yhqF2pfwOffVbKKJLwjSri7Im2pC-tBJr7LLU,5638
32
32
  lemonade/tools/prompt.py,sha256=PyLksp1k8jsZsU7XBRK61k1DUHhbdLa20h-AP8Noh3w,9011
33
33
  lemonade/tools/tool.py,sha256=UsxVYukfm_iM3BfeGYPZxQlTK5UfDfDOl3RIyLr8A1Y,13256
34
+ lemonade/tools/flm/__init__.py,sha256=NQ4CEzJZGS_VvxPMlfrK4Dcx48bQSoUR4iG8e7yZjas,46
35
+ lemonade/tools/flm/utils.py,sha256=HOfw2ohjNE69S6WL3XVgVI0MfO4hQ50U32Cxb8vnjYI,8126
34
36
  lemonade/tools/huggingface/bench.py,sha256=-mTfldCtquL4mspq8ykVwDc9Mut5Ecv_jHJnSb0CYGE,6734
35
37
  lemonade/tools/huggingface/load.py,sha256=KsSGOBBD-tNEIfYC8mCWV_jpnkjHMhN3juVmC1Ln4uQ,7745
36
38
  lemonade/tools/huggingface/utils.py,sha256=j1S-IgjDsznUIVwkHSqqChmFyqIx9f3WcEelzohWwvU,13955
37
- lemonade/tools/llamacpp/bench.py,sha256=1fkE02ecg-jRk92i5dTAXz6re14WH8bd-Z9l-m3lbDA,4844
38
- lemonade/tools/llamacpp/load.py,sha256=DFCvQN548Ch9H8U_rHOiYviinzw6vixb5-V7xLj7XE4,6499
39
- lemonade/tools/llamacpp/utils.py,sha256=WEjdGmVxl30rt0a62MNo_X8ndFQ2SIrqtA2uF3klE6g,33090
39
+ lemonade/tools/llamacpp/bench.py,sha256=ubifZAdZatubfwuxgIY5IBzjW29lP-RwKaxhIZsXubQ,8533
40
+ lemonade/tools/llamacpp/load.py,sha256=yVKiKdtIKG9DOcLLc1MECQys7TiBzal-bPbWrlqQbn0,7238
41
+ lemonade/tools/llamacpp/utils.py,sha256=yQhAtE7z6F9adE1aGjGn0RVQBqiA-4RSJSGKdtFNXO4,40804
40
42
  lemonade/tools/oga/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- lemonade/tools/oga/bench.py,sha256=PJXv4UchcS2YPwijNzef8DY4DSAKYxIYY1ycHuH3T34,5005
43
+ lemonade/tools/oga/bench.py,sha256=g8l_ssvi_FC5Xf9tIe-c0XpcPR9TIVALh0eza5scMjI,4156
42
44
  lemonade/tools/oga/load.py,sha256=x-A-nhoni-WyDpVCLcWRAMfs5ouac9MJzxT-rsnLPw8,34226
43
45
  lemonade/tools/oga/utils.py,sha256=F8UVLKlfYcLa2SUqlehar8-jaX2Aw4u58DjHNNvLdOA,17675
44
46
  lemonade/tools/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
47
  lemonade/tools/report/llm_report.py,sha256=bVHhwCINA-Ok2EdSwAsLubsc83N3KWOVuwTguw7jDcE,6676
46
- lemonade/tools/report/table.py,sha256=Kv_Epd8a6KIrdzSC2EgIl6uTKw7E5eMq10Tg16O0WxM,27996
48
+ lemonade/tools/report/table.py,sha256=_AzknkTXI9xTPem-3N16FPRhkKnLvhhsfnm_P3GN2sw,28241
47
49
  lemonade/tools/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- lemonade/tools/server/llamacpp.py,sha256=8HdTkrU2ht8L1ldXqkfYfYhXiA8TvySuaslinAMqr-c,9002
49
- lemonade/tools/server/serve.py,sha256=W6wugCEaRNsDpWKIcsACrKZRFEwt7H1qWr6kG07WCek,62739
50
+ lemonade/tools/server/flm.py,sha256=NVpjFzcmX6YzW6wCWyMEvQEe_QpRK-Jlcaajxy3kWuo,4025
51
+ lemonade/tools/server/llamacpp.py,sha256=dSab9hR_CcctmU8HeQYQ7U0XCbAQNd_QGZUt6q7cxHA,9952
52
+ lemonade/tools/server/serve.py,sha256=rFv7N9ZW1gcRbw8ZXiXCiAOzPfJT5zbXt-b0Dljggmo,68780
50
53
  lemonade/tools/server/tool_calls.py,sha256=xrAlQwKG-nv2xLlf8f9CDSaUbyMn8ZtHkds9iZLG9K8,5230
51
- lemonade/tools/server/tray.py,sha256=2PQxoEWH-zzUGlveTW4heij4UC9SzxXcFlGs0JtFjF0,22226
52
- lemonade/tools/server/webapp.py,sha256=8Das5yXOaSBLZmSZ_eddJajQFxBhvl5D6GI_hHlGbE0,1040
53
- lemonade/tools/server/wrapped_server.py,sha256=DlzsGUwLQzjOFRfTTxfnhvmM_9lvAki96jWIAz7Czds,16713
54
+ lemonade/tools/server/tray.py,sha256=EFnSc2Ra4owiHVz6ykoMhxi2fYqZAK1g21AynAYBiyk,24426
55
+ lemonade/tools/server/webapp.py,sha256=GGSVIzN19C2ZaadOEPBg_D7Lt0PuF339NuWwjMPfZu8,1225
56
+ lemonade/tools/server/wrapped_server.py,sha256=uh7ifrRX1Hx0IuRwZRCGPyQOukitE7kKQipCCz0bSGA,19844
54
57
  lemonade/tools/server/static/favicon.ico,sha256=hMmP9qGJNeZ0mFS86JIqPbZstXMZn0Z76_HfHQpREAU,126745
55
- lemonade/tools/server/static/styles.css,sha256=SYEK4rC-MdpkTj31gxNl9Kb3hCNd1Fpq-EGnRMTjVe8,45362
56
- lemonade/tools/server/static/webapp.html,sha256=j7A8SOwbY_GfOSkOMV3JvXhOKY1iG70JYYuA3WdoWSQ,17856
57
- lemonade/tools/server/static/js/chat.js,sha256=XpQSIn1TUra26tu2CtDyOayhXAbUEqzBK0oGtkCAu-s,39162
58
+ lemonade/tools/server/static/logs.html,sha256=5TCpjL9XanRH5uiTEB0bJVuM-fhU8OaQrDrkZENkOMc,1543
59
+ lemonade/tools/server/static/styles.css,sha256=GYJgRtlZSgz3pShDeuatu-J9TpVwGgOjOcIWwNnWYck,49100
60
+ lemonade/tools/server/static/webapp.html,sha256=QQRMMMf8fbtJfGZYqBaRVd0-bENmdPfkVo8sdc4092Q,19151
61
+ lemonade/tools/server/static/js/chat.js,sha256=jxyMyu4MfvI2YmsMbJQ8ZwDNBnLzu2nbjm-qLfgWSNI,42182
58
62
  lemonade/tools/server/static/js/model-settings.js,sha256=JXHeG7xVrRU181Hj7CZflERAi1Z6t-qwYFR4aH5nf5I,5820
59
- lemonade/tools/server/static/js/models.js,sha256=7bCJbvS8FWpj6f1ZOwM8pt6UOQueuiOGLG79qrs-C-A,35872
60
- lemonade/tools/server/static/js/shared.js,sha256=mD03xqyMH1iQwH4pOq4IpDDaAX0z7YZY71gD8gufRAg,17487
63
+ lemonade/tools/server/static/js/models.js,sha256=es3LwrU49UtoC59e-AusUpdSXQnIRNsZvw8f05keAM0,37856
64
+ lemonade/tools/server/static/js/shared.js,sha256=4l-P2PHvgN6ALw1FK4xz4_wLRl97gZGS-G3veW6s9oU,17741
65
+ lemonade/tools/server/utils/macos_tray.py,sha256=xwHW44ZN5hDVlJcwIpHHfqn4VRXWxXHuDACaT-ZqdO8,7095
61
66
  lemonade/tools/server/utils/port.py,sha256=J7-g-Aqygb50jNoHLhhRfBZVM-uhGlcB5-oYBAehvgw,2263
62
- lemonade/tools/server/utils/system_tray.py,sha256=b9lvNv9chJKQxvmH7qzAuUe6H9HsLu7pdHFqGlAJaL0,12654
63
67
  lemonade/tools/server/utils/thread.py,sha256=Z-PDzGcpgfN2qxTmtlROWqrUN0B2fXdPrqo_J10fR_w,2772
68
+ lemonade/tools/server/utils/windows_tray.py,sha256=2z5aTmUPlkT-QfkcfwHsyA6dv6nSNBT0gXUErarhac8,13170
64
69
  lemonade_install/__init__.py,sha256=26zohKg2jgr_5y7tObduWMYQg8zCTWMZHL8lfi2zZVQ,40
65
- lemonade_install/install.py,sha256=Dow7kt-K9WI4PH15hBwkKtOxede3dAaOmH4I1y_P5H4,27008
66
- lemonade_sdk-8.1.10.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
67
- lemonade_sdk-8.1.10.dist-info/licenses/NOTICE.md,sha256=RSca9LE5e6pvdWA_LXAUCcACIHPmINKqkRX-AVRqBGo,3499
68
- lemonade_server/cli.py,sha256=0Ht82D1z4Z2MuxTc07jF2glaegX4jT3Jh--sS6ZO6Qc,19302
69
- lemonade_server/model_manager.py,sha256=V8QRf1nlh3wAFtUHoSF_JeAXeR7sfaZE1uTfppcIfcw,20492
70
- lemonade_server/pydantic_models.py,sha256=49MyOlb5feLUlKsGcI75tWaflWckrItqcSVkdCY4e3A,3269
71
- lemonade_server/server_models.json,sha256=0H_G6Jw6Yuz6t0RZnFnq0SbBCsw_cQLe9j24TkyF2eI,12344
70
+ lemonade_install/install.py,sha256=p3pYqhUnLQ9JJMcbjlSYDYqN-amnU_535O9Oj1yPbyM,27608
71
+ lemonade_sdk-8.1.12.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
+ lemonade_sdk-8.1.12.dist-info/licenses/NOTICE.md,sha256=RSca9LE5e6pvdWA_LXAUCcACIHPmINKqkRX-AVRqBGo,3499
73
+ lemonade_server/cli.py,sha256=mzlIqLeGkU96KHuib8lmZn0snU7XjQ9lspOy83dVplo,23401
74
+ lemonade_server/model_manager.py,sha256=6W6_nQea6hLD82Il2o_EgQ7oNaLfICXPKNjZiY9Y1Xk,26331
75
+ lemonade_server/pydantic_models.py,sha256=5U3PZ__UqcWQh-dNXVBc-vyJc6-In2vngZXP9VmiScM,3954
76
+ lemonade_server/server_models.json,sha256=NQ-EgcZ-axyul3aEtlV82rbrTc1Y0gySNQoRpZx0D-8,14996
72
77
  lemonade_server/settings.py,sha256=JOlZmirUXO9rA6BCODVFwyXrrHtYoH_LiKYm49lGm_c,1260
73
- lemonade_sdk-8.1.10.dist-info/METADATA,sha256=EYovzTHGnvWEZI-v_Gg1X0ajXeXiQPydqOkisnh08ME,15023
74
- lemonade_sdk-8.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- lemonade_sdk-8.1.10.dist-info/entry_points.txt,sha256=7sRvpNhi1E7amnM7RZo57e8yFF9iA5uuRaIeJ1Xre6w,193
76
- lemonade_sdk-8.1.10.dist-info/top_level.txt,sha256=10ap5GNiPhalO4V50LRoxA1FqRT9g3Xkia6BITu880k,42
77
- lemonade_sdk-8.1.10.dist-info/RECORD,,
78
+ lemonade_sdk-8.1.12.dist-info/METADATA,sha256=NzOwa4M6tbW-nHUx-IiDDsGlkAPyqX-pxYYso_GnTtg,15390
79
+ lemonade_sdk-8.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
+ lemonade_sdk-8.1.12.dist-info/entry_points.txt,sha256=7sRvpNhi1E7amnM7RZo57e8yFF9iA5uuRaIeJ1Xre6w,193
81
+ lemonade_sdk-8.1.12.dist-info/top_level.txt,sha256=10ap5GNiPhalO4V50LRoxA1FqRT9g3Xkia6BITu880k,42
82
+ lemonade_sdk-8.1.12.dist-info/RECORD,,