syntaxmatrix 2.6.4.4__py3-none-any.whl → 3.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syntaxmatrix/__init__.py +6 -4
- syntaxmatrix/agentic/agents.py +206 -26
- syntaxmatrix/agentic/agents_orchestrer.py +16 -10
- syntaxmatrix/client_docs.py +237 -0
- syntaxmatrix/commentary.py +96 -25
- syntaxmatrix/core.py +142 -56
- syntaxmatrix/dataset_preprocessing.py +2 -2
- syntaxmatrix/db.py +0 -17
- syntaxmatrix/kernel_manager.py +174 -150
- syntaxmatrix/page_builder_generation.py +656 -63
- syntaxmatrix/page_layout_contract.py +25 -3
- syntaxmatrix/page_patch_publish.py +368 -15
- syntaxmatrix/plugins/__init__.py +0 -0
- syntaxmatrix/premium/__init__.py +10 -2
- syntaxmatrix/premium/catalogue/__init__.py +121 -0
- syntaxmatrix/premium/gate.py +15 -3
- syntaxmatrix/premium/state.py +507 -0
- syntaxmatrix/premium/verify.py +222 -0
- syntaxmatrix/profiles.py +1 -1
- syntaxmatrix/routes.py +9847 -8004
- syntaxmatrix/settings/model_map.py +50 -65
- syntaxmatrix/settings/prompts.py +1186 -414
- syntaxmatrix/settings/string_navbar.py +4 -4
- syntaxmatrix/static/icons/bot_icon.png +0 -0
- syntaxmatrix/static/icons/bot_icon2.png +0 -0
- syntaxmatrix/templates/admin_billing.html +408 -0
- syntaxmatrix/templates/admin_branding.html +65 -2
- syntaxmatrix/templates/admin_features.html +54 -0
- syntaxmatrix/templates/dashboard.html +285 -8
- syntaxmatrix/templates/edit_page.html +199 -18
- syntaxmatrix/themes.py +17 -17
- syntaxmatrix/workspace_db.py +0 -23
- syntaxmatrix-3.0.1.dist-info/METADATA +219 -0
- {syntaxmatrix-2.6.4.4.dist-info → syntaxmatrix-3.0.1.dist-info}/RECORD +38 -33
- {syntaxmatrix-2.6.4.4.dist-info → syntaxmatrix-3.0.1.dist-info}/WHEEL +1 -1
- syntaxmatrix/settings/default.yaml +0 -13
- syntaxmatrix-2.6.4.4.dist-info/METADATA +0 -539
- syntaxmatrix-2.6.4.4.dist-info/licenses/LICENSE.txt +0 -21
- /syntaxmatrix/{plugin_manager.py → plugins/plugin_manager.py} +0 -0
- /syntaxmatrix/static/icons/{logo3.png → logo2.png} +0 -0
- {syntaxmatrix-2.6.4.4.dist-info → syntaxmatrix-3.0.1.dist-info}/top_level.txt +0 -0
syntaxmatrix/core.py
CHANGED
|
@@ -16,7 +16,7 @@ from .file_processor import process_admin_pdf_files
|
|
|
16
16
|
from google.genai import types
|
|
17
17
|
from .vector_db import query_embeddings
|
|
18
18
|
from .vectorizer import embed_text
|
|
19
|
-
from typing import List, Generator
|
|
19
|
+
from typing import List, Generator, Optional
|
|
20
20
|
from .auth import init_auth_db
|
|
21
21
|
from . import profiles as _prof
|
|
22
22
|
from syntaxmatrix.smiv import SMIV
|
|
@@ -27,17 +27,16 @@ from html import unescape
|
|
|
27
27
|
from .plottings import render_plotly, pyplot, describe_plotly, describe_matplotlib
|
|
28
28
|
from threading import RLock
|
|
29
29
|
from syntaxmatrix.settings.model_map import GPT_MODELS_LATEST
|
|
30
|
+
from syntaxmatrix.settings.client_items import read_client_file, getenv_api_key
|
|
31
|
+
from syntaxmatrix.plugins.plugin_manager import PluginManager
|
|
32
|
+
from .premium import FeatureGate, ensure_premium_state
|
|
33
|
+
from pathlib import Path
|
|
30
34
|
from syntaxmatrix.settings.prompts import(
|
|
31
35
|
SMXAI_CHAT_IDENTITY,
|
|
32
36
|
SMXAI_CHAT_INSTRUCTIONS,
|
|
33
37
|
SMXAI_WEBSITE_DESCRIPTION,
|
|
34
38
|
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
from .premium import FeatureGate
|
|
38
|
-
from .plugin_manager import PluginManager
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
# ──────── framework‐local storage paths ────────
|
|
42
41
|
# this ensures the key & data always live under the package dir,
|
|
43
42
|
_CLIENT_DIR = detect_project_root()
|
|
@@ -59,7 +58,7 @@ EDA_OUTPUT = {} # global buffer for EDA output by session
|
|
|
59
58
|
|
|
60
59
|
class SyntaxMUI:
|
|
61
60
|
def __init__(self,
|
|
62
|
-
|
|
61
|
+
host="127.0.0.1",
|
|
63
62
|
port="5080",
|
|
64
63
|
user_icon="👩🏿🦲",
|
|
65
64
|
bot_icon="<img src='/static/icons/bot_icon.png' width=20' alt='bot'/>",
|
|
@@ -67,10 +66,12 @@ class SyntaxMUI:
|
|
|
67
66
|
site_logo="<img src='/static/icons/logo.png' width='45' alt='logo'/>",
|
|
68
67
|
site_title="SyntaxMatrix",
|
|
69
68
|
project_name="smxAI",
|
|
70
|
-
theme_name="
|
|
69
|
+
theme_name="chark",
|
|
71
70
|
ui_mode = "default"
|
|
72
71
|
):
|
|
73
|
-
self.app = Flask(__name__)
|
|
72
|
+
self.app = Flask(__name__)
|
|
73
|
+
self._client_dir = Path(_CLIENT_DIR).resolve()
|
|
74
|
+
self._client_root = self._client_dir.parent
|
|
74
75
|
self.host = host
|
|
75
76
|
self.port = port
|
|
76
77
|
|
|
@@ -82,7 +83,6 @@ class SyntaxMUI:
|
|
|
82
83
|
self.bot_icon = bot_icon
|
|
83
84
|
self.site_title = site_title
|
|
84
85
|
self.project_name = project_name
|
|
85
|
-
|
|
86
86
|
self._default_site_logo = self.site_logo
|
|
87
87
|
self._default_favicon = self.favicon
|
|
88
88
|
self._default_bot_icon = self.bot_icon
|
|
@@ -93,25 +93,45 @@ class SyntaxMUI:
|
|
|
93
93
|
self.theme_toggle_enabled = False
|
|
94
94
|
self.user_files_enabled = False
|
|
95
95
|
self.registration_enabled = False
|
|
96
|
+
self.site_documentation_enabled = False
|
|
97
|
+
self.ml_lab_enabled = False
|
|
98
|
+
|
|
96
99
|
self.smxai_identity = SMXAI_CHAT_IDENTITY
|
|
97
100
|
self.smxai_instructions = SMXAI_CHAT_INSTRUCTIONS
|
|
98
101
|
self.website_description = SMXAI_WEBSITE_DESCRIPTION
|
|
102
|
+
# Preserve framework defaults so client branding can safely override and reset.
|
|
103
|
+
self._default_smxai_identity = self.smxai_identity
|
|
104
|
+
self._default_smxai_instructions = self.smxai_instructions
|
|
105
|
+
self._default_website_description = self.website_description
|
|
106
|
+
|
|
99
107
|
self._eda_output = {} # {chat_id: html}
|
|
100
108
|
self._eda_lock = RLock()
|
|
101
109
|
|
|
102
110
|
db.init_db()
|
|
111
|
+
self.db = db
|
|
103
112
|
self.page = ""
|
|
104
113
|
self.pages = db.get_pages()
|
|
114
|
+
|
|
105
115
|
init_auth_db()
|
|
116
|
+
try:
|
|
117
|
+
ensure_premium_state(db=db, client_dir=str(_CLIENT_DIR), trial_days=7)
|
|
118
|
+
except Exception:
|
|
119
|
+
pass
|
|
106
120
|
|
|
107
121
|
self.widgets = OrderedDict()
|
|
108
|
-
self.theme = DEFAULT_THEMES.get(theme_name, DEFAULT_THEMES["
|
|
109
|
-
self.system_output_buffer = "" # Ephemeral buffer
|
|
122
|
+
self.theme = DEFAULT_THEMES.get(theme_name, DEFAULT_THEMES["chark"])
|
|
123
|
+
self.system_output_buffer = "" # Ephemeral buffer initialised
|
|
110
124
|
self.app_token = str(uuid.uuid4()) # NEW: Unique token for each app launch.
|
|
111
125
|
self.admin_pdf_chunks = {} # In-memory store for admin PDF chunks
|
|
112
|
-
self.user_file_chunks = {} # In-memory store of user‑uploaded chunks, scoped per chat
|
|
113
|
-
|
|
126
|
+
self.user_file_chunks = {} # In-memory store of user‑uploaded chunks, scoped per chat
|
|
114
127
|
self._last_llm_usage = None
|
|
128
|
+
|
|
129
|
+
# Apply persisted feature flags + theme (fail-soft)
|
|
130
|
+
try:
|
|
131
|
+
self._apply_feature_flags_from_db()
|
|
132
|
+
except Exception:
|
|
133
|
+
pass
|
|
134
|
+
|
|
115
135
|
routes.setup_routes(self)
|
|
116
136
|
|
|
117
137
|
# Apply client branding overrides if present on disk
|
|
@@ -182,7 +202,7 @@ class SyntaxMUI:
|
|
|
182
202
|
if not hasattr(self, "_recent_visual_summaries"):
|
|
183
203
|
self._recent_visual_summaries = []
|
|
184
204
|
# keep last 6
|
|
185
|
-
self._recent_visual_summaries = (self._recent_visual_summaries + [summary])[-6:]
|
|
205
|
+
self._recent_visual_summaries = (self._recent_visual_summaries + [summary]) # [-6:]
|
|
186
206
|
|
|
187
207
|
def set_plottings(self, fig_or_html, note=None):
|
|
188
208
|
# prefer current chat id; fall back to per-browser sid; finally "default"
|
|
@@ -340,18 +360,29 @@ class SyntaxMUI:
|
|
|
340
360
|
DEFAULT_THEMES[theme_name] = theme
|
|
341
361
|
self.theme = DEFAULT_THEMES[theme_name]
|
|
342
362
|
else:
|
|
343
|
-
self.theme = DEFAULT_THEMES["
|
|
344
|
-
self.error("Theme must be 'light', 'dark', or a custom dict.")
|
|
363
|
+
self.theme = DEFAULT_THEMES["chark"]
|
|
364
|
+
self.error("Theme must be 'chark', 'light', 'dark', or a custom dict.")
|
|
345
365
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
self.theme_toggle_enabled
|
|
349
|
-
|
|
350
|
-
def enable_user_files(self):
|
|
351
|
-
self.user_files_enabled =
|
|
366
|
+
def enable_theme_toggle(self, bul: bool = True):
|
|
367
|
+
self.theme_toggle_enabled = bool(bul)
|
|
368
|
+
return self.theme_toggle_enabled
|
|
369
|
+
|
|
370
|
+
def enable_user_files(self, bul: bool = True):
|
|
371
|
+
self.user_files_enabled = bool(bul)
|
|
372
|
+
return self.user_files_enabled
|
|
373
|
+
|
|
374
|
+
def enable_registration(self, bul: bool = True):
|
|
375
|
+
self.registration_enabled = bool(bul)
|
|
376
|
+
return self.registration_enabled
|
|
377
|
+
|
|
378
|
+
def enable_site_documentation(self, bul: bool = True):
|
|
379
|
+
self.site_documentation_enabled = bool(bul)
|
|
380
|
+
return self.site_documentation_enabled
|
|
381
|
+
|
|
382
|
+
def enable_ml_lab(self, bul: bool = True):
|
|
383
|
+
self.ml_lab_enabled = bool(bul)
|
|
384
|
+
return self.ml_lab_enabled
|
|
352
385
|
|
|
353
|
-
def enable_registration(self):
|
|
354
|
-
self.registration_enabled = True
|
|
355
386
|
|
|
356
387
|
def _apply_feature_flags_from_db(self):
|
|
357
388
|
"""
|
|
@@ -364,8 +395,25 @@ class SyntaxMUI:
|
|
|
364
395
|
stream_v = db.get_setting("feature.stream_mode", "1")
|
|
365
396
|
user_files_v = db.get_setting("feature.user_files", "1")
|
|
366
397
|
|
|
398
|
+
# NEW defaults are all False (0)
|
|
399
|
+
docs_v = db.get_setting("feature.site_documentation", "0")
|
|
400
|
+
ml_v = db.get_setting("feature.ml_lab", "0")
|
|
401
|
+
reg_v = db.get_setting("feature.registration", "0")
|
|
402
|
+
theme_toggle_v = db.get_setting("feature.theme_toggle", "0")
|
|
403
|
+
|
|
404
|
+
# Theme is a choice (default light)
|
|
405
|
+
theme_name = db.get_setting("branding.theme_name", "light")
|
|
406
|
+
|
|
367
407
|
self.is_streaming = _truthy(stream_v)
|
|
368
408
|
self.user_files_enabled = _truthy(user_files_v)
|
|
409
|
+
|
|
410
|
+
self.site_documentation_enabled = _truthy(docs_v)
|
|
411
|
+
self.ml_lab_enabled = _truthy(ml_v)
|
|
412
|
+
self.registration_enabled = _truthy(reg_v)
|
|
413
|
+
self.theme_toggle_enabled = _truthy(theme_toggle_v)
|
|
414
|
+
|
|
415
|
+
# Apply the chosen theme to the instance
|
|
416
|
+
self.set_theme(str(theme_name or "light").strip().lower() or "light")
|
|
369
417
|
except Exception:
|
|
370
418
|
# Keep defaults if DB isn't ready for any reason
|
|
371
419
|
pass
|
|
@@ -399,6 +447,31 @@ class SyntaxMUI:
|
|
|
399
447
|
use it; otherwise keep the framework defaults.
|
|
400
448
|
Also pulls site_title and project_name from app_settings.
|
|
401
449
|
"""
|
|
450
|
+
|
|
451
|
+
# Premium gating: ignore custom branding unless entitled.
|
|
452
|
+
try:
|
|
453
|
+
if hasattr(self, "feature_gate") and self.feature_gate and (not self.feature_gate.enabled("branding_controls")):
|
|
454
|
+
self.site_logo = getattr(self, "_default_site_logo", self.site_logo)
|
|
455
|
+
self.favicon = getattr(self, "_default_favicon", self.favicon)
|
|
456
|
+
self.bot_icon = getattr(self, "_default_bot_icon", self.bot_icon)
|
|
457
|
+
try:
|
|
458
|
+
self.set_smxai_identity("")
|
|
459
|
+
self.set_smxai_instructions("")
|
|
460
|
+
self.set_website_description(getattr(self, "_default_website_description", self.website_description))
|
|
461
|
+
except Exception:
|
|
462
|
+
pass
|
|
463
|
+
self.site_title = getattr(self, "_default_site_title", self.site_title)
|
|
464
|
+
self.project_name = getattr(self, "_default_project_name", self.project_name)
|
|
465
|
+
return
|
|
466
|
+
except Exception:
|
|
467
|
+
# Fail closed: if we cannot resolve entitlements, do not apply custom branding.
|
|
468
|
+
self.site_logo = getattr(self, "_default_site_logo", self.site_logo)
|
|
469
|
+
self.favicon = getattr(self, "_default_favicon", self.favicon)
|
|
470
|
+
self.bot_icon = getattr(self, "_default_bot_icon", self.bot_icon)
|
|
471
|
+
self.site_title = getattr(self, "_default_site_title", self.site_title)
|
|
472
|
+
self.project_name = getattr(self, "_default_project_name", self.project_name)
|
|
473
|
+
return
|
|
474
|
+
|
|
402
475
|
branding_dir = os.path.join(_CLIENT_DIR, "branding")
|
|
403
476
|
|
|
404
477
|
def _pick_any(*basenames: str):
|
|
@@ -432,6 +505,18 @@ class SyntaxMUI:
|
|
|
432
505
|
self.bot_icon = f"<img src='/branding/{bot_fn}' width='20' alt='bot'/>"
|
|
433
506
|
else:
|
|
434
507
|
self.bot_icon = getattr(self, "_default_bot_icon", self.bot_icon)
|
|
508
|
+
# AI branding (stored in DB; blank value means "use framework default")
|
|
509
|
+
ident = (self.db.get_setting("branding.smxai_identity", "") or "").strip()
|
|
510
|
+
instr = (self.db.get_setting("branding.smxai_instructions", "") or "").strip()
|
|
511
|
+
wdesc = (self.db.get_setting("branding.website_description", "") or "").strip()
|
|
512
|
+
|
|
513
|
+
# Use the setters so behaviour is consistent across the framework.
|
|
514
|
+
self.set_smxai_identity(ident)
|
|
515
|
+
self.set_smxai_instructions(instr)
|
|
516
|
+
if wdesc:
|
|
517
|
+
self.set_website_description(wdesc)
|
|
518
|
+
else:
|
|
519
|
+
self.set_website_description(getattr(self, "_default_website_description", self.website_description))
|
|
435
520
|
|
|
436
521
|
# Site title + project name (DB settings; fall back to defaults)
|
|
437
522
|
try:
|
|
@@ -619,17 +704,20 @@ class SyntaxMUI:
|
|
|
619
704
|
# *********** LLM CLIENT HELPERS **********************
|
|
620
705
|
# ──────────────────────────────────────────────────────────────
|
|
621
706
|
def set_smxai_identity(self, profile):
|
|
622
|
-
|
|
623
|
-
|
|
707
|
+
"""Set the system identity/profile used by the chat model."""
|
|
708
|
+
profile = (profile or "").strip()
|
|
709
|
+
self.smxai_identity = profile if profile else getattr(self, "_default_smxai_identity", self.smxai_identity)
|
|
624
710
|
|
|
625
711
|
def set_smxai_instructions(self, instructions):
|
|
626
|
-
|
|
712
|
+
"""Set additional system instructions used by the chat model."""
|
|
713
|
+
instructions = (instructions or "").strip()
|
|
714
|
+
self.smxai_instructions = instructions if instructions else getattr(self, "_default_smxai_instructions", self.smxai_instructions)
|
|
627
715
|
|
|
628
716
|
|
|
629
717
|
def set_website_description(self, desc):
|
|
630
718
|
self.website_description = desc
|
|
631
719
|
|
|
632
|
-
|
|
720
|
+
|
|
633
721
|
def embed_query(self, q):
|
|
634
722
|
return embed_text(q)
|
|
635
723
|
|
|
@@ -705,7 +793,7 @@ class SyntaxMUI:
|
|
|
705
793
|
self.classifier_profile['client'] = _prof.get_client(classifier_profile)
|
|
706
794
|
|
|
707
795
|
_client = self.classifier_profile['client']
|
|
708
|
-
_provider = self.classifier_profile['provider']
|
|
796
|
+
_provider = self.classifier_profile['provider'].lower()
|
|
709
797
|
_model = self.classifier_profile['model']
|
|
710
798
|
|
|
711
799
|
# New instruction format with hybrid option
|
|
@@ -818,7 +906,7 @@ class SyntaxMUI:
|
|
|
818
906
|
"""
|
|
819
907
|
|
|
820
908
|
_client = self.summarizer_profile['client']
|
|
821
|
-
_provider = self.summarizer_profile['provider']
|
|
909
|
+
_provider = self.summarizer_profile['provider'].lower()
|
|
822
910
|
_model = self.summarizer_profile['model']
|
|
823
911
|
|
|
824
912
|
def google_generated_title():
|
|
@@ -829,7 +917,7 @@ class SyntaxMUI:
|
|
|
829
917
|
)
|
|
830
918
|
return response.text.strip()
|
|
831
919
|
except Exception as e:
|
|
832
|
-
return f"Google Summary agent error
|
|
920
|
+
return f"Google Summary agent error: {e}"
|
|
833
921
|
|
|
834
922
|
def gpt_models_latest_generated_title():
|
|
835
923
|
try:
|
|
@@ -905,16 +993,15 @@ class SyntaxMUI:
|
|
|
905
993
|
if not chat_profile:
|
|
906
994
|
yield """
|
|
907
995
|
<p style='color:red;'>
|
|
908
|
-
Error
|
|
909
|
-
|
|
910
|
-
To do that, you must login first or contact your administrator.
|
|
996
|
+
Error, Chat profile is not configured!
|
|
997
|
+
Login to the admin panel and add the LLM profile for chatting or contact your administrator.
|
|
911
998
|
</p>
|
|
912
999
|
"""
|
|
913
1000
|
return None
|
|
914
1001
|
self.chat_profile = chat_profile
|
|
915
1002
|
self.chat_profile['client'] = _prof.get_client(chat_profile)
|
|
916
1003
|
|
|
917
|
-
_provider = self.chat_profile['provider']
|
|
1004
|
+
_provider = self.chat_profile['provider'].lower()
|
|
918
1005
|
_client = self.chat_profile['client']
|
|
919
1006
|
_model = self.chat_profile['model']
|
|
920
1007
|
|
|
@@ -927,19 +1014,14 @@ class SyntaxMUI:
|
|
|
927
1014
|
"""
|
|
928
1015
|
|
|
929
1016
|
try:
|
|
930
|
-
if _provider == "google":
|
|
931
|
-
|
|
932
|
-
for chunk in _client.models.generate_content_stream(
|
|
1017
|
+
if _provider == "google":
|
|
1018
|
+
chuncks = _client.models.generate_content_stream(
|
|
933
1019
|
model=_model,
|
|
934
1020
|
contents=_contents,
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
),
|
|
940
|
-
):
|
|
941
|
-
|
|
942
|
-
yield chunk.text
|
|
1021
|
+
)
|
|
1022
|
+
for chunk in chuncks:
|
|
1023
|
+
if chunk:
|
|
1024
|
+
yield chunk.text
|
|
943
1025
|
|
|
944
1026
|
elif _provider == "openai" and _model in self.get_gpt_models_latest(): # GPt 5 series
|
|
945
1027
|
input_prompt = (
|
|
@@ -986,7 +1068,7 @@ class SyntaxMUI:
|
|
|
986
1068
|
if token:
|
|
987
1069
|
yield token
|
|
988
1070
|
except Exception as e:
|
|
989
|
-
yield f"Error during streaming: {type(e).__name__}: {e}"
|
|
1071
|
+
yield f"Error during streaming: CLIENT {_client}" # {type(e).__name__}: {e}"
|
|
990
1072
|
|
|
991
1073
|
|
|
992
1074
|
def process_query(self, query, context, history, stream=False):
|
|
@@ -996,16 +1078,15 @@ class SyntaxMUI:
|
|
|
996
1078
|
if not chat_profile:
|
|
997
1079
|
yield """
|
|
998
1080
|
<p style='color:red;'>
|
|
999
|
-
Error
|
|
1000
|
-
|
|
1001
|
-
To do that, you must login first or contact your administrator.
|
|
1081
|
+
Error, Chat profile is not configured!
|
|
1082
|
+
Login to the admin panel and add the LLM profile for chatting or contact your administrator.
|
|
1002
1083
|
</p>
|
|
1003
1084
|
"""
|
|
1004
|
-
|
|
1085
|
+
return None
|
|
1005
1086
|
|
|
1006
1087
|
self.chat_profile = chat_profile
|
|
1007
1088
|
self.chat_profile['client'] = _prof.get_client(chat_profile)
|
|
1008
|
-
_provider = self.chat_profile['provider']
|
|
1089
|
+
_provider = self.chat_profile['provider'].lower()
|
|
1009
1090
|
_client = self.chat_profile['client']
|
|
1010
1091
|
_model = self.chat_profile['model']
|
|
1011
1092
|
_contents = f"""
|
|
@@ -1557,7 +1638,12 @@ class SyntaxMUI:
|
|
|
1557
1638
|
current_profile['client'] = _prof.get_client(current_profile)
|
|
1558
1639
|
return current_profile
|
|
1559
1640
|
|
|
1560
|
-
def run(self):
|
|
1641
|
+
def run(self, browser: Optional[str] = None) -> None:
|
|
1561
1642
|
url = f"http://{self.host}:{self.port}/"
|
|
1562
|
-
|
|
1643
|
+
|
|
1644
|
+
if browser:
|
|
1645
|
+
webbrowser.get(browser).open(url)
|
|
1646
|
+
else:
|
|
1647
|
+
webbrowser.open(url)
|
|
1648
|
+
|
|
1563
1649
|
self.app.run(host=self.host, port=self.port, debug=False)
|
|
@@ -181,9 +181,9 @@ def _impute_for_analysis(df: pd.DataFrame) -> Tuple[pd.DataFrame, Dict[str, str]
|
|
|
181
181
|
def ensure_cleaned_df(DATA_FOLDER: str, cleaned_folder: str, df: pd.DataFrame) -> pd.DataFrame:
|
|
182
182
|
"""
|
|
183
183
|
Build (or reuse) an analysis-ready cleaned dataset and persist to:
|
|
184
|
-
f"{DATA_FOLDER}/{
|
|
184
|
+
f"{DATA_FOLDER}/{selected_dataset_processed}/cleaned_df.csv"
|
|
185
185
|
Also writes a missingness audit:
|
|
186
|
-
f"{DATA_FOLDER}/{
|
|
186
|
+
f"{DATA_FOLDER}/{selected_dataset_processed}/missingness.csv"
|
|
187
187
|
Returns the cleaned frame. Does NOT mutate the provided df.
|
|
188
188
|
"""
|
|
189
189
|
target_dir = os.path.join(DATA_FOLDER, cleaned_folder)
|
syntaxmatrix/db.py
CHANGED
|
@@ -628,23 +628,6 @@ def get_setting(key: str, default: str | None = None) -> str | None:
|
|
|
628
628
|
conn.close()
|
|
629
629
|
|
|
630
630
|
|
|
631
|
-
# ============================================================================
|
|
632
|
-
# Optional DB backend override (Premium hook)
|
|
633
|
-
#
|
|
634
|
-
# Default behaviour (no env vars): SQLite stays in use exactly as before.
|
|
635
|
-
#
|
|
636
|
-
# To enable a premium backend (e.g. Postgres), set:
|
|
637
|
-
# SMX_DB_PROVIDER=postgres
|
|
638
|
-
#
|
|
639
|
-
# Optional:
|
|
640
|
-
# SMX_DB_BACKEND_MODULE=syntaxmatrix_premium.db_backends.postgres_backend
|
|
641
|
-
#
|
|
642
|
-
# The backend module should either expose:
|
|
643
|
-
# - install(target_globals: dict) -> None (preferred)
|
|
644
|
-
# OR export a compatible surface (functions/constants) that will be copied
|
|
645
|
-
# into this module namespace.
|
|
646
|
-
# ============================================================================
|
|
647
|
-
|
|
648
631
|
def _smx_apply_optional_backend_override() -> None:
|
|
649
632
|
import os
|
|
650
633
|
import importlib
|