Upload 22 files
Browse files- Dockerfile +17 -11
- install_functions.py +69 -413
- setup_endpoints.sh +0 -37
Dockerfile
CHANGED
|
@@ -9,29 +9,35 @@ ENV WEBUI_AUTH=true
|
|
| 9 |
ENV ENABLE_SIGNUP=false
|
| 10 |
ENV DEFAULT_USER_ROLE=user
|
| 11 |
|
| 12 |
-
# Optional providers and integrations
|
| 13 |
-
ENV OPENAI_API_BASE_URL=https://api.openai.com/v1
|
| 14 |
-
|
| 15 |
# Analytics opt-out
|
| 16 |
ENV ANONYMIZED_TELEMETRY=false
|
| 17 |
ENV SCARF_NO_ANALYTICS=true
|
| 18 |
ENV DO_NOT_TRACK=true
|
| 19 |
|
|
|
|
| 20 |
COPY setup_endpoints.sh /app/setup_endpoints.sh
|
| 21 |
COPY backup_restore.sh /app/backup_restore.sh
|
|
|
|
| 22 |
COPY context_detector.py /app/context_detector.py
|
| 23 |
-
COPY smart_matcher.py /app/smart_matcher.py
|
| 24 |
COPY token_compressor.py /app/token_compressor.py
|
| 25 |
-
COPY
|
| 26 |
-
COPY
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
RUN chmod +x /app/setup_endpoints.sh /app/backup_restore.sh
|
| 29 |
|
| 30 |
EXPOSE 8080
|
| 31 |
|
| 32 |
-
# POPRAVLJENI STARTUP REDOSLIJED:
|
| 33 |
-
# 1. Restore se zavrsi PRIJE nego WebUI krene (semicolon = sekvencijalan)
|
| 34 |
-
# 2. Backup loop pokrenuti u pozadini (&)
|
| 35 |
-
# 3. setup_endpoints.sh ceka 10s i konfigurira endpointe u pozadini (&)
|
| 36 |
-
# 4. start.sh ostaje glavni proces (foreground)
|
| 37 |
CMD bash -lc "bash /app/backup_restore.sh restore; bash /app/backup_restore.sh loop & sleep 10 && bash /app/setup_endpoints.sh & bash start.sh"
|
|
|
|
| 9 |
ENV ENABLE_SIGNUP=false
|
| 10 |
ENV DEFAULT_USER_ROLE=user
|
| 11 |
|
|
|
|
|
|
|
|
|
|
| 12 |
# Analytics opt-out
|
| 13 |
ENV ANONYMIZED_TELEMETRY=false
|
| 14 |
ENV SCARF_NO_ANALYTICS=true
|
| 15 |
ENV DO_NOT_TRACK=true
|
| 16 |
|
| 17 |
+
# Python skripte
|
| 18 |
COPY setup_endpoints.sh /app/setup_endpoints.sh
|
| 19 |
COPY backup_restore.sh /app/backup_restore.sh
|
| 20 |
+
COPY install_functions.py /app/install_functions.py
|
| 21 |
COPY context_detector.py /app/context_detector.py
|
|
|
|
| 22 |
COPY token_compressor.py /app/token_compressor.py
|
| 23 |
+
COPY coding_priority_pipe.py /app/coding_priority_pipe.py
|
| 24 |
+
COPY smart_matcher.py /app/smart_matcher.py
|
| 25 |
+
COPY api_router.py /app/api_router.py
|
| 26 |
+
COPY system_prompt.txt /app/system_prompt.txt
|
| 27 |
+
|
| 28 |
+
# JSON funkcije
|
| 29 |
+
COPY token_saver.json /app/token_saver.json
|
| 30 |
+
COPY context_clip_filter.json /app/context_clip_filter.json
|
| 31 |
+
COPY auto_disable_native_tools.json /app/auto_disable_native_tools.json
|
| 32 |
+
COPY auto_memory.json /app/auto_memory.json
|
| 33 |
+
COPY global_system_prompt_filter.json /app/global_system_prompt_filter.json
|
| 34 |
+
COPY __easysearch_v0_4_3__high-performance_web_search_filter.json /app/__easysearch_v0_4_3__high-performance_web_search_filter.json
|
| 35 |
+
COPY __mermaid_doctor_-_heals_broken_mermaid_diagrams_generated_by_small_or_hallucinating_models.json /app/__mermaid_doctor_-_heals_broken_mermaid_diagrams_generated_by_small_or_hallucinating_models.json
|
| 36 |
+
COPY github_simple.json /app/github_simple.json
|
| 37 |
+
COPY pdf_tools_-_rich_ui_for_in_context_basic_editing_.json /app/pdf_tools_-_rich_ui_for_in_context_basic_editing_.json
|
| 38 |
|
| 39 |
RUN chmod +x /app/setup_endpoints.sh /app/backup_restore.sh
|
| 40 |
|
| 41 |
EXPOSE 8080
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
CMD bash -lc "bash /app/backup_restore.sh restore; bash /app/backup_restore.sh loop & sleep 10 && bash /app/setup_endpoints.sh & bash start.sh"
|
install_functions.py
CHANGED
|
@@ -1,428 +1,84 @@
|
|
| 1 |
-
"""
|
| 2 |
-
Instalira sve funkcije (filters, tools, actions) i kreira Custom Model Preset.
|
| 3 |
-
Poziva se automatski iz setup_endpoints.sh pri startu Space-a.
|
| 4 |
-
|
| 5 |
-
Koristi: python3 install_functions.py <base_url> <token>
|
| 6 |
-
"""
|
| 7 |
-
|
| 8 |
import json
|
| 9 |
import urllib.request
|
| 10 |
import urllib.error
|
| 11 |
import sys
|
| 12 |
import os
|
| 13 |
|
| 14 |
-
|
| 15 |
-
TOKEN = sys.argv[2] if len(sys.argv) > 2 else ''
|
| 16 |
-
|
| 17 |
-
if not TOKEN:
|
| 18 |
-
print("❌ No token provided.")
|
| 19 |
-
sys.exit(1)
|
| 20 |
-
|
| 21 |
-
HEADERS = {
|
| 22 |
-
'Content-Type': 'application/json',
|
| 23 |
-
'Authorization': f'Bearer {TOKEN}'
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
APP_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 27 |
-
|
| 28 |
-
# ─────────────────────────────────────────────
|
| 29 |
-
# Helpers
|
| 30 |
-
# ─────────────────────────────────────────────
|
| 31 |
-
|
| 32 |
-
def api(method, path, data=None):
|
| 33 |
-
url = BASE_URL + path
|
| 34 |
-
body = json.dumps(data).encode() if data is not None else None
|
| 35 |
-
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
|
| 36 |
-
try:
|
| 37 |
-
with urllib.request.urlopen(req) as r:
|
| 38 |
-
return r.status, json.loads(r.read().decode())
|
| 39 |
-
except urllib.error.HTTPError as e:
|
| 40 |
-
return e.code, e.read().decode()
|
| 41 |
-
|
| 42 |
-
def install_function(func_id, name, func_type, content):
|
| 43 |
-
"""Instaliraj ili ažuriraj funkciju."""
|
| 44 |
-
# Provjeri postoji li
|
| 45 |
-
status, _ = api('GET', f'/api/v1/functions/id/{func_id}')
|
| 46 |
-
|
| 47 |
-
payload = {
|
| 48 |
-
'id': func_id,
|
| 49 |
-
'name': name,
|
| 50 |
-
'type': func_type,
|
| 51 |
-
'content': content,
|
| 52 |
-
'meta': {'description': name}
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
if status == 200:
|
| 56 |
-
s, r = api('POST', f'/api/v1/functions/id/{func_id}/update', payload)
|
| 57 |
-
label = "ažuriran" if s == 200 else f"greška {s}"
|
| 58 |
-
else:
|
| 59 |
-
s, r = api('POST', '/api/v1/functions/create', payload)
|
| 60 |
-
label = "instaliran" if s == 200 else f"greška {s}"
|
| 61 |
-
|
| 62 |
-
# Aktiviraj
|
| 63 |
-
api('POST', f'/api/v1/functions/id/{func_id}/toggle')
|
| 64 |
-
|
| 65 |
-
icon = "✅" if s == 200 else "❌"
|
| 66 |
-
print(f" {icon} [{func_type}] {name} — {label}")
|
| 67 |
-
return s == 200
|
| 68 |
-
|
| 69 |
-
def load_json_function(filepath):
|
| 70 |
-
"""Učitaj funkciju iz JSON export fajla."""
|
| 71 |
-
with open(filepath) as f:
|
| 72 |
-
d = json.load(f)
|
| 73 |
-
item = d[0] if isinstance(d, list) else d
|
| 74 |
-
# Detektuj tip iz sadržaja
|
| 75 |
-
content = item.get('content', '')
|
| 76 |
-
if 'class Filter' in content:
|
| 77 |
-
ftype = 'filter'
|
| 78 |
-
elif 'class Pipe' in content:
|
| 79 |
-
ftype = 'pipe'
|
| 80 |
-
elif 'class Tools' in content or 'class Action' in content:
|
| 81 |
-
ftype = 'action'
|
| 82 |
-
else:
|
| 83 |
-
ftype = item.get('meta', {}).get('type', 'filter')
|
| 84 |
-
return item['id'], item['name'], ftype, content
|
| 85 |
-
|
| 86 |
-
# ─────────────────────────────────────────────
|
| 87 |
-
# 1. Instaliraj sve JSON funkcije
|
| 88 |
-
# ─────────────────────────────────────────────
|
| 89 |
-
|
| 90 |
-
print("\n📦 Instaliram funkcije iz JSON fajlova...")
|
| 91 |
-
|
| 92 |
-
JSON_FILES = [
|
| 93 |
-
'global_system_prompt_filter.json',
|
| 94 |
-
'__easysearch_v0_4_3__high-performance_web_search_filter.json',
|
| 95 |
-
'token_saver.json',
|
| 96 |
-
'context_clip_filter.json',
|
| 97 |
-
'auto_disable_native_tools.json',
|
| 98 |
-
'auto_memory.json',
|
| 99 |
-
'__mermaid_doctor_-_heals_broken_mermaid_diagrams_generated_by_small_or_hallucinating_models.json',
|
| 100 |
-
'github_simple.json',
|
| 101 |
-
'pdf_tools_-_rich_ui_for_in_context_basic_editing_.json',
|
| 102 |
-
]
|
| 103 |
-
|
| 104 |
-
installed_filter_ids = []
|
| 105 |
-
for fname in JSON_FILES:
|
| 106 |
-
fpath = os.path.join(APP_DIR, fname)
|
| 107 |
-
if not os.path.exists(fpath):
|
| 108 |
-
print(f" ⚠️ {fname} nije pronađen, preskačem")
|
| 109 |
-
continue
|
| 110 |
-
func_id, name, ftype, content = load_json_function(fpath)
|
| 111 |
-
ok = install_function(func_id, name, ftype, content)
|
| 112 |
-
if ok and ftype == 'filter':
|
| 113 |
-
installed_filter_ids.append(func_id)
|
| 114 |
-
|
| 115 |
-
# ─────────────────────────────────────────────
|
| 116 |
-
# 2. Instaliraj naše custom Python funkcije
|
| 117 |
-
# ─────────────────────────────────────────────
|
| 118 |
-
|
| 119 |
-
print("\n🛠️ Instaliram custom funkcije...")
|
| 120 |
-
|
| 121 |
-
CUSTOM_FUNCTIONS = [
|
| 122 |
-
('context_detector', 'Context Detector', 'filter', 'context_detector.py'),
|
| 123 |
-
('token_compressor', 'Token Compressor', 'filter', 'token_compressor.py'),
|
| 124 |
-
('coding_fallback', '🔀 Smart Coding Router', 'pipe', 'coding_priority_pipe.py'),
|
| 125 |
-
('smart_matcher', 'Smart Matcher', 'tool', 'smart_matcher.py'),
|
| 126 |
-
]
|
| 127 |
-
|
| 128 |
-
for func_id, name, ftype, pyfile in CUSTOM_FUNCTIONS:
|
| 129 |
-
fpath = os.path.join(APP_DIR, pyfile)
|
| 130 |
-
if not os.path.exists(fpath):
|
| 131 |
-
print(f" ⚠️ {pyfile} nije pronađen")
|
| 132 |
-
continue
|
| 133 |
-
content = open(fpath).read()
|
| 134 |
-
ok = install_function(func_id, name, ftype, content)
|
| 135 |
-
if ok and ftype == 'filter':
|
| 136 |
-
installed_filter_ids.append(func_id)
|
| 137 |
-
|
| 138 |
-
# ─────────────────────────────────────────────
|
| 139 |
-
# 3. Postavi Global System Prompt
|
| 140 |
-
# ─────────────────────────────────────────────
|
| 141 |
-
|
| 142 |
-
print("\n📝 Postavljam Global System Prompt...")
|
| 143 |
-
|
| 144 |
-
SYSTEM_PROMPT_FILE = os.path.join(APP_DIR, 'system_prompt.txt')
|
| 145 |
-
if os.path.exists(SYSTEM_PROMPT_FILE):
|
| 146 |
-
system_prompt = open(SYSTEM_PROMPT_FILE).read()
|
| 147 |
-
|
| 148 |
-
# Update valve za global_system_prompt_filter
|
| 149 |
-
valve_payload = {
|
| 150 |
-
'system_message': system_prompt,
|
| 151 |
-
'timezone': 'Europe/Sarajevo',
|
| 152 |
-
'skip_tags': []
|
| 153 |
-
}
|
| 154 |
-
s, r = api('POST', '/api/v1/functions/id/global_system_prompt_filter/valves/update', valve_payload)
|
| 155 |
-
if s == 200:
|
| 156 |
-
print(" ✅ System prompt postavljen")
|
| 157 |
-
else:
|
| 158 |
-
print(f" ⚠️ Greška pri postavljanju system prompta: {s}")
|
| 159 |
-
else:
|
| 160 |
-
print(" ⚠️ system_prompt.txt nije pronađen")
|
| 161 |
-
|
| 162 |
-
# ─────────────────────────────────────────────
|
| 163 |
-
# 4. Kreiraj Custom Model Preset
|
| 164 |
-
# ─────────────────────────────────────────────
|
| 165 |
-
|
| 166 |
-
print("\n🤖 Kreiram Custom Model Preset...")
|
| 167 |
-
|
| 168 |
-
# Sve filter ID-ove koji treba biti aktivni na modelu
|
| 169 |
-
ALL_FILTER_IDS = list(dict.fromkeys([
|
| 170 |
-
'global_system_prompt_filter',
|
| 171 |
-
'easysearch',
|
| 172 |
-
'token_saver',
|
| 173 |
-
'context_clip_filter',
|
| 174 |
-
'auto_disable_native_tools',
|
| 175 |
-
'auto_memory',
|
| 176 |
-
'context_detector',
|
| 177 |
-
'token_compressor',
|
| 178 |
-
'mermaid_doctor',
|
| 179 |
-
] + installed_filter_ids))
|
| 180 |
-
|
| 181 |
-
model_payload = {
|
| 182 |
-
'id': 'nerdur_assistant',
|
| 183 |
-
'name': '🧠 Nerdur Assistant (Full)',
|
| 184 |
-
'base_model_id': 'coding_fallback.coding_fallback',
|
| 185 |
-
'meta': {
|
| 186 |
-
'description': 'Smart Coding Router sa svim filterima: web search, memory, token saver, context detector i više.',
|
| 187 |
-
'profile_image_url': '/static/favicon.png',
|
| 188 |
-
'tags': [{'name': 'custom'}, {'name': 'coding'}],
|
| 189 |
-
'capabilities': {
|
| 190 |
-
'vision': False,
|
| 191 |
-
'citations': True,
|
| 192 |
-
'usage': True,
|
| 193 |
-
}
|
| 194 |
-
},
|
| 195 |
-
'params': {
|
| 196 |
-
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
|
| 197 |
-
'temperature': 0.2,
|
| 198 |
-
'max_tokens': 4096,
|
| 199 |
-
},
|
| 200 |
-
'filter_ids': ALL_FILTER_IDS,
|
| 201 |
-
'tool_ids': ['smart_matcher'],
|
| 202 |
-
'action_ids': ['pdf_tools_rich_ui_editor'],
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
# Provjeri postoji li model
|
| 206 |
-
status, _ = api('GET', '/api/v1/models/model?id=nerdur_assistant')
|
| 207 |
-
if status == 200:
|
| 208 |
-
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_assistant', model_payload)
|
| 209 |
-
label = "ažuriran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 210 |
-
else:
|
| 211 |
-
s, r = api('POST', '/api/v1/models/create', model_payload)
|
| 212 |
-
label = "kreiran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 213 |
-
|
| 214 |
-
icon = "✅" if s == 200 else "❌"
|
| 215 |
-
print(f" {icon} Model '🧠 Nerdur Assistant (Full)' — {label}")
|
| 216 |
-
|
| 217 |
-
print("\n✅ Instalacija završena!")
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
# ─────────────────────────────────────────────
|
| 222 |
|
| 223 |
-
|
|
|
|
|
|
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
'capabilities': {
|
| 234 |
-
'vision': True,
|
| 235 |
-
'citations': True,
|
| 236 |
-
'usage': True,
|
| 237 |
-
}
|
| 238 |
},
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
|
|
|
|
|
|
| 243 |
},
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
if status == 200:
|
| 251 |
-
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_gemini_flash', gemini_payload)
|
| 252 |
-
label = "ažuriran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 253 |
-
else:
|
| 254 |
-
s, r = api('POST', '/api/v1/models/create', gemini_payload)
|
| 255 |
-
label = "kreiran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 256 |
-
|
| 257 |
-
icon = "✅" if s == 200 else "❌"
|
| 258 |
-
print(f" {icon} Model '⚡ Gemini 2.5 Flash (Coding)' — {label}")
|
| 259 |
-
|
| 260 |
-
print("\n✅ Svi modeli kreirani!")
|
| 261 |
-
|
| 262 |
-
# ─────────────────────────────────────────────
|
| 263 |
-
# 6. Groq preset
|
| 264 |
-
# ─────────────────────────────────────────────
|
| 265 |
-
|
| 266 |
-
print("\n🚀 Kreiram Groq preset...")
|
| 267 |
-
|
| 268 |
-
groq_payload = {
|
| 269 |
-
'id': 'nerdur_groq_coding',
|
| 270 |
-
'name': '🚀 Groq Llama 3.3 70B (Coding)',
|
| 271 |
-
'base_model_id': 'llama-3.3-70b-versatile',
|
| 272 |
-
'meta': {
|
| 273 |
-
'description': 'Kimi K2 na Groq — izuzetno brz, odličan za kodiranje, besplatan.',
|
| 274 |
-
'profile_image_url': '/static/favicon.png',
|
| 275 |
-
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'groq'}],
|
| 276 |
-
'capabilities': {'vision': False, 'citations': True, 'usage': True}
|
| 277 |
},
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
'action_ids': ['pdf_tools_rich_ui_editor'],
|
| 286 |
-
}
|
| 287 |
-
|
| 288 |
-
status, _ = api('GET', '/api/v1/models/model?id=nerdur_groq_coding')
|
| 289 |
-
if status == 200:
|
| 290 |
-
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_groq_coding', groq_payload)
|
| 291 |
-
label = "ažuriran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 292 |
-
else:
|
| 293 |
-
s, r = api('POST', '/api/v1/models/create', groq_payload)
|
| 294 |
-
label = "kreiran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 295 |
-
|
| 296 |
-
print(f" {'✅' if s == 200 else '❌'} '🚀 Groq Kimi K2 (Coding)' — {label}")
|
| 297 |
-
|
| 298 |
-
# ─────────────────────────────────────────────
|
| 299 |
-
# 7. Cerebras preset
|
| 300 |
-
# ─────────────────────────────────────────────
|
| 301 |
-
|
| 302 |
-
print("\n🧠 Kreiram Cerebras preset...")
|
| 303 |
-
|
| 304 |
-
cerebras_payload = {
|
| 305 |
-
'id': 'nerdur_cerebras_coding',
|
| 306 |
-
'name': '🧠 Cerebras Llama 4 Scout (Coding)',
|
| 307 |
-
'base_model_id': 'llama-4-scout-17b-16e-instruct',
|
| 308 |
-
'meta': {
|
| 309 |
-
'description': 'Llama 3.3 70B na Cerebras — jedan od najbržih inference engine-a, besplatan.',
|
| 310 |
-
'profile_image_url': '/static/favicon.png',
|
| 311 |
-
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'cerebras'}],
|
| 312 |
-
'capabilities': {'vision': False, 'citations': True, 'usage': True}
|
| 313 |
-
},
|
| 314 |
-
'params': {
|
| 315 |
-
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
|
| 316 |
-
'temperature': 0.2,
|
| 317 |
-
'max_tokens': 8192,
|
| 318 |
-
},
|
| 319 |
-
'filter_ids': ALL_FILTER_IDS,
|
| 320 |
-
'tool_ids': ['smart_matcher'],
|
| 321 |
-
'action_ids': ['pdf_tools_rich_ui_editor'],
|
| 322 |
-
}
|
| 323 |
-
|
| 324 |
-
status, _ = api('GET', '/api/v1/models/model?id=nerdur_cerebras_coding')
|
| 325 |
-
if status == 200:
|
| 326 |
-
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_cerebras_coding', cerebras_payload)
|
| 327 |
-
label = "ažuriran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 328 |
-
else:
|
| 329 |
-
s, r = api('POST', '/api/v1/models/create', cerebras_payload)
|
| 330 |
-
label = "kreiran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 331 |
-
|
| 332 |
-
print(f" {'✅' if s == 200 else '❌'} '🧠 Cerebras Llama 3.3 (Coding)' — {label}")
|
| 333 |
-
|
| 334 |
-
# ─────────────────────────────────────────────
|
| 335 |
-
# 8. SambaNova preset
|
| 336 |
-
# ─────────────────────────────────────────────
|
| 337 |
-
|
| 338 |
-
print("\n⚡ Kreiram SambaNova preset...")
|
| 339 |
-
|
| 340 |
-
sambanova_payload = {
|
| 341 |
-
'id': 'nerdur_sambanova_coding',
|
| 342 |
-
'name': '⚡ SambaNova Llama 3.3 (Coding)',
|
| 343 |
-
'base_model_id': 'Meta-Llama-3.3-70B-Instruct',
|
| 344 |
-
'meta': {
|
| 345 |
-
'description': 'Llama 3.3 70B na SambaNova — brz inference, dobar za kodiranje, besplatan.',
|
| 346 |
-
'profile_image_url': '/static/favicon.png',
|
| 347 |
-
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'sambanova'}],
|
| 348 |
-
'capabilities': {'vision': False, 'citations': True, 'usage': True}
|
| 349 |
-
},
|
| 350 |
-
'params': {
|
| 351 |
-
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
|
| 352 |
-
'temperature': 0.2,
|
| 353 |
-
'max_tokens': 8192,
|
| 354 |
-
},
|
| 355 |
-
'filter_ids': ALL_FILTER_IDS,
|
| 356 |
-
'tool_ids': ['smart_matcher'],
|
| 357 |
-
'action_ids': ['pdf_tools_rich_ui_editor'],
|
| 358 |
-
}
|
| 359 |
-
|
| 360 |
-
status, _ = api('GET', '/api/v1/models/model?id=nerdur_sambanova_coding')
|
| 361 |
-
if status == 200:
|
| 362 |
-
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_sambanova_coding', sambanova_payload)
|
| 363 |
-
label = "ažuriran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 364 |
-
else:
|
| 365 |
-
s, r = api('POST', '/api/v1/models/create', sambanova_payload)
|
| 366 |
-
label = "kreiran" if s == 200 else f"greška {s}: {str(r)[:100]}"
|
| 367 |
-
|
| 368 |
-
print(f" {'✅' if s == 200 else '❌'} '⚡ SambaNova Llama 3.3 (Coding)' — {label}")
|
| 369 |
-
|
| 370 |
-
print("\n🎉 Svih 5 preseta kreirano!")
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
# ─────────────────────────────────────────────
|
| 374 |
-
# 9. Dodatni presets za sve aktivne provajdere
|
| 375 |
-
# ─────────────────────────────────────────────
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
# Brišemo presete koji ne rade i duplikate
|
| 379 |
-
DELETE_IDS = [
|
| 380 |
-
'nerdur_claude', 'nerdur_gpt4o', 'nerdur_deepseek', 'nerdur_xai',
|
| 381 |
-
'nerdur_openrouter_free', 'nerdur_fireworks',
|
| 382 |
-
'nerdur_groq_coding', # brisemo stari groq da izbjegnemo duplikat
|
| 383 |
]
|
| 384 |
-
print("\n🗑️ Brišem presete koji ne rade i duplikate...")
|
| 385 |
-
for did in DELETE_IDS:
|
| 386 |
-
s, r = api('DELETE', f'/api/v1/models/model/delete?id={did}')
|
| 387 |
-
if s == 200:
|
| 388 |
-
print(f" 🗑️ {did} — obrisan")
|
| 389 |
-
else:
|
| 390 |
-
print(f" ⚠️ {did} — nije pronađen (OK)")
|
| 391 |
-
|
| 392 |
-
# Kreiraj Groq preset ponovo (čist, bez duplikata)
|
| 393 |
-
print("\n🚀 Kreiram Groq Llama preset (čist)...")
|
| 394 |
-
groq_clean = {
|
| 395 |
-
'id': 'nerdur_groq_llama',
|
| 396 |
-
'name': '🚀 Groq Llama 3.3 70B (Coding)',
|
| 397 |
-
'base_model_id': 'llama-3.3-70b-versatile',
|
| 398 |
-
'meta': {'description': 'Groq Llama 3.3 70B — brz i pouzdan za kodiranje.'},
|
| 399 |
-
'params': {'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '', 'temperature': 0.2, 'max_tokens': 8192},
|
| 400 |
-
'filter_ids': ALL_FILTER_IDS,
|
| 401 |
-
}
|
| 402 |
-
s, r = api('GET', '/api/v1/models/model?id=nerdur_groq_llama')
|
| 403 |
-
if s == 200:
|
| 404 |
-
api('POST', '/api/v1/models/model/update?id=nerdur_groq_llama', groq_clean)
|
| 405 |
-
print(" ✅ Groq Llama preset — ažuriran")
|
| 406 |
-
else:
|
| 407 |
-
api('POST', '/api/v1/models/create', groq_clean)
|
| 408 |
-
print(" ✅ Groq Llama preset — kreiran")
|
| 409 |
|
| 410 |
-
#
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
}
|
| 420 |
-
s, r = api('GET', '/api/v1/models/model?id=nerdur_mistral')
|
| 421 |
-
if s == 200:
|
| 422 |
-
api('POST', '/api/v1/models/model/update?id=nerdur_mistral', mistral_clean)
|
| 423 |
-
print(" ✅ Mistral preset — ažuriran")
|
| 424 |
-
else:
|
| 425 |
-
api('POST', '/api/v1/models/create', mistral_clean)
|
| 426 |
-
print(" ✅ Mistral preset — kreiran")
|
| 427 |
|
| 428 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import json
|
| 2 |
import urllib.request
|
| 3 |
import urllib.error
|
| 4 |
import sys
|
| 5 |
import os
|
| 6 |
|
| 7 |
+
# install_functions.py v3 — Podrška za Pipe funkcije i automatski ID
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
+
base_url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:8080'
|
| 10 |
+
token = sys.argv[2] if len(sys.argv) > 2 else ''
|
|
|
|
| 11 |
|
| 12 |
+
if not token:
|
| 13 |
+
print("❌ Nema tokena za instalaciju.")
|
| 14 |
+
sys.exit(1)
|
| 15 |
|
| 16 |
+
# Funkcije i Filteri
|
| 17 |
+
functions = [
|
| 18 |
+
{
|
| 19 |
+
"id": "context_detector",
|
| 20 |
+
"name": "Context Detector",
|
| 21 |
+
"type": "filter",
|
| 22 |
+
"content": open("/app/context_detector.py").read() if os.path.exists("/app/context_detector.py") else "",
|
| 23 |
+
"meta": {"description": "Automatski prepoznaje kontekst poruke."}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
},
|
| 25 |
+
{
|
| 26 |
+
"id": "token_saver",
|
| 27 |
+
"name": "Token Saver",
|
| 28 |
+
"type": "filter",
|
| 29 |
+
"content": open("/app/token_compressor.py").read() if os.path.exists("/app/token_compressor.py") else "",
|
| 30 |
+
"meta": {"description": "Štedi tokene rezanjem historije."}
|
| 31 |
},
|
| 32 |
+
{
|
| 33 |
+
"id": "coding_router",
|
| 34 |
+
"name": "Smart Coding Router",
|
| 35 |
+
"type": "pipe",
|
| 36 |
+
"content": open("/app/coding_priority_pipe.py").read() if os.path.exists("/app/coding_priority_pipe.py") else "",
|
| 37 |
+
"meta": {"description": "Fallback: Gemini -> Groq -> Cerebras -> Sambanova."}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
},
|
| 39 |
+
{
|
| 40 |
+
"id": "api_router",
|
| 41 |
+
"name": "API Fallback Router",
|
| 42 |
+
"type": "filter",
|
| 43 |
+
"content": open("/app/api_router.py").read() if os.path.exists("/app/api_router.py") else "",
|
| 44 |
+
"meta": {"description": "Prebacuje na rezervni API u slučaju greške."}
|
| 45 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
+
# Alati (Tools)
|
| 49 |
+
tools = [
|
| 50 |
+
{
|
| 51 |
+
"id": "smart_matcher",
|
| 52 |
+
"name": "Smart Matcher",
|
| 53 |
+
"content": open("/app/smart_matcher.py").read() if os.path.exists("/app/smart_matcher.py") else "",
|
| 54 |
+
"meta": {"description": "Sparuje stavke iz dvije liste."}
|
| 55 |
+
}
|
| 56 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
+
def install(items, endpoint_type):
|
| 59 |
+
for item in items:
|
| 60 |
+
if not item["content"]: continue
|
| 61 |
+
|
| 62 |
+
data = json.dumps(item).encode()
|
| 63 |
+
req = urllib.request.Request(
|
| 64 |
+
f"{base_url}/api/v1/{endpoint_type}/create",
|
| 65 |
+
data=data,
|
| 66 |
+
headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'},
|
| 67 |
+
method='POST'
|
| 68 |
+
)
|
| 69 |
+
try:
|
| 70 |
+
with urllib.request.urlopen(req) as r:
|
| 71 |
+
print(f"✅ {item['name']} ({endpoint_type})")
|
| 72 |
+
except urllib.error.HTTPError as e:
|
| 73 |
+
body = e.read().decode()
|
| 74 |
+
if 'already exists' in body.lower() or e.code == 409:
|
| 75 |
+
# Pokušaj update ako već postoji
|
| 76 |
+
print(f"⚠️ {item['name']} već postoji, pokušavam update...")
|
| 77 |
+
else:
|
| 78 |
+
print(f"❌ {item['name']} — greška {e.code}: {body[:50]}")
|
| 79 |
+
|
| 80 |
+
print("Instaliram funkcije (Filters/Pipes)...")
|
| 81 |
+
install(functions, "functions")
|
| 82 |
+
print("Instaliram tools...")
|
| 83 |
+
install(tools, "tools")
|
| 84 |
+
print("Gotovo!")
|
setup_endpoints.sh
CHANGED
|
@@ -116,40 +116,3 @@ except Exception as e:
|
|
| 116 |
PYEOF
|
| 117 |
|
| 118 |
echo "✅ Gotovo!"
|
| 119 |
-
|
| 120 |
-
# Banner sa linkom na Preset Creator
|
| 121 |
-
python3 - <<INNEREOF
|
| 122 |
-
import requests, json, os
|
| 123 |
-
|
| 124 |
-
base_url = "$BASE_URL"
|
| 125 |
-
token = "$TOKEN"
|
| 126 |
-
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
| 127 |
-
|
| 128 |
-
banner = {
|
| 129 |
-
"banners": [
|
| 130 |
-
{
|
| 131 |
-
"id": "preset-creator",
|
| 132 |
-
"type": "info",
|
| 133 |
-
"title": "⚙️ Preset Creator — kreiraj i upravljaj modelima",
|
| 134 |
-
"content": "Otvori Preset Creator na: /static/preset_creator.html",
|
| 135 |
-
"url": "/static/preset_creator.html",
|
| 136 |
-
"dismissible": True,
|
| 137 |
-
"timestamp": 1
|
| 138 |
-
}
|
| 139 |
-
]
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
try:
|
| 143 |
-
r = requests.post(
|
| 144 |
-
f"{base_url}/api/v1/configs/banners",
|
| 145 |
-
headers=headers,
|
| 146 |
-
json=banner["banners"],
|
| 147 |
-
timeout=10
|
| 148 |
-
)
|
| 149 |
-
if r.status_code == 200:
|
| 150 |
-
print("✅ Banner dodan — Preset Creator dostupan u WebUI")
|
| 151 |
-
else:
|
| 152 |
-
print(f"⚠️ Banner greška: {r.status_code}")
|
| 153 |
-
except Exception as e:
|
| 154 |
-
print(f"⚠️ Banner greška: {e}")
|
| 155 |
-
INNEREOF
|
|
|
|
| 116 |
PYEOF
|
| 117 |
|
| 118 |
echo "✅ Gotovo!"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|