lemonade-sdk 9.1.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.
- lemonade/__init__.py +5 -0
- lemonade/api.py +180 -0
- lemonade/cache.py +92 -0
- lemonade/cli.py +173 -0
- lemonade/common/__init__.py +0 -0
- lemonade/common/build.py +176 -0
- lemonade/common/cli_helpers.py +139 -0
- lemonade/common/exceptions.py +98 -0
- lemonade/common/filesystem.py +368 -0
- lemonade/common/inference_engines.py +408 -0
- lemonade/common/network.py +93 -0
- lemonade/common/printing.py +110 -0
- lemonade/common/status.py +471 -0
- lemonade/common/system_info.py +1411 -0
- lemonade/common/test_helpers.py +28 -0
- lemonade/profilers/__init__.py +1 -0
- lemonade/profilers/agt_power.py +437 -0
- lemonade/profilers/hwinfo_power.py +429 -0
- lemonade/profilers/memory_tracker.py +259 -0
- lemonade/profilers/profiler.py +58 -0
- lemonade/sequence.py +363 -0
- lemonade/state.py +159 -0
- lemonade/tools/__init__.py +1 -0
- lemonade/tools/accuracy.py +432 -0
- lemonade/tools/adapter.py +114 -0
- lemonade/tools/bench.py +302 -0
- lemonade/tools/flm/__init__.py +1 -0
- lemonade/tools/flm/utils.py +305 -0
- lemonade/tools/huggingface/bench.py +187 -0
- lemonade/tools/huggingface/load.py +235 -0
- lemonade/tools/huggingface/utils.py +359 -0
- lemonade/tools/humaneval.py +264 -0
- lemonade/tools/llamacpp/bench.py +255 -0
- lemonade/tools/llamacpp/load.py +222 -0
- lemonade/tools/llamacpp/utils.py +1260 -0
- lemonade/tools/management_tools.py +319 -0
- lemonade/tools/mmlu.py +319 -0
- lemonade/tools/oga/__init__.py +0 -0
- lemonade/tools/oga/bench.py +120 -0
- lemonade/tools/oga/load.py +804 -0
- lemonade/tools/oga/migration.py +403 -0
- lemonade/tools/oga/utils.py +462 -0
- lemonade/tools/perplexity.py +147 -0
- lemonade/tools/prompt.py +263 -0
- lemonade/tools/report/__init__.py +0 -0
- lemonade/tools/report/llm_report.py +203 -0
- lemonade/tools/report/table.py +899 -0
- lemonade/tools/server/__init__.py +0 -0
- lemonade/tools/server/flm.py +133 -0
- lemonade/tools/server/llamacpp.py +320 -0
- lemonade/tools/server/serve.py +2123 -0
- lemonade/tools/server/static/favicon.ico +0 -0
- lemonade/tools/server/static/index.html +279 -0
- lemonade/tools/server/static/js/chat.js +1059 -0
- lemonade/tools/server/static/js/model-settings.js +183 -0
- lemonade/tools/server/static/js/models.js +1395 -0
- lemonade/tools/server/static/js/shared.js +556 -0
- lemonade/tools/server/static/logs.html +191 -0
- lemonade/tools/server/static/styles.css +2654 -0
- lemonade/tools/server/static/webapp.html +321 -0
- lemonade/tools/server/tool_calls.py +153 -0
- lemonade/tools/server/tray.py +664 -0
- lemonade/tools/server/utils/macos_tray.py +226 -0
- lemonade/tools/server/utils/port.py +77 -0
- lemonade/tools/server/utils/thread.py +85 -0
- lemonade/tools/server/utils/windows_tray.py +408 -0
- lemonade/tools/server/webapp.py +34 -0
- lemonade/tools/server/wrapped_server.py +559 -0
- lemonade/tools/tool.py +374 -0
- lemonade/version.py +1 -0
- lemonade_install/__init__.py +1 -0
- lemonade_install/install.py +239 -0
- lemonade_sdk-9.1.1.dist-info/METADATA +276 -0
- lemonade_sdk-9.1.1.dist-info/RECORD +84 -0
- lemonade_sdk-9.1.1.dist-info/WHEEL +5 -0
- lemonade_sdk-9.1.1.dist-info/entry_points.txt +5 -0
- lemonade_sdk-9.1.1.dist-info/licenses/LICENSE +201 -0
- lemonade_sdk-9.1.1.dist-info/licenses/NOTICE.md +47 -0
- lemonade_sdk-9.1.1.dist-info/top_level.txt +3 -0
- lemonade_server/cli.py +805 -0
- lemonade_server/model_manager.py +758 -0
- lemonade_server/pydantic_models.py +159 -0
- lemonade_server/server_models.json +643 -0
- lemonade_server/settings.py +39 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Lemonade Server</title>
|
|
7
|
+
<link rel="icon" href="/favicon.ico">
|
|
8
|
+
<link rel="stylesheet" href="/static/styles.css">
|
|
9
|
+
<script>
|
|
10
|
+
window.SERVER_PORT = {{SERVER_PORT}};
|
|
11
|
+
</script>
|
|
12
|
+
{{SERVER_MODELS_JS}}
|
|
13
|
+
{{PLATFORM_JS}}
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<nav class="navbar" id="navbar">
|
|
17
|
+
<div class="navbar-brand">
|
|
18
|
+
<span class="brand-title"><a href="https://lemonade-server.ai"><img src="/favicon.ico" alt="🍋" class="brand-icon"> Lemonade Server</a></span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="navbar-links">
|
|
21
|
+
<a href="https://github.com/lemonade-sdk/lemonade" target="_blank">GitHub</a>
|
|
22
|
+
<a href="https://lemonade-server.ai/docs/" target="_blank">Docs</a>
|
|
23
|
+
<a href="https://lemonade-server.ai/docs/server/server_models/" target="_blank">Models</a>
|
|
24
|
+
<a href="https://lemonade-server.ai/docs/server/apps/" target="_blank">Featured Apps</a>
|
|
25
|
+
<a href="https://lemonade-server.ai/news/" target="_blank">News</a>
|
|
26
|
+
</div>
|
|
27
|
+
</nav>
|
|
28
|
+
<div id="error-banner" class="error-banner" style="display:none;">
|
|
29
|
+
<span id="error-banner-msg"></span>
|
|
30
|
+
<button class="close-btn" onclick="hideErrorBanner()">×</button>
|
|
31
|
+
</div>
|
|
32
|
+
<div id="migration-banner" class="migration-banner" style="display:none;">
|
|
33
|
+
<span id="migration-banner-msg"></span>
|
|
34
|
+
<button class="migration-action-btn" onclick="showMigrationModal()">Clean Up Now</button>
|
|
35
|
+
<button class="close-btn" onclick="hideMigrationBanner()">×</button>
|
|
36
|
+
</div>
|
|
37
|
+
<main class="main">
|
|
38
|
+
<div class="tab-content-wrapper">
|
|
39
|
+
<div class="tab-container">
|
|
40
|
+
<div class="tabs">
|
|
41
|
+
<div class="tab-group">
|
|
42
|
+
<button class="tab active" id="tab-chat" onclick="showTab('chat')">LLM Chat</button>
|
|
43
|
+
<button class="tab" id="tab-model-settings" onclick="showTab('settings')">Model Settings</button>
|
|
44
|
+
<button class="tab" id="tab-models" onclick="showTab('models')">Model Management</button>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="model-status-indicator" id="model-status-indicator">
|
|
48
|
+
<div class="model-select-wrapper">
|
|
49
|
+
<div class="status-light" id="status-light"></div>
|
|
50
|
+
<select id="model-select" class="model-select">
|
|
51
|
+
<option value="">Pick a model</option>
|
|
52
|
+
</select>
|
|
53
|
+
</div>
|
|
54
|
+
<button class="model-action-btn" id="model-unload-btn" title="Unload model" style="display: flex;">⏏</button>
|
|
55
|
+
<!-- Dropdown -->
|
|
56
|
+
<div class="dropdown">
|
|
57
|
+
<button class="dropbtn" aria-label="Dropdown" style="display: flex;">🛠️</button>
|
|
58
|
+
<div class="dropdown-content">
|
|
59
|
+
<a href="/static/logs.html" target="_blank">View Logs</a>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="tab-content active" id="content-chat">
|
|
65
|
+
<div class="chat-container">
|
|
66
|
+
<div class="chat-history" id="chat-history" style="overflow-y: auto;"></div>
|
|
67
|
+
<div class="chat-input-row">
|
|
68
|
+
<div class="input-with-indicator">
|
|
69
|
+
<textarea id="chat-input" placeholder="Type your message..." rows="1"></textarea>
|
|
70
|
+
</div>
|
|
71
|
+
<input type="file" id="file-attachment" style="display: none;" multiple accept="image/*">
|
|
72
|
+
<button id="attachment-btn" title="Attach files">📎</button>
|
|
73
|
+
<button id="toggle-btn" title="Start">Start</button>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="attachments-preview-container" id="attachments-preview-container">
|
|
76
|
+
<div class="attachments-preview-row" id="attachments-preview-row"></div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
<!-- App Suggestions Section -->
|
|
80
|
+
<div class="app-suggestions-section">
|
|
81
|
+
<div class="suggestion-text">
|
|
82
|
+
Use Lemonade with your favorite app
|
|
83
|
+
</div>
|
|
84
|
+
<div class="app-logos-grid">
|
|
85
|
+
<a href="https://lemonade-server.ai/docs/server/apps/open-webui/" target="_blank" class="app-logo-item" title="Open WebUI">
|
|
86
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/openwebui.jpg" alt="Open WebUI" class="app-logo-img">
|
|
87
|
+
<span class="app-name">Open WebUI</span>
|
|
88
|
+
</a>
|
|
89
|
+
<a href="https://lemonade-server.ai/docs/server/apps/continue/" target="_blank" class="app-logo-item" title="Continue">
|
|
90
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/continue_dev.png" alt="Continue" class="app-logo-img">
|
|
91
|
+
<span class="app-name">Continue</span>
|
|
92
|
+
</a>
|
|
93
|
+
<a href="https://github.com/amd/gaia" target="_blank" class="app-logo-item" title="Gaia">
|
|
94
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/gaia.ico" alt="Gaia" class="app-logo-img">
|
|
95
|
+
<span class="app-name">Gaia</span>
|
|
96
|
+
</a>
|
|
97
|
+
<a href="https://lemonade-server.ai/docs/server/apps/anythingLLM/" target="_blank" class="app-logo-item" title="AnythingLLM">
|
|
98
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/anything_llm.png" alt="AnythingLLM" class="app-logo-img">
|
|
99
|
+
<span class="app-name">AnythingLLM</span>
|
|
100
|
+
</a>
|
|
101
|
+
<a href="https://lemonade-server.ai/docs/server/apps/ai-dev-gallery/" target="_blank" class="app-logo-item" title="AI Dev Gallery">
|
|
102
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/ai_dev_gallery.webp" alt="AI Dev Gallery" class="app-logo-img">
|
|
103
|
+
<span class="app-name">AI Dev Gallery</span>
|
|
104
|
+
</a>
|
|
105
|
+
<a href="https://lemonade-server.ai/docs/server/apps/lm-eval/" target="_blank" class="app-logo-item" title="LM-Eval">
|
|
106
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/lm_eval.png" alt="LM-Eval" class="app-logo-img">
|
|
107
|
+
<span class="app-name">LM-Eval</span>
|
|
108
|
+
</a>
|
|
109
|
+
<a href="https://github.com/lemonade-sdk/lemonade-arcade" target="_blank" class="app-logo-item" title="Lemonade Arcade">
|
|
110
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/lemonade-arcade/refs/heads/main/docs/assets/favicon.ico" alt="Lemonade Arcade" class="app-logo-img">
|
|
111
|
+
<span class="app-name">Lemonade Arcade</span>
|
|
112
|
+
</a>
|
|
113
|
+
<a href="https://github.com/lemonade-sdk/lemonade/blob/main/docs/server/apps/ai-toolkit.md" target="_blank" class="app-logo-item" title="AI Toolkit">
|
|
114
|
+
<img src="https://raw.githubusercontent.com/lemonade-sdk/assets/refs/heads/main/partner_logos/ai_toolkit.png" alt="AI Toolkit" class="app-logo-img">
|
|
115
|
+
<span class="app-name">AI Toolkit</span>
|
|
116
|
+
</a>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="tab-content" id="content-settings">
|
|
121
|
+
<div class="model-settings-container">
|
|
122
|
+
<div class="settings-form">
|
|
123
|
+
<div class="setting-row">
|
|
124
|
+
<label for="setting-temperature">Temperature:</label>
|
|
125
|
+
<input type="number" id="setting-temperature" min="0" max="2" step="0.1" placeholder="default" />
|
|
126
|
+
<span class="setting-description">Controls randomness in responses (0 = deterministic, 2 = very random)</span>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="setting-row">
|
|
129
|
+
<label for="setting-top-k">Top K:</label>
|
|
130
|
+
<input type="number" id="setting-top-k" min="1" max="100" step="1" placeholder="default" />
|
|
131
|
+
<span class="setting-description">Limits token selection to top K most likely tokens</span>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="setting-row">
|
|
134
|
+
<label for="setting-top-p">Top P:</label>
|
|
135
|
+
<input type="number" id="setting-top-p" min="0" max="1" step="0.01" placeholder="default" />
|
|
136
|
+
<span class="setting-description">Nucleus sampling - considers tokens with cumulative probability up to P</span>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="setting-row">
|
|
139
|
+
<label for="setting-repeat-penalty">Repeat Penalty:</label>
|
|
140
|
+
<input type="number" id="setting-repeat-penalty" min="0.5" max="2" step="0.05" placeholder="default" />
|
|
141
|
+
<span class="setting-description">Penalty for repeating tokens (1 = no penalty, >1 = less repetition)</span>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="setting-field">
|
|
144
|
+
<label for="enable-thinking">Enable Thinking:</label>
|
|
145
|
+
<input type="checkbox" id="enable-thinking">
|
|
146
|
+
<br>
|
|
147
|
+
<span class="setting-description">Determines whether hybrid reasoning models, such as Qwen3, will use thinking.</span>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="setting-actions">
|
|
150
|
+
<button id="reset-settings-btn" class="reset-btn">Reset to Defaults</button>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="tab-content" id="content-models">
|
|
156
|
+
<div class="model-browser-container">
|
|
157
|
+
<div class="model-browser-sidebar">
|
|
158
|
+
<div class="model-category" data-category="hot">
|
|
159
|
+
<div class="category-header active" onclick="toggleCategory('hot')">
|
|
160
|
+
<span class="category-icon">🔥</span>
|
|
161
|
+
<span class="category-name">Hot Models</span>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="category-content expanded" id="category-hot"></div>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="model-category-section">
|
|
166
|
+
<div class="section-header">
|
|
167
|
+
<span class="section-icon">🔧</span>
|
|
168
|
+
<span class="section-name">By Recipe</span>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="section-content">
|
|
171
|
+
<div class="subcategory" data-recipe="llamacpp" onclick="selectRecipe('llamacpp')">llama.cpp</div>
|
|
172
|
+
<div class="subcategory" data-recipe="oga-hybrid" onclick="selectRecipe('oga-hybrid')">OGA Hybrid</div>
|
|
173
|
+
<div class="subcategory" data-recipe="oga-npu" onclick="selectRecipe('oga-npu')">OGA NPU</div>
|
|
174
|
+
<div class="subcategory" data-recipe="oga-cpu" onclick="selectRecipe('oga-cpu')">OGA CPU</div>
|
|
175
|
+
<div class="subcategory" data-recipe="flm" onclick="selectRecipe('flm')">FastFlowLM NPU</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="model-category-section">
|
|
179
|
+
<div class="section-header">
|
|
180
|
+
<span class="section-icon">🏷️</span>
|
|
181
|
+
<span class="section-name">By Category</span>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="section-content">
|
|
184
|
+
<div class="subcategory" data-label="coding" onclick="selectLabel('coding')">Coding</div>
|
|
185
|
+
<div class="subcategory" data-label="vision" onclick="selectLabel('vision')">Vision</div>
|
|
186
|
+
<div class="subcategory" data-label="reasoning" onclick="selectLabel('reasoning')">Reasoning</div>
|
|
187
|
+
<div class="subcategory" data-label="tool-calling" onclick="selectLabel('tool-calling')">Tool Calling</div>
|
|
188
|
+
<div class="subcategory" data-label="reranking" onclick="selectLabel('reranking')">Reranking</div>
|
|
189
|
+
<div class="subcategory" data-label="embeddings" onclick="selectLabel('embeddings')">Embeddings</div>
|
|
190
|
+
<div class="subcategory" data-label="custom" onclick="selectLabel('custom')">Custom</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
<div class="model-category" data-category="add">
|
|
194
|
+
<div class="category-header" onclick="showAddModelForm()">
|
|
195
|
+
<span class="category-icon">➕</span>
|
|
196
|
+
<span class="category-name">Add a Model</span>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="model-browser-main">
|
|
201
|
+
<div class="model-list" id="model-list"></div>
|
|
202
|
+
|
|
203
|
+
<!-- Add Model Form (hidden by default) -->
|
|
204
|
+
<div class="add-model-form-main" id="add-model-form-main" style="display: none;">
|
|
205
|
+
<form id="register-model-form" autocomplete="off" class="form-content">
|
|
206
|
+
<div class="register-form-row">
|
|
207
|
+
<label class="register-label">
|
|
208
|
+
Model Name
|
|
209
|
+
<span class="tooltip-icon" data-tooltip="Enter a unique short name for your model. This is how the model will be referenced by Lemonade Server and connected apps. It will be prefixed with 'user.' to distinguish it from the built-in models.">ⓘ</span>
|
|
210
|
+
</label>
|
|
211
|
+
<div class="register-model-name-group">
|
|
212
|
+
<span class="register-model-prefix styled-prefix">user.</span>
|
|
213
|
+
<input type="text" id="register-model-name" name="model_name" placeholder="Gemma-3-12b-it-GGUF" required autocomplete="off">
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="register-form-row">
|
|
217
|
+
<label class="register-label">
|
|
218
|
+
Checkpoint
|
|
219
|
+
<span class="tooltip-icon" data-tooltip="Specify the model checkpoint path from Hugging Face (e.g., org-name/model-name:variant).">ⓘ</span>
|
|
220
|
+
</label>
|
|
221
|
+
<div class="checkpoint-input-group">
|
|
222
|
+
<input type="text" id="register-checkpoint" name="checkpoint" placeholder="unsloth/gemma-3-12b-it-GGUF:Q4_0" class="register-textbox" autocomplete="off">
|
|
223
|
+
<button type="button" id="select-folder-btn" class="folder-select-btn" title="Select local folder">📁</button>
|
|
224
|
+
</div>
|
|
225
|
+
<input type="file" id="folder-input" webkitdirectory directory style="display: none;">
|
|
226
|
+
</div>
|
|
227
|
+
<div class="register-form-row">
|
|
228
|
+
<label class="register-label">
|
|
229
|
+
Recipe
|
|
230
|
+
<span class="tooltip-icon" data-tooltip="Select the Lemonade recipe corresponding to the inference engine and device Lemonade Server should use for the model. Use llamacpp for GGUF models. For OGA/ONNX models, click the More Info button to learn about the oga-* recipes.">ⓘ</span>
|
|
231
|
+
</label>
|
|
232
|
+
<select id="register-recipe" name="recipe" required>
|
|
233
|
+
<option value="llamacpp">llamacpp</option>
|
|
234
|
+
<option value="flm">flm</option>
|
|
235
|
+
<option value="oga-npu">oga-npu</option>
|
|
236
|
+
<option value="oga-hybrid">oga-hybrid</option>
|
|
237
|
+
<option value="oga-cpu">oga-cpu</option>
|
|
238
|
+
</select>
|
|
239
|
+
<a href="https://lemonade-server.ai/docs/lemonade_api/" target="_blank" class="register-doc-link">More info</a>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="register-form-row register-form-row-tight">
|
|
242
|
+
<label class="register-label">
|
|
243
|
+
mmproj file
|
|
244
|
+
<span class="tooltip-icon" data-tooltip="Specify an mmproj file from the same Hugging Face checkpoint as the model. This is used for multimodal models, such as VLMs. Leave empty if not needed.">ⓘ</span>
|
|
245
|
+
</label>
|
|
246
|
+
<input type="text" id="register-mmproj" name="mmproj" placeholder="(Optional) mmproj-F16.gguf" autocomplete="off">
|
|
247
|
+
</div>
|
|
248
|
+
<div class="register-form-row register-form-row-tight register-checkboxes-row">
|
|
249
|
+
<label class="register-label reasoning-inline">
|
|
250
|
+
<input type="checkbox" id="register-reasoning" name="reasoning">
|
|
251
|
+
Reasoning
|
|
252
|
+
<span class="tooltip-icon" data-tooltip="Enable to inform Lemonade Server that the model has reasoning capabilities that will use thinking tokens.">ⓘ</span>
|
|
253
|
+
</label>
|
|
254
|
+
<label class="register-label reasoning-inline">
|
|
255
|
+
<input type="checkbox" id="register-vision" name="vision">
|
|
256
|
+
Vision
|
|
257
|
+
<span class="tooltip-icon" data-tooltip="Enable to inform Lemonade Server that the model has vision capabilities for processing images.">ⓘ</span>
|
|
258
|
+
</label>
|
|
259
|
+
<label class="register-label reasoning-inline">
|
|
260
|
+
<input type="checkbox" id="register-embedding" name="embedding">
|
|
261
|
+
Embedding
|
|
262
|
+
<span class="tooltip-icon" data-tooltip="Enable to inform Lemonade Server that the model is an embedding model for use with the /api/v1/embeddings endpoint.">ⓘ</span>
|
|
263
|
+
</label>
|
|
264
|
+
<label class="register-label reasoning-inline">
|
|
265
|
+
<input type="checkbox" id="register-reranking" name="reranking">
|
|
266
|
+
Reranking
|
|
267
|
+
<span class="tooltip-icon" data-tooltip="Enable to inform Lemonade Server that the model is a reranking model for use with the /api/v1/reranking endpoint.">ⓘ</span>
|
|
268
|
+
</label>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="register-form-row register-form-row-tight">
|
|
271
|
+
<button type="submit" id="register-submit">Install</button>
|
|
272
|
+
<span id="register-model-status" class="register-status"></span>
|
|
273
|
+
</div>
|
|
274
|
+
</form>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
</main>
|
|
282
|
+
<footer class="site-footer">
|
|
283
|
+
<div class="dad-joke">When life gives you LLMs, make an LLM aide.</div>
|
|
284
|
+
<div class="copyright">Copyright 2025 AMD</div>
|
|
285
|
+
</footer>
|
|
286
|
+
|
|
287
|
+
<!-- External libraries -->
|
|
288
|
+
<script src="https://cdn.jsdelivr.net/npm/openai@6.7.0/dist/openai.min.js"></script>
|
|
289
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@9.1.0/marked.min.js"></script>
|
|
290
|
+
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
|
291
|
+
|
|
292
|
+
<!-- Migration Cleanup Modal -->
|
|
293
|
+
<div id="migration-modal" class="modal" style="display:none;">
|
|
294
|
+
<div class="modal-content">
|
|
295
|
+
<div class="modal-header">
|
|
296
|
+
<h2>Clean Up Incompatible Models</h2>
|
|
297
|
+
<button class="modal-close" onclick="hideMigrationModal()">×</button>
|
|
298
|
+
</div>
|
|
299
|
+
<div class="modal-body">
|
|
300
|
+
<p>The following RyzenAI models are incompatible with RyzenAI 1.6 and can be safely deleted:</p>
|
|
301
|
+
<p class="migration-instructions">
|
|
302
|
+
After deleting, you can re-download compatible Ryzen AI 1.6 models from the <em>OGA NPU</em> and <em>OGA Hybrid</em> tabs.</p>
|
|
303
|
+
<div id="migration-model-list" class="migration-model-list"></div>
|
|
304
|
+
<div class="migration-summary">
|
|
305
|
+
<strong>Total space to free: <span id="migration-total-size"></span></strong>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
<div class="modal-footer">
|
|
309
|
+
<button class="cancel-btn" onclick="hideMigrationModal()">Cancel</button>
|
|
310
|
+
<button class="delete-btn" onclick="deleteIncompatibleModels()">Delete All</button>
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<!-- Application JavaScript -->
|
|
316
|
+
<script src="/static/js/shared.js"></script>
|
|
317
|
+
<script src="/static/js/models.js"></script>
|
|
318
|
+
<script src="/static/js/model-settings.js"></script>
|
|
319
|
+
<script src="/static/js/chat.js"></script>
|
|
320
|
+
</body>
|
|
321
|
+
</html>
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import List, Dict, Pattern, Optional
|
|
3
|
+
import logging
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def extract_code_block(text: str) -> str:
|
|
8
|
+
"""
|
|
9
|
+
Extracts the content inside triple backtick code blocks from a text.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
text (str): The text to extract the code block from.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
str: The content of the first code block if any are found, otherwise the raw text.
|
|
16
|
+
"""
|
|
17
|
+
# Regex pattern to match triple backtick code blocks (with optional language hint)
|
|
18
|
+
pattern = re.compile(r"```(?:\w+)?\n(.*?)```", re.DOTALL)
|
|
19
|
+
|
|
20
|
+
# Find all matches
|
|
21
|
+
code_blocks = pattern.findall(text)
|
|
22
|
+
|
|
23
|
+
# Return first match or raw text
|
|
24
|
+
return code_blocks[0] if code_blocks else text
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def standardize_tool_call(tool_call: dict) -> dict | None:
|
|
28
|
+
"""
|
|
29
|
+
Standardizes the format of tool calls according to the format expected by OpenAI.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
tool_call (dict): The tool call to validate.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
dict | None: Standardized tool call if valid, None otherwise.
|
|
36
|
+
"""
|
|
37
|
+
# Ensure the tool call has a "name"
|
|
38
|
+
standardized_tool_call = {}
|
|
39
|
+
if "name" in tool_call:
|
|
40
|
+
standardized_tool_call["name"] = tool_call["name"]
|
|
41
|
+
else:
|
|
42
|
+
logging.warning("Tool call does not have a 'name' field.")
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
# Ensure the tool call has "arguments"
|
|
46
|
+
if "arguments" in tool_call:
|
|
47
|
+
standardized_tool_call["arguments"] = tool_call["arguments"]
|
|
48
|
+
elif "parameters" in tool_call:
|
|
49
|
+
standardized_tool_call["arguments"] = tool_call["parameters"]
|
|
50
|
+
else:
|
|
51
|
+
logging.warning("Tool call does not have a 'arguments' or 'parameters' field.")
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
return standardized_tool_call
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_tool_call_pattern(added_tokens_decoder: List[str]) -> Optional[Pattern]:
|
|
58
|
+
"""
|
|
59
|
+
Extracts tool call pattern from the added tokens decoder.
|
|
60
|
+
"""
|
|
61
|
+
special_tokens = [v.content for v in added_tokens_decoder.values()]
|
|
62
|
+
|
|
63
|
+
# Pattern 1: <tool_call>...</tool_call> block
|
|
64
|
+
# Sample model that uses this pattern: Qwen3-8B
|
|
65
|
+
if "<tool_call>" in special_tokens and "</tool_call>" in special_tokens:
|
|
66
|
+
return re.compile(r"<tool_call>(.*?)</tool_call>", re.DOTALL)
|
|
67
|
+
|
|
68
|
+
# Pattern 2: [TOOL_CALLS] [ {...} ] block
|
|
69
|
+
# Sample model that uses this pattern: Mistral-7B-Instruct-v0.3
|
|
70
|
+
elif "[TOOL_CALLS]" in special_tokens:
|
|
71
|
+
return re.compile(r"\[TOOL_CALLS\]\s*\[(.*?)\](?=\s*<|/?eos|$)", re.DOTALL)
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
logging.warning(
|
|
75
|
+
"Tool calling identifiers were not found for the current model."
|
|
76
|
+
)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def extract_tool_calls(
|
|
81
|
+
text: str, tool_call_pattern: Optional[Pattern] = None
|
|
82
|
+
) -> tuple[List[Dict], str]:
|
|
83
|
+
"""
|
|
84
|
+
Extracts tool calls from generated text based on tool calling identifiers.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
text (str): The text output generated by the model.
|
|
88
|
+
tool_call_pattern (Optional[Pattern]): The pattern to use to extract tool calls.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
tuple[List[Dict], str]: A tuple containing:
|
|
92
|
+
- List[Dict]: A list of extracted tool call objects (raw JSON-like dicts)
|
|
93
|
+
- str: The original text with tool calls removed
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
matches = []
|
|
97
|
+
if tool_call_pattern is not None:
|
|
98
|
+
matches = list(tool_call_pattern.finditer(text))
|
|
99
|
+
|
|
100
|
+
# Some models don't use any tool calling identifiers.
|
|
101
|
+
# Instead, tool calls are identified by only generating JSON content.
|
|
102
|
+
# Sample model that uses this pattern: Llama-3.1-8B-Instruct
|
|
103
|
+
else:
|
|
104
|
+
try:
|
|
105
|
+
# Remove the json for a code block if needed
|
|
106
|
+
parsed_text = extract_code_block(text)
|
|
107
|
+
json_tool_calls = json.loads(parsed_text)
|
|
108
|
+
|
|
109
|
+
if isinstance(json_tool_calls, dict):
|
|
110
|
+
json_tool_calls = [json_tool_calls]
|
|
111
|
+
|
|
112
|
+
extracted_tool_calls = []
|
|
113
|
+
for tool_call in json_tool_calls:
|
|
114
|
+
# Return the tool call if all calls are valid
|
|
115
|
+
standard_tool_call = standardize_tool_call(tool_call)
|
|
116
|
+
if standard_tool_call is not None:
|
|
117
|
+
extracted_tool_calls.append(standard_tool_call)
|
|
118
|
+
else:
|
|
119
|
+
return [], text
|
|
120
|
+
|
|
121
|
+
return extracted_tool_calls, ""
|
|
122
|
+
|
|
123
|
+
except json.JSONDecodeError:
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
# Process matches in reverse to avoid position shifting
|
|
127
|
+
extracted_tool_calls = []
|
|
128
|
+
cleaned_text = text
|
|
129
|
+
for match in reversed(matches):
|
|
130
|
+
content = match.group(1).strip()
|
|
131
|
+
json_tool_call = None
|
|
132
|
+
try:
|
|
133
|
+
json_tool_call = json.loads(content)
|
|
134
|
+
except json.JSONDecodeError:
|
|
135
|
+
logging.warning("Could not parse tool call as JSON.")
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
# Attempt to standardize the tool call
|
|
139
|
+
standard_tool_call = standardize_tool_call(json_tool_call)
|
|
140
|
+
if standard_tool_call is None:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
# If the content is a valid JSON object, add it to the list
|
|
144
|
+
extracted_tool_calls.append(standard_tool_call)
|
|
145
|
+
|
|
146
|
+
# Remove the matched tool call from the text
|
|
147
|
+
cleaned_text = cleaned_text[: match.start()] + cleaned_text[match.end() :]
|
|
148
|
+
|
|
149
|
+
return extracted_tool_calls, cleaned_text.strip()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# This file was originally licensed under Apache 2.0. It has been modified.
|
|
153
|
+
# Modifications Copyright (c) 2025 AMD
|