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

Files changed (55) hide show
  1. lemonade/api.py +3 -3
  2. lemonade/cli.py +11 -17
  3. lemonade/common/build.py +0 -47
  4. lemonade/common/network.py +50 -0
  5. lemonade/common/status.py +2 -21
  6. lemonade/common/system_info.py +19 -4
  7. lemonade/profilers/memory_tracker.py +3 -1
  8. lemonade/tools/accuracy.py +3 -4
  9. lemonade/tools/adapter.py +1 -2
  10. lemonade/tools/{huggingface_bench.py → huggingface/bench.py} +2 -87
  11. lemonade/tools/huggingface/load.py +235 -0
  12. lemonade/tools/{huggingface_load.py → huggingface/utils.py} +87 -255
  13. lemonade/tools/humaneval.py +9 -3
  14. lemonade/tools/{llamacpp_bench.py → llamacpp/bench.py} +1 -1
  15. lemonade/tools/{llamacpp.py → llamacpp/load.py} +18 -2
  16. lemonade/tools/mmlu.py +7 -15
  17. lemonade/tools/{ort_genai/oga.py → oga/load.py} +31 -422
  18. lemonade/tools/oga/utils.py +423 -0
  19. lemonade/tools/perplexity.py +4 -3
  20. lemonade/tools/prompt.py +2 -1
  21. lemonade/tools/quark/quark_load.py +2 -1
  22. lemonade/tools/quark/quark_quantize.py +5 -5
  23. lemonade/tools/report/table.py +3 -3
  24. lemonade/tools/server/llamacpp.py +159 -34
  25. lemonade/tools/server/serve.py +169 -147
  26. lemonade/tools/server/static/favicon.ico +0 -0
  27. lemonade/tools/server/static/styles.css +568 -0
  28. lemonade/tools/server/static/webapp.html +439 -0
  29. lemonade/tools/server/tray.py +458 -0
  30. lemonade/tools/server/{port_utils.py → utils/port.py} +22 -3
  31. lemonade/tools/server/utils/system_tray.py +395 -0
  32. lemonade/tools/server/{instructions.py → webapp.py} +4 -10
  33. lemonade/version.py +1 -1
  34. lemonade_install/install.py +46 -28
  35. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/METADATA +84 -22
  36. lemonade_sdk-8.0.0.dist-info/RECORD +70 -0
  37. lemonade_server/cli.py +182 -27
  38. lemonade_server/model_manager.py +192 -20
  39. lemonade_server/pydantic_models.py +9 -4
  40. lemonade_server/server_models.json +5 -3
  41. lemonade/common/analyze_model.py +0 -26
  42. lemonade/common/labels.py +0 -61
  43. lemonade/common/onnx_helpers.py +0 -176
  44. lemonade/common/plugins.py +0 -10
  45. lemonade/common/tensor_helpers.py +0 -83
  46. lemonade/tools/server/static/instructions.html +0 -262
  47. lemonade_sdk-7.0.3.dist-info/RECORD +0 -69
  48. /lemonade/tools/{ort_genai → oga}/__init__.py +0 -0
  49. /lemonade/tools/{ort_genai/oga_bench.py → oga/bench.py} +0 -0
  50. /lemonade/tools/server/{thread_utils.py → utils/thread.py} +0 -0
  51. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/WHEEL +0 -0
  52. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/entry_points.txt +0 -0
  53. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/licenses/LICENSE +0 -0
  54. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/licenses/NOTICE.md +0 -0
  55. {lemonade_sdk-7.0.3.dist-info → lemonade_sdk-8.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,395 @@
1
+ import os
2
+ import sys
3
+
4
+ # Add pywin32_system32 dlls (missing from embeddable Python executable)
5
+ pywin32_system32 = os.path.join(sys.prefix, "Lib", "site-packages", "pywin32_system32")
6
+ os.add_dll_directory(pywin32_system32)
7
+
8
+ from win32 import win32gui, win32api
9
+ import win32.lib.win32con as win32con
10
+ import ctypes
11
+ import psutil
12
+ from typing import Dict, Set, Callable, List, Optional, Tuple, Any
13
+
14
+ # Windows message constants
15
+ WM_USER = 0x0400
16
+ WM_TRAYICON = WM_USER + 1
17
+ WM_COMMAND = 0x0111
18
+
19
+
20
+ class MenuItem:
21
+ def __init__(
22
+ self,
23
+ text: str,
24
+ callback: Optional[Callable] = None,
25
+ enabled: bool = True,
26
+ submenu=None,
27
+ bitmap_path: Optional[str] = None,
28
+ ):
29
+ self.text = text
30
+ self.callback = callback
31
+ self.enabled = enabled
32
+ self.submenu = submenu
33
+ self.bitmap_path = bitmap_path
34
+ self.id = None # Will be set when menu is created
35
+ self.bitmap_handle = None
36
+
37
+
38
+ class Menu:
39
+ SEPARATOR = "SEPARATOR"
40
+
41
+ def __init__(self, *items):
42
+ self.items = list(items)
43
+
44
+
45
+ class SystemTray:
46
+ """
47
+ Generic system tray implementation for Windows.
48
+ """
49
+
50
+ def __init__(self, app_name: str, icon_path: str):
51
+ self.app_name = app_name
52
+ self.icon_path = icon_path
53
+ self.hwnd = None
54
+ self.hinst = win32api.GetModuleHandle(None)
55
+ self.class_atom = None
56
+ self.notify_id = None
57
+ self.menu_handle = None
58
+ self.menu_items = [] # Store menu items with their IDs
59
+ self.next_menu_id = 1000 # Starting ID for menu items
60
+
61
+ # Message map for window procedure
62
+ self.message_map = {
63
+ win32con.WM_DESTROY: self.on_destroy,
64
+ win32con.WM_COMMAND: self.on_command,
65
+ WM_TRAYICON: self.on_tray_icon,
66
+ }
67
+
68
+ def register_window_class(self):
69
+ """
70
+ Register the window class for the tray icon.
71
+ """
72
+ window_class = win32gui.WNDCLASS()
73
+ window_class.hInstance = self.hinst
74
+ window_class.lpszClassName = f"{self.app_name}TrayClass"
75
+ window_class.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW
76
+ window_class.hCursor = win32api.LoadCursor(0, win32con.IDC_ARROW)
77
+ window_class.hbrBackground = win32con.COLOR_WINDOW
78
+ window_class.lpfnWndProc = self.window_proc
79
+
80
+ self.class_atom = win32gui.RegisterClass(window_class)
81
+ return self.class_atom
82
+
83
+ def create_window(self):
84
+ """
85
+ Create a hidden window to receive messages.
86
+ """
87
+ style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
88
+ self.hwnd = win32gui.CreateWindow(
89
+ self.class_atom,
90
+ f"{self.app_name} Tray",
91
+ style,
92
+ 0,
93
+ 0,
94
+ win32con.CW_USEDEFAULT,
95
+ win32con.CW_USEDEFAULT,
96
+ 0,
97
+ 0,
98
+ self.hinst,
99
+ None,
100
+ )
101
+
102
+ # Set the AppUserModelID to identify our app to Windows
103
+ try:
104
+ SetCurrentProcessExplicitAppUserModelID = (
105
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID
106
+ )
107
+ SetCurrentProcessExplicitAppUserModelID(ctypes.c_wchar_p(self.app_name))
108
+ except Exception as e:
109
+ print(f"Failed to set AppUserModelID: {e}")
110
+
111
+ win32gui.UpdateWindow(self.hwnd)
112
+ return self.hwnd
113
+
114
+ def add_tray_icon(self):
115
+ """
116
+ Add the tray icon to the system tray.
117
+ """
118
+ # Load the .ico file
119
+ icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
120
+ hicon = win32gui.LoadImage(
121
+ self.hinst, str(self.icon_path), win32con.IMAGE_ICON, 0, 0, icon_flags
122
+ )
123
+
124
+ flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
125
+ nid = (self.hwnd, 0, flags, WM_TRAYICON, hicon, self.app_name)
126
+ win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
127
+ self.notify_id = nid
128
+
129
+ def show_balloon_notification(self, title, message, timeout=5000):
130
+ """
131
+ Show a balloon notification from the tray icon.
132
+ """
133
+ if self.notify_id:
134
+ # The notify_id is a tuple, we need to extract its elements
135
+ hwnd, id, flags, callback_msg, hicon, tip = self.notify_id
136
+
137
+ # Create a new notification with the balloon info
138
+ flags |= win32gui.NIF_INFO
139
+
140
+ # NIIF_USER (0x4) tells Windows to use our custom icon in the notification
141
+ info_flags = 0x4 # NIIF_USER
142
+
143
+ # Create the notification data structure with our custom icon flag
144
+ nid = (
145
+ hwnd,
146
+ id,
147
+ flags,
148
+ callback_msg,
149
+ hicon,
150
+ self.app_name,
151
+ message,
152
+ timeout,
153
+ title,
154
+ info_flags,
155
+ )
156
+
157
+ # Show the notification
158
+ win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, nid)
159
+
160
+ def window_proc(self, hwnd, message, wparam, lparam):
161
+ """
162
+ Window procedure to handle window messages.
163
+ """
164
+ if message in self.message_map:
165
+ return self.message_map[message](hwnd, message, wparam, lparam)
166
+ return win32gui.DefWindowProc(hwnd, message, wparam, lparam)
167
+
168
+ def on_destroy(self, hwnd, message, wparam, lparam):
169
+ """
170
+ Handle window destruction.
171
+ """
172
+ if self.notify_id:
173
+ win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, self.notify_id)
174
+
175
+ # Clean up bitmap resources
176
+ for item_id, item in self.menu_items:
177
+ if hasattr(item, "bitmap_handle") and item.bitmap_handle:
178
+ win32gui.DeleteObject(item.bitmap_handle)
179
+
180
+ win32gui.PostQuitMessage(0)
181
+ return 0
182
+
183
+ def on_command(self, hwnd, message, wparam, lparam):
184
+ """
185
+ Handle menu commands.
186
+ """
187
+ menu_id = win32gui.LOWORD(wparam)
188
+
189
+ # Find the menu item with this ID and execute its callback
190
+ for item_id, item_obj in self.menu_items:
191
+ if item_id == menu_id and item_obj.callback:
192
+ item_obj.callback(None, item_obj)
193
+ break
194
+
195
+ return 0
196
+
197
+ def on_tray_icon(self, hwnd, message, wparam, lparam):
198
+ """
199
+ Handle tray icon events.
200
+ """
201
+ if lparam == win32con.WM_RBUTTONUP or lparam == win32con.WM_LBUTTONUP:
202
+ # Show context menu on right-click and left-click
203
+ self.show_menu()
204
+ return 0
205
+
206
+ def create_menu_item(self, menu_handle, item, pos):
207
+ """
208
+ Create a menu item and add it to the menu.
209
+ """
210
+ if item == Menu.SEPARATOR:
211
+ win32gui.AppendMenu(menu_handle, win32con.MF_SEPARATOR, 0, "")
212
+ return pos + 1
213
+
214
+ # Assign a unique ID to this menu item
215
+ item.id = self.next_menu_id
216
+ self.next_menu_id += 1
217
+
218
+ # Store the menu item with its ID for later lookup
219
+ self.menu_items.append((item.id, item))
220
+
221
+ # Create the menu item
222
+ flags = win32con.MF_STRING
223
+
224
+ if not item.enabled:
225
+ flags |= win32con.MF_GRAYED
226
+
227
+ # Add checkmark if this is a selected item
228
+ if hasattr(item, "checked") and item.checked:
229
+ flags |= win32con.MF_CHECKED
230
+
231
+ # Handle submenu
232
+ if item.submenu:
233
+ submenu_handle = win32gui.CreatePopupMenu()
234
+ submenu_pos = 0
235
+ for submenu_item in item.submenu.items:
236
+ submenu_pos = self.create_menu_item(
237
+ submenu_handle, submenu_item, submenu_pos
238
+ )
239
+
240
+ # Add submenu to parent menu
241
+ win32gui.AppendMenu(
242
+ menu_handle, win32con.MF_POPUP | flags, submenu_handle, item.text
243
+ )
244
+ else:
245
+ # Add regular menu item first
246
+ win32gui.AppendMenu(menu_handle, flags, item.id, item.text)
247
+
248
+ # Then add bitmap if provided (as a separate step)
249
+ if item.bitmap_path:
250
+ try:
251
+ # Load the bitmap
252
+ icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
253
+ item.bitmap_handle = win32gui.LoadImage(
254
+ self.hinst,
255
+ str(item.bitmap_path),
256
+ win32con.IMAGE_BITMAP,
257
+ 0,
258
+ 0,
259
+ icon_flags,
260
+ )
261
+
262
+ if item.bitmap_handle:
263
+ # Set the bitmap for checked/unchecked states
264
+ # Using the same bitmap for both states
265
+ win32gui.SetMenuItemBitmaps(
266
+ menu_handle,
267
+ item.id,
268
+ win32con.MF_BYCOMMAND,
269
+ item.bitmap_handle,
270
+ item.bitmap_handle,
271
+ )
272
+ else:
273
+ print(f"Failed to load bitmap from {item.bitmap_path}")
274
+ except Exception as e:
275
+ print(f"Error adding bitmap to menu item: {e}")
276
+
277
+ return pos + 1
278
+
279
+ def build_menu(self, menu_items):
280
+ """
281
+ Build a menu from a list of menu items.
282
+ """
283
+ # Create a new menu
284
+ menu_handle = win32gui.CreatePopupMenu()
285
+ pos = 0
286
+
287
+ # Clear previous menu items
288
+ self.menu_items = []
289
+ self.next_menu_id = 1000
290
+
291
+ # Add each item to the menu
292
+ for item in menu_items:
293
+ pos = self.create_menu_item(menu_handle, item, pos)
294
+
295
+ return menu_handle
296
+
297
+ def show_menu(self):
298
+ """
299
+ Show the context menu.
300
+ """
301
+ # Create menu based on current state
302
+ menu = self.create_menu()
303
+ menu_handle = self.build_menu(menu.items)
304
+
305
+ # Get cursor position
306
+ pos = win32gui.GetCursorPos()
307
+
308
+ # Make our window the foreground window
309
+ try:
310
+ win32gui.SetForegroundWindow(self.hwnd)
311
+ except Exception:
312
+ # Ignore errors when setting foreground window
313
+ # Those are common when the tray icon is already open
314
+ pass
315
+
316
+ # Display the menu
317
+ win32gui.TrackPopupMenu(
318
+ menu_handle,
319
+ win32con.TPM_LEFTALIGN | win32con.TPM_RIGHTBUTTON,
320
+ pos[0],
321
+ pos[1],
322
+ 0,
323
+ self.hwnd,
324
+ None,
325
+ )
326
+
327
+ # Required by Windows
328
+ win32gui.PostMessage(self.hwnd, win32con.WM_NULL, 0, 0)
329
+
330
+ def create_menu(self):
331
+ """
332
+ Create the context menu based on current state. Override in subclass.
333
+ """
334
+ return Menu(MenuItem("Exit", self.exit_app))
335
+
336
+ def exit_app(self, _, __):
337
+ """Exit the application."""
338
+ win32gui.DestroyWindow(self.hwnd)
339
+
340
+ def update_menu(self):
341
+ """
342
+ Update the menu (will be shown on next right-click).
343
+ """
344
+ if self.hwnd:
345
+ win32gui.InvalidateRect(self.hwnd, None, True)
346
+
347
+ def message_loop(self):
348
+ """
349
+ Run the Windows message loop.
350
+ """
351
+ win32gui.PumpMessages()
352
+
353
+ def run(self):
354
+ """
355
+ Run the tray application.
356
+ """
357
+ # Register window class and create window
358
+ self.register_window_class()
359
+ self.create_window()
360
+
361
+ # Add tray icon
362
+ self.add_tray_icon()
363
+
364
+ # Run the message loop in the main thread
365
+ self.message_loop()
366
+
367
+ def setup_console_control_handler(self, logger=None):
368
+ """
369
+ Set up Windows console control handler for CTRL+C events.
370
+ This handles graceful shutdown when the console window is closed or CTRL+C is pressed.
371
+ """
372
+
373
+ def console_ctrl_handler(ctrl_type):
374
+ if ctrl_type in (0, 2): # CTRL_C_EVENT or CTRL_CLOSE_EVENT
375
+ if logger:
376
+ logger.info(
377
+ "Received console control event, shutting down gracefully"
378
+ )
379
+ # Post a quit message to the main thread instead of calling exit_app directly
380
+ # This avoids thread access issues
381
+ if self.hwnd:
382
+ win32gui.PostMessage(self.hwnd, win32con.WM_CLOSE, 0, 0)
383
+ return True
384
+ return False
385
+
386
+ # Define the handler function type
387
+ HANDLER_ROUTINE = ctypes.WINFUNCTYPE(
388
+ ctypes.wintypes.BOOL, ctypes.wintypes.DWORD
389
+ )
390
+ handler = HANDLER_ROUTINE(console_ctrl_handler)
391
+
392
+ # Set the console control handler
393
+ ctypes.windll.kernel32.SetConsoleCtrlHandler(handler, True)
394
+
395
+ return handler # Return handler to keep it in scope
@@ -4,18 +4,12 @@ from fastapi.responses import HTMLResponse
4
4
  from lemonade_server.model_manager import ModelManager
5
5
 
6
6
 
7
- def get_instructions_html(port=8000):
7
+ def get_webapp_html(port=8000):
8
8
  """
9
- Show instructions on how to use the server.
9
+ Show Lemonade Web App for LLM chat and model management.
10
10
  """
11
11
  # Load server models from JSON
12
- server_models_path = (
13
- Path(__file__).parent.parent.parent.parent
14
- / "lemonade_server"
15
- / "server_models.json"
16
- )
17
- with open(server_models_path, "r", encoding="utf-8") as f:
18
- server_models = json.load(f)
12
+ server_models = ModelManager().supported_models
19
13
 
20
14
  # Use shared filter function from model_manager.py
21
15
  filtered_models = ModelManager().filter_models_by_backend(server_models)
@@ -26,7 +20,7 @@ def get_instructions_html(port=8000):
26
20
  )
27
21
 
28
22
  # Load HTML template
29
- template_path = Path(__file__).parent / "static" / "instructions.html"
23
+ template_path = Path(__file__).parent / "static" / "webapp.html"
30
24
  with open(template_path, "r", encoding="utf-8") as f:
31
25
  html_template = f.read()
32
26
 
lemonade/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "7.0.3"
1
+ __version__ = "8.0.0"
@@ -52,7 +52,6 @@ import subprocess
52
52
  import sys
53
53
  from typing import Optional
54
54
  import zipfile
55
- import requests
56
55
 
57
56
  DEFAULT_RYZEN_AI_VERSION = "1.4.0"
58
57
  version_info_filename = "version_info.json"
@@ -192,6 +191,8 @@ def get_oga_hybrid_dir():
192
191
 
193
192
  def download_lfs_file(token, file, output_filename):
194
193
  """Downloads a file from LFS"""
194
+ import requests
195
+
195
196
  # Set up the headers for the request
196
197
  headers = {
197
198
  "Authorization": f"token {token}",
@@ -229,6 +230,8 @@ def download_lfs_file(token, file, output_filename):
229
230
 
230
231
 
231
232
  def download_file(url: str, output_filename: str, description: str = None):
233
+ import requests
234
+
232
235
  try:
233
236
  response = requests.get(url)
234
237
  if response.status_code != 200:
@@ -265,55 +268,67 @@ def check_ryzen_ai_processor():
265
268
  "Ryzen AI installation is only supported on Windows."
266
269
  )
267
270
 
271
+ skip_check = os.getenv("RYZENAI_SKIP_PROCESSOR_CHECK", "").lower() in {
272
+ "1",
273
+ "true",
274
+ "yes",
275
+ }
276
+ if skip_check:
277
+ print("[WARNING]: Processor check skipped.")
278
+ return
279
+
268
280
  is_supported = False
269
281
  cpu_name = ""
270
282
 
271
283
  try:
272
- # Use Windows registry to get CPU information
284
+ # Use PowerShell command to get processor name
285
+ powershell_cmd = [
286
+ "powershell",
287
+ "-ExecutionPolicy",
288
+ "Bypass",
289
+ "-Command",
290
+ "Get-WmiObject -Class Win32_Processor | Select-Object -ExpandProperty Name",
291
+ ]
292
+
273
293
  result = subprocess.run(
274
- [
275
- "reg",
276
- "query",
277
- "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
278
- "/v",
279
- "ProcessorNameString",
280
- ],
294
+ powershell_cmd,
281
295
  capture_output=True,
282
296
  text=True,
283
297
  check=True,
284
298
  )
285
299
 
286
- # Parse the output to extract the CPU name
287
- for line in result.stdout.splitlines():
288
- if "ProcessorNameString" in line:
289
- # The format is typically: name REG_SZ value
290
- parts = line.strip().split("REG_SZ")
291
- if len(parts) >= 2:
292
- cpu_name = parts[1].strip()
293
- break
300
+ # Extract the CPU name from PowerShell output
301
+ cpu_name = result.stdout.strip()
302
+ if not cpu_name:
303
+ print(
304
+ "[WARNING]: Could not detect processor name. Proceeding with installation."
305
+ )
306
+ return
294
307
 
295
308
  # Check for any supported series
296
309
  for series in SUPPORTED_RYZEN_AI_SERIES:
297
310
  # Look for the series number pattern - matches any processor in the supported series
298
311
  pattern = rf"ryzen ai.*\b{series[0]}\d{{2}}\b"
299
312
  match = re.search(pattern, cpu_name.lower(), re.IGNORECASE)
313
+
300
314
  if match:
301
315
  is_supported = True
302
316
  break
303
317
 
304
- except Exception: # pylint: disable=broad-exception-caught
305
- supported_series_str = ", ".join(SUPPORTED_RYZEN_AI_SERIES)
306
- raise UnsupportedPlatformError(
307
- f"Ryzen AI installation requires a Ryzen AI {supported_series_str} "
308
- f"series processor. Processor detection failed."
309
- )
318
+ if not is_supported:
319
+ print(
320
+ f"[WARNING]: Processor '{cpu_name}' may not be officially supported for Ryzen AI hybrid execution."
321
+ )
322
+ print(
323
+ "[WARNING]: Installation will proceed, but hybrid features may not work correctly."
324
+ )
325
+ print("[WARNING]: Officially supported processors: Ryzen AI 300-series")
310
326
 
311
- if not is_supported:
312
- supported_series_str = ", ".join(SUPPORTED_RYZEN_AI_SERIES)
313
- raise UnsupportedPlatformError(
314
- f"Ryzen AI installation requires a Ryzen AI {supported_series_str} "
315
- f"series processor. Your current processor ({cpu_name}) is not supported."
327
+ except Exception as e: # pylint: disable=broad-exception-caught
328
+ print(
329
+ f"[WARNING]: Could not detect processor ({e}). Proceeding with installation."
316
330
  )
331
+ print("[WARNING]: Hybrid features may not work if processor is not supported.")
317
332
 
318
333
 
319
334
  def download_and_extract_package(
@@ -334,6 +349,8 @@ def download_and_extract_package(
334
349
  Returns:
335
350
  str: Path where package was extracted (renamed to package-version)
336
351
  """
352
+ import requests
353
+
337
354
  zip_filename = f"{package_name}-{version}.zip"
338
355
  zip_path = os.path.join(install_dir, zip_filename)
339
356
  target_folder = os.path.join(install_dir, f"{package_name}-{version}")
@@ -691,6 +708,7 @@ class Install:
691
708
  raise ValueError(
692
709
  f"Value passed to ryzenai argument is not supported: {ryzenai}"
693
710
  )
711
+
694
712
  if build_model:
695
713
  model_prep_file = Install._install_ryzenai_model_artifacts(
696
714
  ryzen_ai_folder, version