nativelab 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nativelab/GlobalConfig/__init__.py +0 -0
- nativelab/GlobalConfig/binaryResolve.py +34 -0
- nativelab/GlobalConfig/config.py +94 -0
- nativelab/GlobalConfig/config_global.py +4 -0
- nativelab/GlobalConfig/const.py +191 -0
- nativelab/GlobalConfig/hardwareUtil.py +38 -0
- nativelab/Model/APImodels.py +69 -0
- nativelab/Model/ModelRegistry.py +159 -0
- nativelab/Model/__init__.py +0 -0
- nativelab/Model/model_family.py +107 -0
- nativelab/Model/model_global.py +4 -0
- nativelab/Model/templates.py +326 -0
- nativelab/Prefrences/ParallelLoading.py +30 -0
- nativelab/Prefrences/__init__.py +0 -0
- nativelab/Prefrences/prefrence_global.py +1 -0
- nativelab/Server/ServerHandling.py +287 -0
- nativelab/Server/__init__.py +0 -0
- nativelab/Server/hfdwld.py +184 -0
- nativelab/Server/server_global.py +2 -0
- nativelab/UI/Qt6widgets/__init__.py +0 -0
- nativelab/UI/Qt6widgets/chatarea.py +142 -0
- nativelab/UI/Qt6widgets/chatmodule.py +139 -0
- nativelab/UI/Qt6widgets/inputbar.py +175 -0
- nativelab/UI/Qt6widgets/messagewidget.py +194 -0
- nativelab/UI/Qt6widgets/refrencepanels.py +552 -0
- nativelab/UI/Qt6widgets/sessionsidebar.py +141 -0
- nativelab/UI/Qt6widgets/thinkingblock.py +79 -0
- nativelab/UI/RichTextEditor.py +49 -0
- nativelab/UI/UI_const.py +62 -0
- nativelab/UI/UI_global.py +7 -0
- nativelab/UI/__init__.py +0 -0
- nativelab/UI/buildUI.py +677 -0
- nativelab/UI/effects.py +45 -0
- nativelab/UI/md_to_html.py +198 -0
- nativelab/UI/tabs.py +2223 -0
- nativelab/UI/widgets.py +7 -0
- nativelab/codeparser/__init__.py +0 -0
- nativelab/codeparser/codeparser_global.py +2 -0
- nativelab/codeparser/parser/__init__.py +0 -0
- nativelab/codeparser/parser/parsefinal.py +100 -0
- nativelab/codeparser/parser/typeparser.py +41 -0
- nativelab/codeparser/refrenceengine.py +308 -0
- nativelab/codeparser/scriptparser.py +517 -0
- nativelab/components/__init__.py +0 -0
- nativelab/components/components_global.py +4 -0
- nativelab/components/jobhandler.py +32 -0
- nativelab/components/multipdf_summarise.py +290 -0
- nativelab/components/pdfsummarise.py +227 -0
- nativelab/components/reason_code_pipeline.py +292 -0
- nativelab/core/__init__.py +0 -0
- nativelab/core/engine_global.py +2 -0
- nativelab/core/engines/__init__.py +0 -0
- nativelab/core/engines/apiengine.py +98 -0
- nativelab/core/engines/llamaengine.py +254 -0
- nativelab/core/streamer_global.py +3 -0
- nativelab/core/streamerworker/__init__.py +0 -0
- nativelab/core/streamerworker/apistreamer.py +114 -0
- nativelab/core/streamerworker/clistreamer.py +40 -0
- nativelab/core/streamerworker/serverstreamer.py +97 -0
- nativelab/icon.ico +0 -0
- nativelab/icon.png +0 -0
- nativelab/imports/__init__.py +0 -0
- nativelab/imports/import_global.py +6 -0
- nativelab/imports/optional_lib.py +15 -0
- nativelab/imports/pyqt_lib.py +13 -0
- nativelab/imports/standard_lib.py +9 -0
- nativelab/main.py +2724 -0
- nativelab/manual.py +411 -0
- nativelab/pipelinebuilder/__init__.py +0 -0
- nativelab/pipelinebuilder/blck_typ.py +40 -0
- nativelab/pipelinebuilder/canvas.py +912 -0
- nativelab/pipelinebuilder/editordialogue.py +509 -0
- nativelab/pipelinebuilder/executionWorker.py +932 -0
- nativelab/pipelinebuilder/outrender.py +138 -0
- nativelab/pipelinebuilder/pipblck.py +54 -0
- nativelab/pipelinebuilder/pipe_global.py +8 -0
- nativelab/pipelinebuilder/pipebuilder.py +808 -0
- nativelab/pipelinebuilder/pipefunctions.py +75 -0
- nativelab-0.1.0.dist-info/METADATA +849 -0
- nativelab-0.1.0.dist-info/RECORD +84 -0
- nativelab-0.1.0.dist-info/WHEEL +5 -0
- nativelab-0.1.0.dist-info/entry_points.txt +2 -0
- nativelab-0.1.0.dist-info/licenses/LICENSE +661 -0
- nativelab-0.1.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from nativelab.imports.import_global import Path, json, Dict
|
|
2
|
+
from .config import LLAMA_CLI_DEFAULT, LLAMA_SERVER_DEFAULT
|
|
3
|
+
from .const import APP_CONFIG_DEFAULTS, APP_CONFIG_FILE
|
|
4
|
+
def refresh_binary_paths():
|
|
5
|
+
"""Re-read SERVER_CONFIG and update module-level LLAMA_CLI / LLAMA_SERVER."""
|
|
6
|
+
from nativelab.Server.server_global import SERVER_CONFIG # local import
|
|
7
|
+
|
|
8
|
+
global LLAMA_CLI, LLAMA_SERVER
|
|
9
|
+
LLAMA_CLI = _resolve_binary(SERVER_CONFIG.cli_path, LLAMA_CLI_DEFAULT)
|
|
10
|
+
LLAMA_SERVER = _resolve_binary(SERVER_CONFIG.server_path, LLAMA_SERVER_DEFAULT)
|
|
11
|
+
MODELS_DIR = Path("./localllm")
|
|
12
|
+
SESSIONS_DIR = Path("./sessions")
|
|
13
|
+
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
14
|
+
|
|
15
|
+
def _load_app_config() -> Dict:
|
|
16
|
+
cfg = dict(APP_CONFIG_DEFAULTS)
|
|
17
|
+
if APP_CONFIG_FILE.exists():
|
|
18
|
+
try:
|
|
19
|
+
saved = json.loads(APP_CONFIG_FILE.read_text())
|
|
20
|
+
cfg.update({k: v for k, v in saved.items() if k in cfg})
|
|
21
|
+
except Exception:
|
|
22
|
+
pass
|
|
23
|
+
return cfg
|
|
24
|
+
|
|
25
|
+
def save_app_config(cfg: Dict):
|
|
26
|
+
APP_CONFIG_FILE.write_text(json.dumps(cfg, indent=2))
|
|
27
|
+
|
|
28
|
+
APP_CONFIG = _load_app_config()
|
|
29
|
+
|
|
30
|
+
def _resolve_binary(cfg_path: str, fallback: str) -> str:
|
|
31
|
+
"""Return cfg_path if set and exists, else fallback."""
|
|
32
|
+
if cfg_path and Path(cfg_path).exists():
|
|
33
|
+
return cfg_path
|
|
34
|
+
return fallback
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from nativelab.imports.import_global import Path, _sys, re, os
|
|
2
|
+
_BASE = Path(getattr(_sys, "_MEIPASS", Path(".")))
|
|
3
|
+
_EXT = ".exe" if __import__("platform").system() == "Windows" else ""
|
|
4
|
+
|
|
5
|
+
LLAMA_CLI_DEFAULT = str(_BASE / f"llama-bin/llama-cli{_EXT}")
|
|
6
|
+
LLAMA_SERVER_DEFAULT = str(_BASE / f"llama-bin/llama-server{_EXT}")
|
|
7
|
+
|
|
8
|
+
# Fallback to local llama/bin for dev mode
|
|
9
|
+
if not Path(LLAMA_CLI_DEFAULT).exists():
|
|
10
|
+
LLAMA_CLI_DEFAULT = f"./llama/bin/llama-cli{_EXT}"
|
|
11
|
+
LLAMA_SERVER_DEFAULT = f"./llama/bin/llama-server{_EXT}"
|
|
12
|
+
|
|
13
|
+
# These are resolved at runtime via SERVER_CONFIG (set after ServerConfig loads
|
|
14
|
+
LLAMA_CLI = LLAMA_CLI_DEFAULT
|
|
15
|
+
LLAMA_SERVER = LLAMA_SERVER_DEFAULT
|
|
16
|
+
|
|
17
|
+
DEFAULT_MODEL = "./localllm/mistral-7b-instruct-v0.2.Q5_K_M.gguf"
|
|
18
|
+
def DEFAULT_CTX() -> int:
|
|
19
|
+
return 2048
|
|
20
|
+
|
|
21
|
+
def DEFAULT_THREADS() -> int:
|
|
22
|
+
return os.cpu_count() or 4
|
|
23
|
+
DEFAULT_N_PRED = 512
|
|
24
|
+
CUSTOM_MODELS_FILE = Path("./localllm/custom_models.json")
|
|
25
|
+
MODEL_CONFIGS_FILE = Path("./localllm/model_configs.json")
|
|
26
|
+
PARALLEL_PREFS_FILE = Path("./localllm/parallel_prefs.json")
|
|
27
|
+
SERVER_CONFIG_FILE = Path("./localllm/server_config.json")
|
|
28
|
+
API_MODELS_FILE = Path("./localllm/api_models.json")
|
|
29
|
+
|
|
30
|
+
# ── model roles ───────────────────────────────────────────────────────────────
|
|
31
|
+
MODEL_ROLES = ["general", "reasoning", "summarization", "coding", "secondary"]
|
|
32
|
+
ROLE_ICONS = {
|
|
33
|
+
"general": "💬",
|
|
34
|
+
"reasoning": "🧠",
|
|
35
|
+
"summarization": "📄",
|
|
36
|
+
"coding": "💻",
|
|
37
|
+
"secondary": "🔀",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# ═════════════════════════════ MODEL FAMILY DETECTION ═══════════════════════
|
|
41
|
+
|
|
42
|
+
# All GGUF quantization formats supported by llama.cpp
|
|
43
|
+
GGUF_QUANT_PATTERNS = [
|
|
44
|
+
# imatrix importance quants
|
|
45
|
+
r'IQ1_S', r'IQ1_M', r'IQ2_XXS', r'IQ2_XS', r'IQ2_S', r'IQ2_M',
|
|
46
|
+
r'IQ3_XXS', r'IQ3_XS', r'IQ3_S', r'IQ3_M', r'IQ4_XS', r'IQ4_NL',
|
|
47
|
+
# K-quants
|
|
48
|
+
r'Q2_K(?:_S)?', r'Q3_K_(?:S|M|L)', r'Q3_K',
|
|
49
|
+
r'Q4_K_(?:S|M)', r'Q4_K',
|
|
50
|
+
r'Q5_K_(?:S|M)', r'Q5_K',
|
|
51
|
+
r'Q6_K',
|
|
52
|
+
# legacy quants
|
|
53
|
+
r'Q4_0', r'Q4_1', r'Q5_0', r'Q5_1', r'Q8_0',
|
|
54
|
+
# float
|
|
55
|
+
r'F16', r'F32', r'BF16',
|
|
56
|
+
# GGML legacy
|
|
57
|
+
r'Q4_0_4_4', r'Q4_0_4_8', r'Q4_0_8_8',
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
QUANT_REGEX = re.compile(
|
|
61
|
+
r'\.(' + '|'.join(GGUF_QUANT_PATTERNS) + r')\.gguf$',
|
|
62
|
+
re.IGNORECASE
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Dynamic accessors (use these everywhere instead of bare constants)
|
|
66
|
+
def RAM_WATCHDOG_MB() -> float:
|
|
67
|
+
from .binaryResolve import APP_CONFIG
|
|
68
|
+
return float(APP_CONFIG["ram_watchdog_mb"])
|
|
69
|
+
|
|
70
|
+
def CHUNK_INDEX_SIZE() -> int:
|
|
71
|
+
from .binaryResolve import APP_CONFIG
|
|
72
|
+
return int(APP_CONFIG["chunk_index_size"])
|
|
73
|
+
|
|
74
|
+
def MAX_RAM_CHUNKS() -> int:
|
|
75
|
+
from .binaryResolve import APP_CONFIG
|
|
76
|
+
return int(APP_CONFIG["max_ram_chunks"])
|
|
77
|
+
|
|
78
|
+
def get_default_threads() -> int:
|
|
79
|
+
from .binaryResolve import APP_CONFIG
|
|
80
|
+
return int(APP_CONFIG["default_threads"])
|
|
81
|
+
|
|
82
|
+
def get_default_ctx() -> int:
|
|
83
|
+
from .binaryResolve import APP_CONFIG
|
|
84
|
+
return int(APP_CONFIG["default_ctx"])
|
|
85
|
+
|
|
86
|
+
def get_default_n_pred() -> int:
|
|
87
|
+
from .binaryResolve import APP_CONFIG
|
|
88
|
+
return int(APP_CONFIG["default_n_predict"])
|
|
89
|
+
from nativelab.Model.model_global import SCRIPT_LANGUAGES
|
|
90
|
+
SCRIPT_EXTENSIONS_FILTER = (
|
|
91
|
+
"Source files ("
|
|
92
|
+
+ " ".join(f"*{ext}" for ext in SCRIPT_LANGUAGES.keys())
|
|
93
|
+
+ ");;All Files (*)"
|
|
94
|
+
)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from nativelab.imports.import_global import _sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from .hardwareUtil import cpu_count
|
|
4
|
+
_sys.path.append(str(Path(__file__).resolve().parents[1]))
|
|
5
|
+
# ── Reference system constants ────────────────────────────────────────────────
|
|
6
|
+
REFS_DIR = Path("chat_refs")
|
|
7
|
+
REF_CACHE_DIR = Path("ref_cache")
|
|
8
|
+
REF_INDEX_DIR = Path("ref_index")
|
|
9
|
+
PAUSED_JOBS_DIR = Path("paused_jobs")
|
|
10
|
+
APP_CONFIG_FILE = Path("app_config.json")
|
|
11
|
+
REFS_DIR.mkdir(parents=True, exist_ok=True)
|
|
12
|
+
REF_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
13
|
+
REF_INDEX_DIR.mkdir(parents=True, exist_ok=True)
|
|
14
|
+
PAUSED_JOBS_DIR.mkdir(parents=True, exist_ok=True)
|
|
15
|
+
PIPELINES_DIR = Path.home() / ".native_lab" / "pipelines"
|
|
16
|
+
PIPELINES_DIR.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
APP_CONFIG_DEFAULTS = {
|
|
18
|
+
"ram_watchdog_mb": 800,
|
|
19
|
+
"chunk_index_size": 400,
|
|
20
|
+
"max_ram_chunks": 120,
|
|
21
|
+
"summary_chunk_chars": 3000,
|
|
22
|
+
"summary_ctx_carry": 600,
|
|
23
|
+
"summary_n_pred_sect": 380,
|
|
24
|
+
"summary_n_pred_final": 700,
|
|
25
|
+
"multipdf_n_pred_sect": 380,
|
|
26
|
+
"multipdf_n_pred_final": 900,
|
|
27
|
+
"ref_top_k": 6,
|
|
28
|
+
"ref_max_context_chars": 3000,
|
|
29
|
+
"pause_after_chunks": 2, # auto-pause suggestion threshold
|
|
30
|
+
"default_threads": 12,
|
|
31
|
+
"default_ctx": 4096,
|
|
32
|
+
"default_n_predict": 512,
|
|
33
|
+
"tps_display": True,
|
|
34
|
+
"auto_spill_on_start": False,
|
|
35
|
+
"stream_socket_timeout": 32000, # seconds before a silent read errors
|
|
36
|
+
"stream_stall_timeout": 32000, # seconds of no tokens before giving up
|
|
37
|
+
"stream_max_buf_bytes": 65536, # max line buffer size
|
|
38
|
+
}
|
|
39
|
+
# ─── Config descriptions ──────────────────────────────────────────────────────
|
|
40
|
+
CONFIG_FIELD_META = {
|
|
41
|
+
"ram_watchdog_mb": {
|
|
42
|
+
"label": "RAM Watchdog (MB)",
|
|
43
|
+
"desc": (
|
|
44
|
+
"Free RAM threshold in megabytes. When available RAM drops below "
|
|
45
|
+
"this value, reference chunk caches are automatically spilled to disk "
|
|
46
|
+
"to prevent system memory exhaustion. Lower = more aggressive spilling. "
|
|
47
|
+
"Recommended: 400–1200 MB depending on your total RAM."
|
|
48
|
+
),
|
|
49
|
+
"min": 100, "max": 8000, "type": "int",
|
|
50
|
+
},
|
|
51
|
+
"chunk_index_size": {
|
|
52
|
+
"label": "Ref Chunk Size (chars)",
|
|
53
|
+
"desc": (
|
|
54
|
+
"Character size of each indexed chunk when a reference file is loaded. "
|
|
55
|
+
"Smaller chunks = finer retrieval granularity but more memory entries. "
|
|
56
|
+
"Larger chunks = broader context per hit but less precise. "
|
|
57
|
+
"Recommended: 300–600."
|
|
58
|
+
),
|
|
59
|
+
"min": 100, "max": 2000, "type": "int",
|
|
60
|
+
},
|
|
61
|
+
"max_ram_chunks": {
|
|
62
|
+
"label": "Max RAM Chunks (per ref)",
|
|
63
|
+
"desc": (
|
|
64
|
+
"Maximum number of reference chunks kept in RAM per loaded file. "
|
|
65
|
+
"Chunks beyond this limit are evicted to disk. On systems with "
|
|
66
|
+
"8 GB RAM, 80–120 is safe. On 4 GB, consider 40–60."
|
|
67
|
+
),
|
|
68
|
+
"min": 10, "max": 500, "type": "int",
|
|
69
|
+
},
|
|
70
|
+
"summary_chunk_chars": {
|
|
71
|
+
"label": "Summary Chunk Size (chars)",
|
|
72
|
+
"desc": (
|
|
73
|
+
"Size of each text chunk sent to the model during PDF summarization. "
|
|
74
|
+
"Smaller values = more chunks, less RAM per step, but more inference calls. "
|
|
75
|
+
"Larger values = fewer calls but each prompt uses more context window. "
|
|
76
|
+
"Recommended: 2000–4000."
|
|
77
|
+
),
|
|
78
|
+
"min": 500, "max": 8000, "type": "int",
|
|
79
|
+
},
|
|
80
|
+
"summary_ctx_carry": {
|
|
81
|
+
"label": "Summary Context Carry (chars)",
|
|
82
|
+
"desc": (
|
|
83
|
+
"Number of characters from the previous chunk's summary to carry forward "
|
|
84
|
+
"as context for the next chunk. Helps maintain narrative continuity "
|
|
85
|
+
"across long documents. Recommended: 400–800."
|
|
86
|
+
),
|
|
87
|
+
"min": 100, "max": 2000, "type": "int",
|
|
88
|
+
},
|
|
89
|
+
"summary_n_pred_sect": {
|
|
90
|
+
"label": "Summary Tokens / Section",
|
|
91
|
+
"desc": (
|
|
92
|
+
"Maximum tokens the model generates for each section summary. "
|
|
93
|
+
"Higher = more detailed section summaries but slower processing. "
|
|
94
|
+
"Recommended: 250–500."
|
|
95
|
+
),
|
|
96
|
+
"min": 64, "max": 1024, "type": "int",
|
|
97
|
+
},
|
|
98
|
+
"summary_n_pred_final": {
|
|
99
|
+
"label": "Summary Tokens / Final Pass",
|
|
100
|
+
"desc": (
|
|
101
|
+
"Maximum tokens for the final consolidation pass that synthesizes "
|
|
102
|
+
"all section summaries into one cohesive document summary. "
|
|
103
|
+
"Recommended: 500–900."
|
|
104
|
+
),
|
|
105
|
+
"min": 128, "max": 2048, "type": "int",
|
|
106
|
+
},
|
|
107
|
+
"multipdf_n_pred_sect": {
|
|
108
|
+
"label": "Multi-PDF Tokens / Section",
|
|
109
|
+
"desc": (
|
|
110
|
+
"Tokens per section for multi-PDF batch summarization. "
|
|
111
|
+
"Same as Summary Tokens / Section but applied to each document "
|
|
112
|
+
"in a multi-document batch job. Recommended: 300–500."
|
|
113
|
+
),
|
|
114
|
+
"min": 64, "max": 1024, "type": "int",
|
|
115
|
+
},
|
|
116
|
+
"multipdf_n_pred_final": {
|
|
117
|
+
"label": "Multi-PDF Tokens / Final",
|
|
118
|
+
"desc": (
|
|
119
|
+
"Tokens for the final cross-document consolidation in multi-PDF mode. "
|
|
120
|
+
"This pass synthesizes summaries across all loaded documents, "
|
|
121
|
+
"so a higher value gives richer cross-document analysis. "
|
|
122
|
+
"Recommended: 700–1200."
|
|
123
|
+
),
|
|
124
|
+
"min": 128, "max": 2048, "type": "int",
|
|
125
|
+
},
|
|
126
|
+
"ref_top_k": {
|
|
127
|
+
"label": "Reference Top-K Chunks",
|
|
128
|
+
"desc": (
|
|
129
|
+
"Number of most relevant chunks retrieved from each reference file "
|
|
130
|
+
"per query. Higher = more context injected but larger prompts. "
|
|
131
|
+
"Lower = faster, smaller prompts. Recommended: 4–8."
|
|
132
|
+
),
|
|
133
|
+
"min": 1, "max": 20, "type": "int",
|
|
134
|
+
},
|
|
135
|
+
"ref_max_context_chars": {
|
|
136
|
+
"label": "Ref Max Context (chars)",
|
|
137
|
+
"desc": (
|
|
138
|
+
"Maximum total characters injected from all references combined "
|
|
139
|
+
"into each prompt. Guards against overflowing the model's context window. "
|
|
140
|
+
"Recommended: 1500–4000."
|
|
141
|
+
),
|
|
142
|
+
"min": 200, "max": 12000, "type": "int",
|
|
143
|
+
},
|
|
144
|
+
"pause_after_chunks": {
|
|
145
|
+
"label": "Pause-Suggest Threshold (chunks)",
|
|
146
|
+
"desc": (
|
|
147
|
+
"After this many chunks are processed, the app will show a "
|
|
148
|
+
"pause/save banner if many chunks remain. Set to 0 to disable "
|
|
149
|
+
"auto-pause suggestions. Recommended: 2–5."
|
|
150
|
+
),
|
|
151
|
+
"min": 0, "max": 50, "type": "int",
|
|
152
|
+
},
|
|
153
|
+
"default_threads": {
|
|
154
|
+
"label": "Default CPU Threads",
|
|
155
|
+
"desc": (
|
|
156
|
+
"Number of CPU threads used by llama.cpp for inference. "
|
|
157
|
+
"Setting this higher than your physical core count may reduce performance. "
|
|
158
|
+
f"Your system has {cpu_count()} logical CPUs. "
|
|
159
|
+
"Recommended: physical core count (not hyperthreaded)."
|
|
160
|
+
),
|
|
161
|
+
"min": 1, "max": 64, "type": "int",
|
|
162
|
+
},
|
|
163
|
+
"default_ctx": {
|
|
164
|
+
"label": "Default Context Window (tokens)",
|
|
165
|
+
"desc": (
|
|
166
|
+
"Default token context window loaded with each model. "
|
|
167
|
+
"Larger context = more conversation history, more RAM. "
|
|
168
|
+
"Each 4096 additional tokens uses ~0.5 GB extra RAM. "
|
|
169
|
+
"Recommended: 2048–8192 for most systems."
|
|
170
|
+
),
|
|
171
|
+
"min": 512, "max": 32768, "type": "int",
|
|
172
|
+
},
|
|
173
|
+
"default_n_predict": {
|
|
174
|
+
"label": "Default Max New Tokens",
|
|
175
|
+
"desc": (
|
|
176
|
+
"Default maximum number of tokens the model generates per response. "
|
|
177
|
+
"Does not affect RAM usage, only generation length. "
|
|
178
|
+
"Recommended: 256–1024."
|
|
179
|
+
),
|
|
180
|
+
"min": 32, "max": 4096, "type": "int",
|
|
181
|
+
},
|
|
182
|
+
"auto_spill_on_start": {
|
|
183
|
+
"label": "Auto-Spill Refs on Startup",
|
|
184
|
+
"desc": (
|
|
185
|
+
"When enabled, all reference chunk caches are immediately spilled to disk "
|
|
186
|
+
"on app startup regardless of available RAM. Useful on systems with "
|
|
187
|
+
"very low RAM where you need the model to have maximum headroom."
|
|
188
|
+
),
|
|
189
|
+
"min": 0, "max": 1, "type": "bool",
|
|
190
|
+
},
|
|
191
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from nativelab.imports.import_global import hashlib, psutil, HAS_PSUTIL, Dict
|
|
2
|
+
|
|
3
|
+
def ram_free_mb() -> float:
|
|
4
|
+
if HAS_PSUTIL:
|
|
5
|
+
return psutil.virtual_memory().available / (1024 * 1024)
|
|
6
|
+
return 9999.0
|
|
7
|
+
|
|
8
|
+
def cpu_count() -> int:
|
|
9
|
+
try:
|
|
10
|
+
import multiprocessing
|
|
11
|
+
n = multiprocessing.cpu_count()
|
|
12
|
+
return n if n and n > 0 else 4
|
|
13
|
+
except Exception:
|
|
14
|
+
return 4
|
|
15
|
+
|
|
16
|
+
def simple_hash(text: str) -> str:
|
|
17
|
+
return hashlib.md5(text.encode("utf-8", errors="replace")).hexdigest()[:12]
|
|
18
|
+
|
|
19
|
+
_SESSION_REF_STORES: Dict = {}
|
|
20
|
+
|
|
21
|
+
def get_ref_store(session_id: str):
|
|
22
|
+
from codeparser.codeparser_global import SessionReferenceStore
|
|
23
|
+
if session_id not in _SESSION_REF_STORES:
|
|
24
|
+
_SESSION_REF_STORES[session_id] = SessionReferenceStore(session_id)
|
|
25
|
+
return _SESSION_REF_STORES[session_id]
|
|
26
|
+
|
|
27
|
+
class RamWatchdog:
|
|
28
|
+
triggered = False
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def check_and_spill(session_id: str) -> bool:
|
|
32
|
+
from nativelab.GlobalConfig.config_global import RAM_WATCHDOG_MB
|
|
33
|
+
if ram_free_mb() < RAM_WATCHDOG_MB:
|
|
34
|
+
store = get_ref_store(session_id)
|
|
35
|
+
store.flush_ram()
|
|
36
|
+
RamWatchdog.triggered = True
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from nativelab.imports.import_global import dataclass, List, json, Dict
|
|
2
|
+
def _cfg():
|
|
3
|
+
from GlobalConfig import config_global
|
|
4
|
+
return config_global
|
|
5
|
+
@dataclass
|
|
6
|
+
class ApiConfig:
|
|
7
|
+
name: str = ""
|
|
8
|
+
provider: str = "OpenAI"
|
|
9
|
+
model_id: str = ""
|
|
10
|
+
api_key: str = ""
|
|
11
|
+
base_url: str = ""
|
|
12
|
+
api_format: str = "openai"
|
|
13
|
+
max_tokens: int = 2048
|
|
14
|
+
temperature: float = 0.7
|
|
15
|
+
# ── custom prompt format ─────────────────────────────────────────────────
|
|
16
|
+
use_custom_prompt: bool = False
|
|
17
|
+
system_prompt: str = ""
|
|
18
|
+
user_prefix: str = ""
|
|
19
|
+
user_suffix: str = ""
|
|
20
|
+
assistant_prefix: str = ""
|
|
21
|
+
prompt_template: str = "default" # "default"|"chatml"|"llama2"|"alpaca"|"custom"
|
|
22
|
+
# ── custom provider display ──────────────────────────────────────────────
|
|
23
|
+
custom_provider_name: str = ""
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> Dict:
|
|
26
|
+
return {k: getattr(self, k) for k in self.__dataclass_fields__}
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_dict(cls, d: Dict) -> "ApiConfig":
|
|
30
|
+
return cls(**{k: v for k, v in d.items() if k in cls.__dataclass_fields__})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ApiRegistry:
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self._configs: List[ApiConfig] = []
|
|
36
|
+
self._load()
|
|
37
|
+
|
|
38
|
+
def _load(self):
|
|
39
|
+
if _cfg().API_MODELS_FILE.exists():
|
|
40
|
+
try:
|
|
41
|
+
self._configs = [ApiConfig.from_dict(d)
|
|
42
|
+
for d in json.loads(_cfg().API_MODELS_FILE.read_text())]
|
|
43
|
+
except Exception:
|
|
44
|
+
self._configs = []
|
|
45
|
+
|
|
46
|
+
def save(self):
|
|
47
|
+
_cfg().API_MODELS_FILE.write_text(
|
|
48
|
+
json.dumps([c.to_dict() for c in self._configs], indent=2))
|
|
49
|
+
|
|
50
|
+
def add(self, cfg: ApiConfig):
|
|
51
|
+
self._configs = [c for c in self._configs if c.name != cfg.name]
|
|
52
|
+
self._configs.append(cfg)
|
|
53
|
+
self.save()
|
|
54
|
+
|
|
55
|
+
def remove(self, name: str):
|
|
56
|
+
self._configs = [c for c in self._configs if c.name != name]
|
|
57
|
+
self.save()
|
|
58
|
+
|
|
59
|
+
def all(self) -> List[ApiConfig]:
|
|
60
|
+
return list(self._configs)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
api_registry = None
|
|
64
|
+
|
|
65
|
+
def getapi_registry():
|
|
66
|
+
global api_registry
|
|
67
|
+
if api_registry is None:
|
|
68
|
+
api_registry = ApiRegistry()
|
|
69
|
+
return api_registry
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from nativelab.imports.import_global import Dict, dataclass, Path, json, field
|
|
2
|
+
from .model_family import *
|
|
3
|
+
# ═════════════════════════════ MODEL REGISTRY ═══════════════════════════════
|
|
4
|
+
def _cfg():
|
|
5
|
+
from GlobalConfig import config_global
|
|
6
|
+
return config_global
|
|
7
|
+
|
|
8
|
+
def _default_ctx():
|
|
9
|
+
v = _cfg().DEFAULT_CTX
|
|
10
|
+
return v() if callable(v) else int(v)
|
|
11
|
+
|
|
12
|
+
def _default_threads():
|
|
13
|
+
v = _cfg().DEFAULT_THREADS
|
|
14
|
+
return v() if callable(v) else int(v)
|
|
15
|
+
|
|
16
|
+
def _default_n_pred():
|
|
17
|
+
v = _cfg().DEFAULT_N_PRED
|
|
18
|
+
return v() if callable(v) else int(v)
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ModelConfig:
|
|
22
|
+
path: str
|
|
23
|
+
role: str = "general"
|
|
24
|
+
|
|
25
|
+
threads: int = field(default_factory=_default_threads)
|
|
26
|
+
ctx: int = field(default_factory=_default_ctx)
|
|
27
|
+
n_predict: int = field(default_factory=_default_n_pred)
|
|
28
|
+
|
|
29
|
+
temperature: float = 0.7
|
|
30
|
+
top_p: float = 0.9
|
|
31
|
+
repeat_penalty: float = 1.1
|
|
32
|
+
family: str = "default"
|
|
33
|
+
|
|
34
|
+
def to_dict(self) -> Dict:
|
|
35
|
+
return {
|
|
36
|
+
"path": self.path, "role": self.role,
|
|
37
|
+
"threads": int(self.threads) if not callable(self.threads) else int(self.threads()),
|
|
38
|
+
"ctx": int(self.ctx) if not callable(self.ctx) else int(self.ctx()),
|
|
39
|
+
"n_predict": int(self.n_predict) if not callable(self.n_predict) else int(self.n_predict()),
|
|
40
|
+
"temperature": self.temperature,
|
|
41
|
+
"top_p": self.top_p,
|
|
42
|
+
"repeat_penalty": self.repeat_penalty,
|
|
43
|
+
"family": self.family,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_dict(cls, d: Dict) -> "ModelConfig":
|
|
48
|
+
return cls(**{k: v for k, v in d.items() if k in cls.__dataclass_fields__})
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def name(self) -> str:
|
|
52
|
+
return Path(self.path).name
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def size_mb(self) -> float:
|
|
56
|
+
p = Path(self.path)
|
|
57
|
+
return round(p.stat().st_size / 1e6, 1) if p.exists() else 0.0
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def detected_family(self) -> ModelFamily:
|
|
61
|
+
return detect_model_family(self.path)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def quant_type(self) -> str:
|
|
65
|
+
return detect_quant_type(self.path)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ModelRegistry:
|
|
69
|
+
def __init__(self):
|
|
70
|
+
self._custom: List[str] = []
|
|
71
|
+
self._configs: Dict[str, ModelConfig] = {}
|
|
72
|
+
self._load()
|
|
73
|
+
|
|
74
|
+
def _load(self):
|
|
75
|
+
from nativelab.GlobalConfig.config_global import DEFAULT_CTX, DEFAULT_THREADS, DEFAULT_N_PRED, CUSTOM_MODELS_FILE, MODEL_CONFIGS_FILE, MODELS_DIR
|
|
76
|
+
if CUSTOM_MODELS_FILE.exists():
|
|
77
|
+
try:
|
|
78
|
+
self._custom = json.loads(CUSTOM_MODELS_FILE.read_text())
|
|
79
|
+
except Exception:
|
|
80
|
+
self._custom = []
|
|
81
|
+
if MODEL_CONFIGS_FILE.exists():
|
|
82
|
+
try:
|
|
83
|
+
raw = json.loads(MODEL_CONFIGS_FILE.read_text())
|
|
84
|
+
self._configs = {p: ModelConfig.from_dict(d) for p, d in raw.items()}
|
|
85
|
+
except Exception:
|
|
86
|
+
self._configs = {}
|
|
87
|
+
|
|
88
|
+
def save(self):
|
|
89
|
+
from nativelab.GlobalConfig.config_global import DEFAULT_CTX, DEFAULT_THREADS, DEFAULT_N_PRED, CUSTOM_MODELS_FILE, MODEL_CONFIGS_FILE, MODELS_DIR
|
|
90
|
+
CUSTOM_MODELS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
MODEL_CONFIGS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
|
|
93
|
+
CUSTOM_MODELS_FILE.write_text(json.dumps(self._custom, indent=2))
|
|
94
|
+
MODEL_CONFIGS_FILE.write_text(
|
|
95
|
+
json.dumps({p: c.to_dict() for p, c in self._configs.items()}, indent=2))
|
|
96
|
+
|
|
97
|
+
def add(self, path: str):
|
|
98
|
+
if path not in self._custom:
|
|
99
|
+
self._custom.append(path)
|
|
100
|
+
if path not in self._configs:
|
|
101
|
+
fam = detect_model_family(path)
|
|
102
|
+
self._configs[path] = ModelConfig(path=path, family=fam.family)
|
|
103
|
+
self.save()
|
|
104
|
+
|
|
105
|
+
def remove(self, path: str):
|
|
106
|
+
self._custom = [p for p in self._custom if p != path]
|
|
107
|
+
self._configs.pop(path, None)
|
|
108
|
+
self.save()
|
|
109
|
+
|
|
110
|
+
def get_config(self, path: str) -> ModelConfig:
|
|
111
|
+
if path not in self._configs:
|
|
112
|
+
fam = detect_model_family(path)
|
|
113
|
+
self._configs[path] = ModelConfig(path=path, family=fam.family)
|
|
114
|
+
return self._configs[path]
|
|
115
|
+
|
|
116
|
+
def set_config(self, path: str, cfg: ModelConfig):
|
|
117
|
+
self._configs[path] = cfg
|
|
118
|
+
self.save()
|
|
119
|
+
|
|
120
|
+
def all_models(self) -> List[Dict]:
|
|
121
|
+
from nativelab.GlobalConfig.config_global import DEFAULT_CTX, DEFAULT_THREADS, DEFAULT_N_PRED, CUSTOM_MODELS_FILE, MODEL_CONFIGS_FILE, MODELS_DIR
|
|
122
|
+
seen: set = set()
|
|
123
|
+
models: List[Dict] = []
|
|
124
|
+
if MODELS_DIR.exists():
|
|
125
|
+
for f in sorted(MODELS_DIR.glob("*.gguf")):
|
|
126
|
+
seen.add(str(f))
|
|
127
|
+
cfg = self.get_config(str(f))
|
|
128
|
+
fam = detect_model_family(str(f))
|
|
129
|
+
qt = detect_quant_type(str(f))
|
|
130
|
+
models.append({
|
|
131
|
+
"path": str(f), "name": f.name,
|
|
132
|
+
"size_mb": round(f.stat().st_size / 1e6, 1),
|
|
133
|
+
"source": "auto", "role": cfg.role,
|
|
134
|
+
"family": fam.name, "quant": qt,
|
|
135
|
+
})
|
|
136
|
+
for p in self._custom:
|
|
137
|
+
fp = Path(p)
|
|
138
|
+
if fp.exists() and p not in seen:
|
|
139
|
+
seen.add(p)
|
|
140
|
+
cfg = self.get_config(p)
|
|
141
|
+
fam = detect_model_family(p)
|
|
142
|
+
qt = detect_quant_type(p)
|
|
143
|
+
models.append({
|
|
144
|
+
"path": p, "name": fp.name,
|
|
145
|
+
"size_mb": round(fp.stat().st_size / 1e6, 1),
|
|
146
|
+
"source": "custom", "role": cfg.role,
|
|
147
|
+
"family": fam.name, "quant": qt,
|
|
148
|
+
})
|
|
149
|
+
return models
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
_model_registry = None
|
|
153
|
+
|
|
154
|
+
def get_model_registry():
|
|
155
|
+
global _model_registry
|
|
156
|
+
if _model_registry is None:
|
|
157
|
+
_model_registry = ModelRegistry()
|
|
158
|
+
return _model_registry
|
|
159
|
+
|
|
File without changes
|