webui / install_functions.py
Nerdur's picture
Revert na commit 3e0cd7f2
5e3277c verified
Raw
History Blame Contribute Delete
17.3 kB
"""
Instalira sve funkcije (filters, tools, actions) i kreira Custom Model Preset.
Poziva se automatski iz setup_endpoints.sh pri startu Space-a.
Koristi: python3 install_functions.py <base_url> <token>
"""
import json
import urllib.request
import urllib.error
import sys
import os
BASE_URL = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:8080'
TOKEN = sys.argv[2] if len(sys.argv) > 2 else ''
if not TOKEN:
print("❌ No token provided.")
sys.exit(1)
HEADERS = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {TOKEN}'
}
APP_DIR = os.path.dirname(os.path.abspath(__file__))
# ─────────────────────────────────────────────
# Helpers
# ─────────────────────────────────────────────
def api(method, path, data=None):
url = BASE_URL + path
body = json.dumps(data).encode() if data is not None else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
with urllib.request.urlopen(req) as r:
return r.status, json.loads(r.read().decode())
except urllib.error.HTTPError as e:
return e.code, e.read().decode()
def install_function(func_id, name, func_type, content):
"""Instaliraj ili aΕΎuriraj funkciju."""
# Provjeri postoji li
status, _ = api('GET', f'/api/v1/functions/id/{func_id}')
payload = {
'id': func_id,
'name': name,
'type': func_type,
'content': content,
'meta': {'description': name}
}
if status == 200:
s, r = api('POST', f'/api/v1/functions/id/{func_id}/update', payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}"
else:
s, r = api('POST', '/api/v1/functions/create', payload)
label = "instaliran" if s == 200 else f"greΕ‘ka {s}"
# Aktiviraj
api('POST', f'/api/v1/functions/id/{func_id}/toggle')
icon = "βœ…" if s == 200 else "❌"
print(f" {icon} [{func_type}] {name} β€” {label}")
return s == 200
def load_json_function(filepath):
"""Učitaj funkciju iz JSON export fajla."""
with open(filepath) as f:
d = json.load(f)
item = d[0] if isinstance(d, list) else d
# Detektuj tip iz sadrΕΎaja
content = item.get('content', '')
if 'class Filter' in content:
ftype = 'filter'
elif 'class Pipe' in content:
ftype = 'pipe'
elif 'class Tools' in content or 'class Action' in content:
ftype = 'action'
else:
ftype = item.get('meta', {}).get('type', 'filter')
return item['id'], item['name'], ftype, content
# ─────────────────────────────────────────────
# 1. Instaliraj sve JSON funkcije
# ─────────────────────────────────────────────
print("\nπŸ“¦ Instaliram funkcije iz JSON fajlova...")
JSON_FILES = [
'global_system_prompt_filter.json',
'__easysearch_v0_4_3__high-performance_web_search_filter.json',
'token_saver.json',
'context_clip_filter.json',
'auto_disable_native_tools.json',
'auto_memory.json',
'__mermaid_doctor_-_heals_broken_mermaid_diagrams_generated_by_small_or_hallucinating_models.json',
'github_simple.json',
'pdf_tools_-_rich_ui_for_in_context_basic_editing_.json',
]
installed_filter_ids = []
for fname in JSON_FILES:
fpath = os.path.join(APP_DIR, fname)
if not os.path.exists(fpath):
print(f" ⚠️ {fname} nije pronaΔ‘en, preskačem")
continue
func_id, name, ftype, content = load_json_function(fpath)
ok = install_function(func_id, name, ftype, content)
if ok and ftype == 'filter':
installed_filter_ids.append(func_id)
# ─────────────────────────────────────────────
# 2. Instaliraj naΕ‘e custom Python funkcije
# ─────────────────────────────────────────────
print("\nπŸ› οΈ Instaliram custom funkcije...")
CUSTOM_FUNCTIONS = [
('context_detector', 'Context Detector', 'filter', 'context_detector.py'),
('token_compressor', 'Token Compressor', 'filter', 'token_compressor.py'),
('coding_fallback', 'πŸ”€ Smart Coding Router', 'pipe', 'coding_priority_pipe.py'),
('smart_matcher', 'Smart Matcher', 'tool', 'smart_matcher.py'),
]
for func_id, name, ftype, pyfile in CUSTOM_FUNCTIONS:
fpath = os.path.join(APP_DIR, pyfile)
if not os.path.exists(fpath):
print(f" ⚠️ {pyfile} nije pronaΔ‘en")
continue
content = open(fpath).read()
ok = install_function(func_id, name, ftype, content)
if ok and ftype == 'filter':
installed_filter_ids.append(func_id)
# ─────────────────────────────────────────────
# 3. Postavi Global System Prompt
# ─────────────────────────────────────────────
print("\nπŸ“ Postavljam Global System Prompt...")
SYSTEM_PROMPT_FILE = os.path.join(APP_DIR, 'system_prompt.txt')
if os.path.exists(SYSTEM_PROMPT_FILE):
system_prompt = open(SYSTEM_PROMPT_FILE).read()
# Update valve za global_system_prompt_filter
valve_payload = {
'system_message': system_prompt,
'timezone': 'Europe/Sarajevo',
'skip_tags': []
}
s, r = api('POST', '/api/v1/functions/id/global_system_prompt_filter/valves/update', valve_payload)
if s == 200:
print(" βœ… System prompt postavljen")
else:
print(f" ⚠️ Greőka pri postavljanju system prompta: {s}")
else:
print(" ⚠️ system_prompt.txt nije pronaΔ‘en")
# ─────────────────────────────────────────────
# 4. Kreiraj Custom Model Preset
# ─────────────────────────────────────────────
print("\nπŸ€– Kreiram Custom Model Preset...")
# Sve filter ID-ove koji treba biti aktivni na modelu
ALL_FILTER_IDS = list(dict.fromkeys([
'global_system_prompt_filter',
'easysearch',
'token_saver',
'context_clip_filter',
'auto_disable_native_tools',
'auto_memory',
'context_detector',
'token_compressor',
'mermaid_doctor',
] + installed_filter_ids))
model_payload = {
'id': 'nerdur_assistant',
'name': '🧠 Nerdur Assistant (Full)',
'base_model_id': 'coding_fallback.coding_fallback',
'meta': {
'description': 'Smart Coding Router sa svim filterima: web search, memory, token saver, context detector i viΕ‘e.',
'profile_image_url': '/static/favicon.png',
'tags': [{'name': 'custom'}, {'name': 'coding'}],
'capabilities': {
'vision': False,
'citations': True,
'usage': True,
}
},
'params': {
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
'temperature': 0.2,
'max_tokens': 4096,
},
'filter_ids': ALL_FILTER_IDS,
'tool_ids': ['smart_matcher'],
'action_ids': ['pdf_tools_rich_ui_editor'],
}
# Provjeri postoji li model
status, _ = api('GET', '/api/v1/models/model?id=nerdur_assistant')
if status == 200:
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_assistant', model_payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
else:
s, r = api('POST', '/api/v1/models/create', model_payload)
label = "kreiran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
icon = "βœ…" if s == 200 else "❌"
print(f" {icon} Model '🧠 Nerdur Assistant (Full)' β€” {label}")
print("\nβœ… Instalacija zavrΕ‘ena!")
# ─────────────────────────────────────────────
# 5. Kreiraj Gemini 2.5 Flash Preset
# ─────────────────────────────────────────────
print("\n⚑ Kreiram Gemini 2.5 Flash Preset...")
gemini_payload = {
'id': 'nerdur_gemini_flash',
'name': '⚑ Gemini 2.5 Flash (Coding)',
'base_model_id': 'models/gemini-2.5-flash',
'meta': {
'description': 'Gemini 2.5 Flash sa svim filterima β€” web search, memory, token saver i viΕ‘e.',
'profile_image_url': '/static/favicon.png',
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'gemini'}],
'capabilities': {
'vision': True,
'citations': True,
'usage': True,
}
},
'params': {
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
'temperature': 0.2,
'max_tokens': 8192,
},
'filter_ids': ALL_FILTER_IDS,
'tool_ids': ['smart_matcher'],
'action_ids': ['pdf_tools_rich_ui_editor'],
}
status, _ = api('GET', '/api/v1/models/model?id=nerdur_gemini_flash')
if status == 200:
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_gemini_flash', gemini_payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
else:
s, r = api('POST', '/api/v1/models/create', gemini_payload)
label = "kreiran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
icon = "βœ…" if s == 200 else "❌"
print(f" {icon} Model '⚑ Gemini 2.5 Flash (Coding)' β€” {label}")
print("\nβœ… Svi modeli kreirani!")
# ─────────────────────────────────────────────
# 6. Groq preset
# ─────────────────────────────────────────────
print("\nπŸš€ Kreiram Groq preset...")
groq_payload = {
'id': 'nerdur_groq_coding',
'name': 'πŸš€ Groq Llama 3.3 70B (Coding)',
'base_model_id': 'llama-3.3-70b-versatile',
'meta': {
'description': 'Kimi K2 na Groq β€” izuzetno brz, odličan za kodiranje, besplatan.',
'profile_image_url': '/static/favicon.png',
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'groq'}],
'capabilities': {'vision': False, 'citations': True, 'usage': True}
},
'params': {
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
'temperature': 0.2,
'max_tokens': 8192,
},
'filter_ids': ALL_FILTER_IDS,
'tool_ids': ['smart_matcher'],
'action_ids': ['pdf_tools_rich_ui_editor'],
}
status, _ = api('GET', '/api/v1/models/model?id=nerdur_groq_coding')
if status == 200:
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_groq_coding', groq_payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
else:
s, r = api('POST', '/api/v1/models/create', groq_payload)
label = "kreiran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
print(f" {'βœ…' if s == 200 else '❌'} 'πŸš€ Groq Kimi K2 (Coding)' β€” {label}")
# ─────────────────────────────────────────────
# 7. Cerebras preset
# ─────────────────────────────────────────────
print("\n🧠 Kreiram Cerebras preset...")
cerebras_payload = {
'id': 'nerdur_cerebras_coding',
'name': '🧠 Cerebras Llama 4 Scout (Coding)',
'base_model_id': 'llama-4-scout-17b-16e-instruct',
'meta': {
'description': 'Llama 3.3 70B na Cerebras β€” jedan od najbrΕΎih inference engine-a, besplatan.',
'profile_image_url': '/static/favicon.png',
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'cerebras'}],
'capabilities': {'vision': False, 'citations': True, 'usage': True}
},
'params': {
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
'temperature': 0.2,
'max_tokens': 8192,
},
'filter_ids': ALL_FILTER_IDS,
'tool_ids': ['smart_matcher'],
'action_ids': ['pdf_tools_rich_ui_editor'],
}
status, _ = api('GET', '/api/v1/models/model?id=nerdur_cerebras_coding')
if status == 200:
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_cerebras_coding', cerebras_payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
else:
s, r = api('POST', '/api/v1/models/create', cerebras_payload)
label = "kreiran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
print(f" {'βœ…' if s == 200 else '❌'} '🧠 Cerebras Llama 3.3 (Coding)' β€” {label}")
# ─────────────────────────────────────────────
# 8. SambaNova preset
# ─────────────────────────────────────────────
print("\n⚑ Kreiram SambaNova preset...")
sambanova_payload = {
'id': 'nerdur_sambanova_coding',
'name': '⚑ SambaNova Llama 3.3 (Coding)',
'base_model_id': 'Meta-Llama-3.3-70B-Instruct',
'meta': {
'description': 'Llama 3.3 70B na SambaNova β€” brz inference, dobar za kodiranje, besplatan.',
'profile_image_url': '/static/favicon.png',
'tags': [{'name': 'custom'}, {'name': 'coding'}, {'name': 'sambanova'}],
'capabilities': {'vision': False, 'citations': True, 'usage': True}
},
'params': {
'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '',
'temperature': 0.2,
'max_tokens': 8192,
},
'filter_ids': ALL_FILTER_IDS,
'tool_ids': ['smart_matcher'],
'action_ids': ['pdf_tools_rich_ui_editor'],
}
status, _ = api('GET', '/api/v1/models/model?id=nerdur_sambanova_coding')
if status == 200:
s, r = api('POST', '/api/v1/models/model/update?id=nerdur_sambanova_coding', sambanova_payload)
label = "aΕΎuriran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
else:
s, r = api('POST', '/api/v1/models/create', sambanova_payload)
label = "kreiran" if s == 200 else f"greΕ‘ka {s}: {str(r)[:100]}"
print(f" {'βœ…' if s == 200 else '❌'} '⚑ SambaNova Llama 3.3 (Coding)' β€” {label}")
print("\nπŸŽ‰ Svih 5 preseta kreirano!")
# ─────────────────────────────────────────────
# 9. Dodatni presets za sve aktivne provajdere
# ─────────────────────────────────────────────
# BriΕ‘emo presete koji ne rade i duplikate
DELETE_IDS = [
'nerdur_claude', 'nerdur_gpt4o', 'nerdur_deepseek', 'nerdur_xai',
'nerdur_openrouter_free', 'nerdur_fireworks',
'nerdur_groq_coding', # brisemo stari groq da izbjegnemo duplikat
]
print("\nπŸ—‘οΈ BriΕ‘em presete koji ne rade i duplikate...")
for did in DELETE_IDS:
s, r = api('DELETE', f'/api/v1/models/model/delete?id={did}')
if s == 200:
print(f" πŸ—‘οΈ {did} β€” obrisan")
else:
print(f" ⚠️ {did} β€” nije pronaΔ‘en (OK)")
# Kreiraj Groq preset ponovo (čist, bez duplikata)
print("\nπŸš€ Kreiram Groq Llama preset (čist)...")
groq_clean = {
'id': 'nerdur_groq_llama',
'name': 'πŸš€ Groq Llama 3.3 70B (Coding)',
'base_model_id': 'llama-3.3-70b-versatile',
'meta': {'description': 'Groq Llama 3.3 70B β€” brz i pouzdan za kodiranje.'},
'params': {'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '', 'temperature': 0.2, 'max_tokens': 8192},
'filter_ids': ALL_FILTER_IDS,
}
s, r = api('GET', '/api/v1/models/model?id=nerdur_groq_llama')
if s == 200:
api('POST', '/api/v1/models/model/update?id=nerdur_groq_llama', groq_clean)
print(" βœ… Groq Llama preset β€” aΕΎuriran")
else:
api('POST', '/api/v1/models/create', groq_clean)
print(" βœ… Groq Llama preset β€” kreiran")
# Kreiraj Mistral preset
print("\nπŸ”΅ Kreiram Mistral preset...")
mistral_clean = {
'id': 'nerdur_mistral',
'name': 'πŸ”΅ Mistral Large (Coding)',
'base_model_id': 'mistral-large-latest',
'meta': {'description': 'Mistral Large β€” europski model, odličan za kodiranje.'},
'params': {'system': open(SYSTEM_PROMPT_FILE).read() if os.path.exists(SYSTEM_PROMPT_FILE) else '', 'temperature': 0.2, 'max_tokens': 8192},
'filter_ids': ALL_FILTER_IDS,
}
s, r = api('GET', '/api/v1/models/model?id=nerdur_mistral')
if s == 200:
api('POST', '/api/v1/models/model/update?id=nerdur_mistral', mistral_clean)
print(" βœ… Mistral preset β€” aΕΎuriran")
else:
api('POST', '/api/v1/models/create', mistral_clean)
print(" βœ… Mistral preset β€” kreiran")
print("\nπŸŽ‰ Instalacija kompletna!")