Nerdur commited on
Commit
22303f5
·
verified ·
1 Parent(s): c1d6332

Upload 22 files

Browse files
Files changed (3) hide show
  1. Dockerfile +17 -11
  2. install_functions.py +69 -413
  3. 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 install_functions.py /app/install_functions.py
26
- COPY preset_creator.html /app/backend/static/preset_creator.html
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- BASE_URL = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:8080'
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
- # 5. Kreiraj Gemini 2.5 Flash Preset
221
- # ─────────────────────────────────────────────
222
 
223
- print("\n⚡ Kreiram Gemini 2.5 Flash Preset...")
 
 
224
 
225
- gemini_payload = {
226
- 'id': 'nerdur_gemini_flash',
227
- 'name': '⚡ Gemini 2.5 Flash (Coding)',
228
- 'base_model_id': 'models/gemini-2.5-flash',
229
- 'meta': {
230
- 'description': 'Gemini 2.5 Flash sa svim filterima — web search, memory, token saver i više.',
231
- 'profile_image_url': '/static/favicon.png',
232
- 'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'gemini'}],
233
- 'capabilities': {
234
- 'vision': True,
235
- 'citations': True,
236
- 'usage': True,
237
- }
238
  },
239
- 'params': {
240
- 'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
241
- 'temperature': 0.2,
242
- 'max_tokens': 8192,
 
 
243
  },
244
- 'filter_ids': ALL_FILTER_IDS,
245
- 'tool_ids': ['smart_matcher'],
246
- 'action_ids': ['pdf_tools_rich_ui_editor'],
247
- }
248
-
249
- status, _ = api('GET', '/api/v1/models/model?id=nerdur_gemini_flash')
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
- 'params': {
279
- 'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
280
- 'temperature': 0.2,
281
- 'max_tokens': 8192,
282
- },
283
- 'filter_ids': ALL_FILTER_IDS,
284
- 'tool_ids': ['smart_matcher'],
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
- # Kreiraj Mistral preset
411
- print("\n🔵 Kreiram Mistral preset...")
412
- mistral_clean = {
413
- 'id': 'nerdur_mistral',
414
- 'name': '🔵 Mistral Large (Coding)',
415
- 'base_model_id': 'mistral-large-latest',
416
- 'meta': {'description': 'Mistral Large — europski model, odličan za kodiranje.'},
417
- 'params': {'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '', 'temperature': 0.2, 'max_tokens': 8192},
418
- 'filter_ids': ALL_FILTER_IDS,
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
- print("\n🎉 Instalacija kompletna!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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!"