syntaxmatrix 2.2.3__tar.gz → 2.2.5__tar.gz
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-2.2.3 → syntaxmatrix-2.2.5}/PKG-INFO +1 -1
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/PKG-INFO +1 -1
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/SOURCES.txt +1 -1
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/setup.py +1 -1
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/commentary.py +18 -37
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/core.py +66 -75
- syntaxmatrix-2.2.5/syntaxmatrix/display.py +54 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/kernel_manager.py +91 -17
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/routes.py +168 -54
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/prompts.py +18 -74
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/docs.md +2 -2
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/dashboard.html +59 -8
- syntaxmatrix-2.2.5/syntaxmatrix/templates/docs.html +72 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/utils.py +41 -0
- syntaxmatrix-2.2.3/syntaxmatrix/display.py +0 -132
- syntaxmatrix-2.2.3/syntaxmatrix/templates/docs_page_embed.html +0 -20
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/LICENSE.txt +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/README.md +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/dependency_links.txt +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/requires.txt +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/top_level.txt +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/pyproject.toml +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/setup.cfg +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/__init__.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/auth.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/bootstrap.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/db.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/emailer.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/file_processor.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/generate_page.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/gpt_models_latest.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/history_store.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/llm_store.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/model_templates.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/models.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/plottings.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/profiles.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/project_root.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/session.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/__init__.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/default.yaml +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/logging.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/model_map.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/string_navbar.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/smiv.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/smpv.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/css/style.css +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/favicon.png +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/hero_bg.jpg +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/logo.png +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/svg_497526.svg +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/svg_497528.svg +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/chat.js +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/sidebar.js +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/widgets.js +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/code_cell.html +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/error.html +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/login.html +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/register.html +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/themes.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/ui_modes.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vector_db.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/__init__.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/__init__.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/milvus_adapter.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/pgvector_adapter.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/sqlite_adapter.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/base.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/registry.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectorizer.py +0 -0
- {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/workspace_db.py +0 -0
|
@@ -59,7 +59,7 @@ syntaxmatrix/static/js/sidebar.js
|
|
|
59
59
|
syntaxmatrix/static/js/widgets.js
|
|
60
60
|
syntaxmatrix/templates/code_cell.html
|
|
61
61
|
syntaxmatrix/templates/dashboard.html
|
|
62
|
-
syntaxmatrix/templates/
|
|
62
|
+
syntaxmatrix/templates/docs.html
|
|
63
63
|
syntaxmatrix/templates/error.html
|
|
64
64
|
syntaxmatrix/templates/login.html
|
|
65
65
|
syntaxmatrix/templates/register.html
|
|
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="syntaxmatrix",
|
|
11
|
-
version="2.2.
|
|
11
|
+
version="2.2.5",
|
|
12
12
|
author="Bob Nti",
|
|
13
13
|
author_email="bob.nti@syntaxmatrix.com",
|
|
14
14
|
description="SyntaxMUI: A customizable framework for Python AI Assistant Projects.",
|
|
@@ -169,11 +169,11 @@ Question:
|
|
|
169
169
|
Visible context strings (titles, axes, legends, headers):
|
|
170
170
|
{ctx}
|
|
171
171
|
|
|
172
|
-
Write a concise conclusion (~
|
|
173
|
-
- Headline (one sentence answering the question).
|
|
174
|
-
- Evidence (
|
|
175
|
-
- Limitations (1
|
|
176
|
-
- Next step (1 bullet).
|
|
172
|
+
Write a concise conclusion (~200-260 words) with:
|
|
173
|
+
- <strong>Headline</strong> (one sentence answering the question).
|
|
174
|
+
- <strong>Evidence</strong> (6-8 bullets referencing panels/axes/legend groups seen in the figures and explaining the plots/tables vis-a-vis the query). Explain all the oupupt comprehensively in details.
|
|
175
|
+
- <strong>Limitations</strong> (1 bullets; avoid quoting numbers unless present in context).
|
|
176
|
+
- <strong>Next step</strong> (1 bullet).
|
|
177
177
|
"""
|
|
178
178
|
|
|
179
179
|
def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) -> str:
|
|
@@ -188,18 +188,18 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
188
188
|
ctx=json.dumps(visible, ensure_ascii=False, indent=2)
|
|
189
189
|
)
|
|
190
190
|
|
|
191
|
-
prof = _prof.get_profile("
|
|
191
|
+
prof = _prof.get_profile("image2text") or _prof.get_profile("admin")
|
|
192
192
|
if not prof:
|
|
193
193
|
return (
|
|
194
194
|
"<div class='smx-alert smx-alert-warn'>"
|
|
195
|
-
"No LLM profile configured for
|
|
195
|
+
"No LLM profile is configured for Image2Text. Please, do that in the Admin panel or contact your Administrator."
|
|
196
196
|
"</div>"
|
|
197
197
|
)
|
|
198
198
|
_client = _prof.get_client(prof)
|
|
199
199
|
_provider = (prof.get("provider") or "").lower()
|
|
200
200
|
_model = prof.get("model") or ""
|
|
201
201
|
|
|
202
|
-
# Google
|
|
202
|
+
# Google
|
|
203
203
|
if _provider == "google":
|
|
204
204
|
try:
|
|
205
205
|
parts = [types.Part.from_text(text=user)]
|
|
@@ -216,8 +216,9 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
216
216
|
if txt.strip():
|
|
217
217
|
return txt.strip()
|
|
218
218
|
except Exception:
|
|
219
|
-
|
|
219
|
+
pass # Fall through to the chat.completions fallback implemented below.
|
|
220
220
|
|
|
221
|
+
# Openai
|
|
221
222
|
elif _provider == "openai" and _model in GPT_MODELS_LATEST:
|
|
222
223
|
# Use the Responses API with multimodal input (text + up to 4 images)
|
|
223
224
|
try:
|
|
@@ -240,10 +241,8 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
240
241
|
if txt.strip():
|
|
241
242
|
return txt.strip()
|
|
242
243
|
except Exception:
|
|
243
|
-
#
|
|
244
|
-
|
|
245
|
-
pass
|
|
246
|
-
|
|
244
|
+
pass # Fall through to the chat.completions fallback implemented below.
|
|
245
|
+
|
|
247
246
|
# Anthropic
|
|
248
247
|
elif _provider == "anthropic":
|
|
249
248
|
try:
|
|
@@ -261,8 +260,9 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
261
260
|
)
|
|
262
261
|
return response.content[0].text.strip()
|
|
263
262
|
except Exception:
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
pass # Fall through to the chat.completions fallback implemented below.
|
|
264
|
+
|
|
265
|
+
# OpenAI SDK
|
|
266
266
|
else: # provider in {"openai","xai","deepseek","moonshotai","alibaba"}:
|
|
267
267
|
try:
|
|
268
268
|
parts = [{"type":"text","text": user}]
|
|
@@ -271,7 +271,7 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
271
271
|
parts.append({"type":"image_url","image_url":{"url": f"data:image/png;base64,{b64}"}})
|
|
272
272
|
resp = _client.chat.completions.create(
|
|
273
273
|
model=_model,
|
|
274
|
-
temperature=0.
|
|
274
|
+
temperature=0.3,
|
|
275
275
|
messages=[
|
|
276
276
|
{"role":"system","content":_SYSTEM_VISION},
|
|
277
277
|
{"role":"user","content":parts},
|
|
@@ -280,29 +280,10 @@ def phrase_commentary_vision(context: Dict[str, Any], images_b64: List[str]) ->
|
|
|
280
280
|
)
|
|
281
281
|
return (resp.choices[0].message.content or "").strip()
|
|
282
282
|
except Exception:
|
|
283
|
-
|
|
283
|
+
pass # Fall through to the chat.completions fallback implemented below.
|
|
284
284
|
|
|
285
285
|
# Text-only fallback via Responses API
|
|
286
|
-
|
|
287
|
-
args = set_args(model=_model, instructions=_SYSTEM_VISION,
|
|
288
|
-
input=user, previous_id=None, store=False,
|
|
289
|
-
reasoning_effort="minimal", verbosity="low")
|
|
290
|
-
resp = _client.responses.create(**args)
|
|
291
|
-
return _out(resp)
|
|
292
|
-
except Exception:
|
|
293
|
-
# Classic chat fallback
|
|
294
|
-
try:
|
|
295
|
-
resp = _client.chat.completions.create(
|
|
296
|
-
model=_model,
|
|
297
|
-
temperature=0.2,
|
|
298
|
-
messages=[{"role":"system","content":_SYSTEM_VISION},
|
|
299
|
-
{"role":"user","content":user}],
|
|
300
|
-
max_tokens=600,
|
|
301
|
-
)
|
|
302
|
-
return (resp.choices[0].message.content or "").strip()
|
|
303
|
-
except Exception:
|
|
304
|
-
return "Insufficient context to comment usefully."
|
|
305
|
-
|
|
286
|
+
return "Insufficient context to comment usefully."
|
|
306
287
|
|
|
307
288
|
def wrap_html(card_text: str) -> str:
|
|
308
289
|
return f"""
|
|
@@ -14,7 +14,7 @@ from .file_processor import process_admin_pdf_files
|
|
|
14
14
|
from google.genai import types
|
|
15
15
|
from .vector_db import query_embeddings
|
|
16
16
|
from .vectorizer import embed_text
|
|
17
|
-
from syntaxmatrix.settings.prompts import
|
|
17
|
+
from syntaxmatrix.settings.prompts import SMXAI_CHAT_ID, SMXAI_CHAT_INSTRUCTIONS, SMX_WEBSITE_DESCRIPTION
|
|
18
18
|
from typing import List, Generator
|
|
19
19
|
from .auth import init_auth_db
|
|
20
20
|
from . import profiles as _prof
|
|
@@ -69,8 +69,8 @@ class SyntaxMUI:
|
|
|
69
69
|
self.ui_mode = ui_mode
|
|
70
70
|
self.theme_toggle_enabled = False
|
|
71
71
|
self.user_files_enabled = False
|
|
72
|
-
self.
|
|
73
|
-
self.
|
|
72
|
+
self.ai_chat_id = SMXAI_CHAT_ID
|
|
73
|
+
self.ai_chat_instructions = SMXAI_CHAT_INSTRUCTIONS
|
|
74
74
|
self.website_description = SMX_WEBSITE_DESCRIPTION
|
|
75
75
|
|
|
76
76
|
db.init_db()
|
|
@@ -443,11 +443,11 @@ class SyntaxMUI:
|
|
|
443
443
|
# *********** LLM CLIENT HELPERS **********************
|
|
444
444
|
# ──────────────────────────────────────────────────────────────
|
|
445
445
|
def set_prompt_profile(self, profile):
|
|
446
|
-
self.
|
|
446
|
+
self.ai_chat_id = profile
|
|
447
447
|
|
|
448
448
|
|
|
449
449
|
def set_prompt_instructions(self, instructions):
|
|
450
|
-
self.
|
|
450
|
+
self.ai_chat_instructions = instructions
|
|
451
451
|
|
|
452
452
|
|
|
453
453
|
def set_website_description(self, desc):
|
|
@@ -733,7 +733,7 @@ class SyntaxMUI:
|
|
|
733
733
|
_model = self._chat_profile['model']
|
|
734
734
|
|
|
735
735
|
_contents = f"""
|
|
736
|
-
{self.
|
|
736
|
+
{self.ai_chat_instructions}\n\n
|
|
737
737
|
Question: {query}\n
|
|
738
738
|
Context: {context}\n\n
|
|
739
739
|
History: {history}\n\n
|
|
@@ -746,7 +746,7 @@ class SyntaxMUI:
|
|
|
746
746
|
types.Content(
|
|
747
747
|
role="user",
|
|
748
748
|
parts=[
|
|
749
|
-
types.Part.from_text(text=f"{self.
|
|
749
|
+
types.Part.from_text(text=f"{self.ai_chat_id}\n\n{_contents}"),
|
|
750
750
|
],
|
|
751
751
|
),
|
|
752
752
|
]
|
|
@@ -759,14 +759,14 @@ class SyntaxMUI:
|
|
|
759
759
|
|
|
760
760
|
elif _provider == "openai" and _model in self.gpt_models_latest(): # GPt 5 series
|
|
761
761
|
input_prompt = (
|
|
762
|
-
f"{self.
|
|
762
|
+
f"{self.ai_chat_instructions}\n\n"
|
|
763
763
|
f"Generate a response to this query:\n{query}\n"
|
|
764
764
|
f"based on this given context:\n{context}\n\n"
|
|
765
765
|
f"(Use conversation continuity if available.)"
|
|
766
766
|
)
|
|
767
767
|
sid = self.get_session_id()
|
|
768
768
|
prev_id = self._gpt_models_latest_prev_resp_ids.get(sid)
|
|
769
|
-
args = set_args(model=_model, instructions=self.
|
|
769
|
+
args = set_args(model=_model, instructions=self.ai_chat_id, input=input_prompt, previous_id=prev_id, store=True)
|
|
770
770
|
|
|
771
771
|
with _client.responses.stream(**args) as s:
|
|
772
772
|
for event in s:
|
|
@@ -781,7 +781,7 @@ class SyntaxMUI:
|
|
|
781
781
|
elif _provider == "anthropic":
|
|
782
782
|
with _client.messages.stream(
|
|
783
783
|
max_tokens=1024,
|
|
784
|
-
messages=[{"role": "user", "content":f"{self.
|
|
784
|
+
messages=[{"role": "user", "content":f"{self.ai_chat_id}\n\n {_contents}"},],
|
|
785
785
|
model=_model,
|
|
786
786
|
) as stream:
|
|
787
787
|
for text in stream.text_stream:
|
|
@@ -790,15 +790,15 @@ class SyntaxMUI:
|
|
|
790
790
|
response = _client.messages.create(
|
|
791
791
|
model=_model,
|
|
792
792
|
max_tokens=1024,
|
|
793
|
-
system=self.
|
|
793
|
+
system=self.ai_chat_id,
|
|
794
794
|
messages=[{"role": "user", "content":_contents}],
|
|
795
795
|
stream=False,
|
|
796
796
|
)
|
|
797
797
|
|
|
798
798
|
else: # Assumes standard openai_sdk
|
|
799
799
|
openai_sdk_prompt = [
|
|
800
|
-
{"role": "system", "content": self.
|
|
801
|
-
{"role": "user", "content": f"{self.
|
|
800
|
+
{"role": "system", "content": self.ai_chat_id},
|
|
801
|
+
{"role": "user", "content": f"{self.ai_chat_instructions}\n\nGenerate response to this query: {query}\nbased on this context:\n{context}\nand history:\n{history}\n\nUse conversation continuity if available.)"},
|
|
802
802
|
]
|
|
803
803
|
response = _client.chat.completions.create(
|
|
804
804
|
model=_model,
|
|
@@ -818,7 +818,7 @@ class SyntaxMUI:
|
|
|
818
818
|
if not self._chat_profile:
|
|
819
819
|
chat_profile = _prof.get_profile("chat") or _prof.get_profile("admin")
|
|
820
820
|
if not chat_profile:
|
|
821
|
-
|
|
821
|
+
return """<p style='color:red;'>Error: Chat profile is not configured. Add a chat profile inside the admin panel or contact your administrator.</p>
|
|
822
822
|
"""
|
|
823
823
|
return
|
|
824
824
|
|
|
@@ -826,7 +826,7 @@ class SyntaxMUI:
|
|
|
826
826
|
self._chat_profile['client'] = _prof.get_client(chat_profile)
|
|
827
827
|
|
|
828
828
|
_contents = f"""
|
|
829
|
-
{self.
|
|
829
|
+
{self.ai_chat_instructions}\n\n
|
|
830
830
|
Question: {query}\n
|
|
831
831
|
Context: {context}\n\n
|
|
832
832
|
History: {history}\n\n
|
|
@@ -834,8 +834,8 @@ class SyntaxMUI:
|
|
|
834
834
|
"""
|
|
835
835
|
|
|
836
836
|
openai_sdk_prompt = [
|
|
837
|
-
{"role": "system", "content": self.
|
|
838
|
-
{"role": "user", "content": f"""{self.
|
|
837
|
+
{"role": "system", "content": self.ai_chat_id},
|
|
838
|
+
{"role": "user", "content": f"""{self.ai_chat_instructions}\n\n
|
|
839
839
|
Generate response to this query: {query}\n
|
|
840
840
|
based on this context:\n{context}\n
|
|
841
841
|
and history:\n{history}\n\n
|
|
@@ -852,7 +852,7 @@ class SyntaxMUI:
|
|
|
852
852
|
try:
|
|
853
853
|
response = _client.models.generate_content(
|
|
854
854
|
model=_model,
|
|
855
|
-
contents=f"{self.
|
|
855
|
+
contents=f"{self.ai_chat_id}\n\n{_contents}"
|
|
856
856
|
)
|
|
857
857
|
answer = response.text
|
|
858
858
|
|
|
@@ -867,7 +867,7 @@ class SyntaxMUI:
|
|
|
867
867
|
"""
|
|
868
868
|
# Prepare the prompt with conversation history and context
|
|
869
869
|
input = (
|
|
870
|
-
f"{self.
|
|
870
|
+
f"{self.ai_chat_instructions}\n\n"
|
|
871
871
|
f"Generate a response to this query:\n{query}\n"
|
|
872
872
|
f"based on this given context:\n{context}\n\n"
|
|
873
873
|
f"(Use conversation continuity if available.)"
|
|
@@ -878,7 +878,7 @@ class SyntaxMUI:
|
|
|
878
878
|
|
|
879
879
|
args = set_args(
|
|
880
880
|
model=_model,
|
|
881
|
-
instructions=self.
|
|
881
|
+
instructions=self.ai_chat_id,
|
|
882
882
|
input=input,
|
|
883
883
|
previous_id=prev_id,
|
|
884
884
|
store=True,
|
|
@@ -903,7 +903,7 @@ class SyntaxMUI:
|
|
|
903
903
|
response = _client.messages.create(
|
|
904
904
|
model=_model,
|
|
905
905
|
max_tokens=1024,
|
|
906
|
-
system=self.
|
|
906
|
+
system=self.ai_chat_id,
|
|
907
907
|
messages=[{"role": "user", "content":_contents}],
|
|
908
908
|
stream=False,
|
|
909
909
|
)
|
|
@@ -936,7 +936,7 @@ class SyntaxMUI:
|
|
|
936
936
|
return openai_sdk_process_query()
|
|
937
937
|
|
|
938
938
|
|
|
939
|
-
def ai_generate_code(self, question, df):
|
|
939
|
+
def ai_generate_code(self, question, intent, df):
|
|
940
940
|
|
|
941
941
|
if not self._coding_profile:
|
|
942
942
|
coding_profile = _prof.get_profile("coding") or _prof.get_profile("admin")
|
|
@@ -957,62 +957,53 @@ class SyntaxMUI:
|
|
|
957
957
|
_model = self._coding_profile['model']
|
|
958
958
|
|
|
959
959
|
context = f"Columns: {list(df.columns)}\n\nDtypes: {df.dtypes.astype(str).to_dict()}\n\n"
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
<Instruction for Generating Multiple Linear Regression Analysis Code>
|
|
963
|
-
You are a data science code generation assistant. Your task is to produce a complete, executable Python script that performs a multiple linear regression analysis based on a user's specific request, using a provided dataset (`df`).
|
|
964
|
-
|
|
965
|
-
<Steps to Generate the Code>
|
|
966
|
-
<dataset loading>:
|
|
967
|
-
Assume the dataset is accessible (e.g., via an uploaded file or a provided path).
|
|
968
|
-
Use pandas (pd) to load the dataset into a DataFrame named df. The specific loading command (pd.read_csv, etc.) should match the dataset's format as implied by the user (e.g., if the user mentions diabetes_dataset.csv, use pd.read_csv('diabetes_dataset.csv')).
|
|
969
|
-
Print the first few rows (df.head()) and descriptive statistics (df.describe()) of the loaded DataFrame to verify successful loading.
|
|
970
|
-
|
|
971
|
-
<Variable Identification>:
|
|
972
|
-
<carefully analyze the user's query to identify>:
|
|
973
|
-
The target variable (dependent variable) to be predicted (e.g., "predict the level of the liver enzyme GGT").
|
|
974
|
-
The specific predictor variables (independent variables) to be used in the model (e.g., "BMI, Waist_Circumference, Alcohol_Consumption, and HbA1c").
|
|
975
|
-
Examine the column names of the loaded DataFrame (df.columns) to find the exact column names corresponding to the variables identified in the query. Ensure the column names used in the code exactly match those in the dataset.
|
|
976
|
-
|
|
977
|
-
<Data Preparation>:
|
|
978
|
-
Select the identified predictor variables and create a feature matrix X.
|
|
979
|
-
Select the identified target variable and create a target vector y.
|
|
980
|
-
Handle any potential missing values if necessary (e.g., using dropna() or imputation, though for simplicity, dropping rows with missing values in relevant columns is often acceptable for initial analysis).
|
|
981
|
-
|
|
982
|
-
<Model Creation and Training>:
|
|
983
|
-
Import necessary modules from sklearn (train_test_split, LinearRegression, mean_squared_error, r2_score).
|
|
984
|
-
Split the data into training and testing sets using train_test_split (e.g., 80% train, 20% test).
|
|
985
|
-
Instantiate a LinearRegression model.
|
|
986
|
-
Fit the model to the training data (model.fit(X_train, y_train)).
|
|
987
|
-
Model Evaluation:
|
|
988
|
-
Use the trained model to make predictions on the test set (y_pred = model.predict(X_test)).
|
|
989
|
-
Calculate performance metrics like R-squared (r2_score) and Mean Squared Error (mean_squared_error) to evaluate how well the model fits the data on the test set.
|
|
990
|
-
|
|
991
|
-
<Result Interpretation>:
|
|
992
|
-
Extract the model's coefficients (model.coef_) and intercept (model.intercept_).
|
|
993
|
-
Print the intercept and a list of feature names paired with their corresponding coefficients.
|
|
994
|
-
Calculate the absolute values of the coefficients to assess the relative importance of each predictor variable.
|
|
995
|
-
Provide a clear interpretation:
|
|
996
|
-
Explain what each coefficient means in the context of the problem (e.g., "A 1 unit increase in [Feature Name], holding other variables constant, is associated with a [Coefficient Value] unit change in [Target Variable Name]").
|
|
997
|
-
Rank the predictor variables by the absolute value of their coefficients to indicate their relative contribution to the prediction.
|
|
998
|
-
|
|
999
|
-
<Output Formatting>:
|
|
1000
|
-
Structure the printed output clearly using section headers (e.g., "=== Multiple Linear Regression Results ===", "=== Interpretation ===").
|
|
1001
|
-
Ensure the final code is self-contained, uses appropriate variable names, and includes necessary import statements.
|
|
1002
|
-
Add a comment reminding the user to ensure column names match their actual dataset if they adapt the code.
|
|
1003
|
-
"""
|
|
1004
|
-
|
|
960
|
+
ALLOWED_COLUMNS = list(df.columns)
|
|
961
|
+
|
|
1005
962
|
ai_profile = f"""
|
|
1006
|
-
You are a
|
|
963
|
+
You are a senior Python data scientist writing production-quality, **runnable** code for a Jupyter-like kernel. You are given a pandas DataFrame named `df`. Begin ONLY the data already in `df` (no file I/O).
|
|
1007
964
|
"""
|
|
1008
965
|
|
|
1009
966
|
instructions = f"""
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
967
|
+
### Context
|
|
968
|
+
- Schema (names → dtypes): {context}
|
|
969
|
+
- Row count: {len(df)}
|
|
970
|
+
- Task: {question}
|
|
971
|
+
- Task type: {intent}
|
|
972
|
+
- Allowed columns: {ALLOWED_COLUMNS}
|
|
973
|
+
|
|
974
|
+
### Hard requirements
|
|
975
|
+
1) **Code only**. No markdown, no comments, no explanations.
|
|
976
|
+
2) Import everything you use explicitly. Assume: pandas≥2, numpy≥1.25, matplotlib≥3.8, seaborn≥0.13, scikit-learn≥1.4 are available.
|
|
977
|
+
3) **Avoid deprecated / removed APIs**, e.g.:
|
|
978
|
+
- pandas: do not use `.append`, `.ix`, `.as_matrix`, `DataFrame.select_dtypes(include='category')` is OK, but prefer current patterns.
|
|
979
|
+
- seaborn: do not use `distplot`, `pairplot` on very large data without sampling; prefer `histplot`, `displot`, `regplot`, or FacetGrid with `.map_dataframe`.
|
|
980
|
+
- scikit-learn: import from `sklearn.model_selection` (not `sklearn.cross_validation`); for confusion matrices use `ConfusionMatrixDisplay.from_estimator`; set `random_state=42` where relevant.
|
|
981
|
+
4) Be **defensive**:
|
|
982
|
+
- Verify required columns exist; if any are missing, raise `ValueError("Missing columns: ...")` early.
|
|
983
|
+
- Handle missing values sensibly (e.g., drop rows for simple EDA; use `ColumnTransformer` + `SimpleImputer` for modeling).
|
|
984
|
+
- For categorical features in ML, use `OneHotEncoder(handle_unknown="ignore")` inside a `Pipeline`/`ColumnTransformer` (no `LabelEncoder` on features).
|
|
985
|
+
5) Keep it **fast** (kernel timeout ~8s):
|
|
986
|
+
- For plots on large frames (>20k rows), downsample to ~1,000 rows (`df.sample(1000, random_state=42)`) unless aggregation is more appropriate.
|
|
987
|
+
- Prefer vectorized ops; avoid O(n²) Python loops.
|
|
988
|
+
6) Always **produce at least one visible result** at the end:
|
|
989
|
+
- If plotting with matplotlib/seaborn: call `plt.tight_layout(); plt.show()`.
|
|
990
|
+
- If producing a table or metrics: from `syntaxmatrix.display import show` then `show(object_or_dataframe)`.
|
|
991
|
+
7) Follow task type conventions:
|
|
992
|
+
- **EDA/Stats**: compute the requested stat, then show a relevant table (e.g., summary/crosstab) or plot.
|
|
993
|
+
- **Classification**: train/valid split (`train_test_split`), build a pipeline with scaling/encoding as needed, fit, show accuracy **and** a confusion matrix via `ConfusionMatrixDisplay.from_estimator(...); plt.show()`. Also show `classification_report` as a dataframe if short.
|
|
994
|
+
- **Regression**: train/valid split, pipeline as needed, fit, show R² and MAE; plot predicted vs actual scatter.
|
|
995
|
+
- **Correlation/Chi-square/ANOVA**: compute the statistic + p-value and show a concise result table (with `show(...)`) and, when sensible, a small plot (heatmap/bar).
|
|
996
|
+
8) Don't mutate or recreate target columns if they already exist (e.g., if asked to “predict TARGET”, use `y = df['TARGET']` as-is).
|
|
997
|
+
9) Keep variable names short and clear; prefer `num_cols` / `cat_cols` discovery by dtype.
|
|
998
|
+
10) You MUST NOT reference any column outside Allowed columns: {ALLOWED_COLUMNS}\n.
|
|
999
|
+
11) If asked to predict/classify, choose the target by matching the task text to Allowed columns: {ALLOWED_COLUMNS}\n and never invent a new name (e.g., 'whether', 'the').
|
|
1000
|
+
|
|
1001
|
+
### Output
|
|
1002
|
+
Return **only runnable Python** that:
|
|
1003
|
+
- Imports what it needs,
|
|
1004
|
+
- Validates columns,
|
|
1005
|
+
- Solves: {question},
|
|
1006
|
+
- And ends with at least one visible output (`show(...)` and/or `plt.show()`).
|
|
1016
1007
|
"""
|
|
1017
1008
|
|
|
1018
1009
|
def google_generate_code():
|
|
@@ -1059,7 +1050,7 @@ class SyntaxMUI:
|
|
|
1059
1050
|
{"role": "system", "content": ai_profile},
|
|
1060
1051
|
{"role": "user", "content": instructions},
|
|
1061
1052
|
],
|
|
1062
|
-
temperature=0.
|
|
1053
|
+
temperature=0.3,
|
|
1063
1054
|
max_tokens=2048,
|
|
1064
1055
|
)
|
|
1065
1056
|
return response.choices[0].message.content
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -----------------------------------------------------------------
|
|
2
|
+
# Paste *inside* syntaxmatrix/display.py – only the show() body
|
|
3
|
+
# -----------------------------------------------------------------
|
|
4
|
+
def show(obj):
|
|
5
|
+
"""
|
|
6
|
+
Render common objects so the Dashboard (or chat) always shows output.
|
|
7
|
+
"""
|
|
8
|
+
import io, base64, numbers
|
|
9
|
+
from IPython.display import display, HTML
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import matplotlib.figure as mpfig
|
|
12
|
+
|
|
13
|
+
# ── matplotlib Figure ─────────────────────────────────────────
|
|
14
|
+
if isinstance(obj, mpfig.Figure):
|
|
15
|
+
display(obj)
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
if isinstance(obj, (pd.Series, pd.DataFrame)):
|
|
19
|
+
|
|
20
|
+
html = obj.to_html(classes="smx-table", border=0)
|
|
21
|
+
wrapped_html = (
|
|
22
|
+
"<style>"
|
|
23
|
+
".smx-table{border-collapse:collapse;font-size:0.9em;white-space:nowrap;}"
|
|
24
|
+
".smx-table th{background:#f0f2f5;text-align:left;padding:6px 8px;border:1px solid gray;}"
|
|
25
|
+
".smx-table td{border:1px solid #ddd;padding:6px 8px;}"
|
|
26
|
+
".smx-table tbody tr:nth-child(even){background-color:#f9f9f9;}"
|
|
27
|
+
"</style>"
|
|
28
|
+
"<div style='overflow-x:auto; max-width:100%; margin-bottom:1rem;'>"
|
|
29
|
+
+ html +
|
|
30
|
+
"</div>"
|
|
31
|
+
)
|
|
32
|
+
display(HTML(wrapped_html))
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
# ── dict of scalars → pretty 2-col table ─────────────────────
|
|
36
|
+
if isinstance(obj, dict) and all(isinstance(v, numbers.Number) for v in obj.values()):
|
|
37
|
+
df_ = pd.DataFrame({"metric": list(obj.keys()),
|
|
38
|
+
"value": list(obj.values())})
|
|
39
|
+
display(df_)
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
# ── 2-tuple of numbers (mse, r²) ─────────────────────────────
|
|
43
|
+
if (isinstance(obj, tuple) and len(obj) == 2 and
|
|
44
|
+
all(isinstance(v, numbers.Number) for v in obj)):
|
|
45
|
+
mse, r2 = obj
|
|
46
|
+
df_ = pd.DataFrame({"metric": ["Mean-squared error", "R²"],
|
|
47
|
+
"value": [mse, r2]})
|
|
48
|
+
display(df_)
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
# ── fallback ─────────────────────────────────────────────────
|
|
52
|
+
display(HTML(f"<pre>{obj}</pre>"))
|
|
53
|
+
|
|
54
|
+
return None
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import jupyter_client
|
|
4
4
|
import nest_asyncio
|
|
5
|
-
import
|
|
6
|
-
import time
|
|
7
|
-
import re
|
|
5
|
+
import io, contextlib
|
|
6
|
+
import time
|
|
8
7
|
from functools import wraps
|
|
9
8
|
import inspect, pandas as _pd
|
|
10
|
-
|
|
9
|
+
from functools import wraps
|
|
10
|
+
import inspect, pandas as _pd
|
|
11
|
+
import io, contextlib
|
|
12
|
+
import html as _html
|
|
13
|
+
import re as _re
|
|
11
14
|
|
|
12
15
|
nest_asyncio.apply()
|
|
13
16
|
|
|
@@ -42,11 +45,13 @@ class SyntaxMatrixKernelManager:
|
|
|
42
45
|
for sid in list(cls._kernels):
|
|
43
46
|
cls.shutdown_kernel(sid)
|
|
44
47
|
|
|
45
|
-
nest_asyncio.apply()
|
|
46
48
|
|
|
47
49
|
_df_cache = None
|
|
48
50
|
|
|
49
|
-
def execute_code_in_kernel(kc, code, timeout=
|
|
51
|
+
def execute_code_in_kernel(kc, code, timeout=90):
|
|
52
|
+
|
|
53
|
+
_local_stdout = ""
|
|
54
|
+
_local_stderr = ""
|
|
50
55
|
|
|
51
56
|
global _df_cache
|
|
52
57
|
exec_namespace = {}
|
|
@@ -134,7 +139,13 @@ def execute_code_in_kernel(kc, code, timeout=None):
|
|
|
134
139
|
exec_namespace["df"] = _df_cache
|
|
135
140
|
|
|
136
141
|
try:
|
|
137
|
-
|
|
142
|
+
# Prevent any print()/stdout/stderr from hitting your server console
|
|
143
|
+
_buf_out, _buf_err = io.StringIO(), io.StringIO()
|
|
144
|
+
with contextlib.redirect_stdout(_buf_out), contextlib.redirect_stderr(_buf_err):
|
|
145
|
+
exec(code, exec_namespace, exec_namespace)
|
|
146
|
+
|
|
147
|
+
_local_stdout = _buf_out.getvalue()
|
|
148
|
+
_local_stderr = _buf_err.getvalue()
|
|
138
149
|
|
|
139
150
|
# ── show a friendly “missing package” hint ────
|
|
140
151
|
except (ModuleNotFoundError, ImportError) as e:
|
|
@@ -152,7 +163,7 @@ def execute_code_in_kernel(kc, code, timeout=None):
|
|
|
152
163
|
except Exception:
|
|
153
164
|
pass
|
|
154
165
|
|
|
155
|
-
|
|
166
|
+
# cache df for next call
|
|
156
167
|
if "df" in exec_namespace:
|
|
157
168
|
_df_cache = exec_namespace["df"]
|
|
158
169
|
|
|
@@ -172,7 +183,6 @@ def execute_code_in_kernel(kc, code, timeout=None):
|
|
|
172
183
|
|
|
173
184
|
while True:
|
|
174
185
|
# Block until a message is available; if `timeout` is None this will block.
|
|
175
|
-
# (You can set a numeric timeout here if you want a failsafe.)
|
|
176
186
|
try:
|
|
177
187
|
msg = kc.get_iopub_msg(timeout=timeout)
|
|
178
188
|
except Exception:
|
|
@@ -186,24 +196,88 @@ def execute_code_in_kernel(kc, code, timeout=None):
|
|
|
186
196
|
if mtype == 'status' and content.get('execution_state') == 'idle':
|
|
187
197
|
break
|
|
188
198
|
|
|
199
|
+
# if mtype == "stream":
|
|
200
|
+
# output_blocks.append(f"<pre>{content['text']}</pre>")
|
|
201
|
+
|
|
189
202
|
if mtype == "stream":
|
|
190
|
-
|
|
203
|
+
raw = content.get("text", "")
|
|
204
|
+
# Remove noisy reprs from printed HTML/Markdown display objects
|
|
205
|
+
lines = [
|
|
206
|
+
ln for ln in raw.splitlines()
|
|
207
|
+
if ("IPython.core.display.HTML object" not in ln
|
|
208
|
+
and "IPython.core.display.Markdown object" not in ln)
|
|
209
|
+
]
|
|
210
|
+
txt = "\n".join(lines).strip()
|
|
211
|
+
if txt:
|
|
212
|
+
output_blocks.append(f"<pre>{_html.escape(txt)}</pre>")
|
|
213
|
+
|
|
214
|
+
# elif mtype in ("execute_result", "display_data"):
|
|
215
|
+
# data = content["data"]
|
|
216
|
+
# if "text/html" in data:
|
|
217
|
+
# output_blocks.append(data["text/html"])
|
|
218
|
+
# elif "image/png" in data:
|
|
219
|
+
# output_blocks.append(
|
|
220
|
+
# f"<img src='data:image/png;base64,{data['image/png']}' "
|
|
221
|
+
# f"style='max-width:100%;'/>"
|
|
222
|
+
# )
|
|
223
|
+
# else:
|
|
224
|
+
# output_blocks.append(f"<pre>{data.get('text/plain','')}</pre>")
|
|
191
225
|
|
|
192
226
|
elif mtype in ("execute_result", "display_data"):
|
|
193
|
-
data = content
|
|
227
|
+
data = content.get("data", {})
|
|
194
228
|
if "text/html" in data:
|
|
195
|
-
|
|
229
|
+
output_blocks.append(data["text/html"])
|
|
196
230
|
elif "image/png" in data:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
231
|
+
output_blocks.append(
|
|
232
|
+
f"<img src='data:image/png;base64,{data['image/png']}' "
|
|
233
|
+
f"style='max-width:100%;'/>"
|
|
234
|
+
)
|
|
235
|
+
|
|
201
236
|
else:
|
|
202
|
-
|
|
237
|
+
# Clean up plain-text reprs like "<IPython.core.display.HTML object>"
|
|
238
|
+
txt = data.get("text/plain", "") or ""
|
|
239
|
+
if ("IPython.core.display.HTML object" in txt
|
|
240
|
+
or "IPython.core.display.Markdown object" in txt):
|
|
241
|
+
# skip useless reprs entirely
|
|
242
|
+
continue
|
|
243
|
+
output_blocks.append(f"<pre>{_html.escape(txt)}</pre>")
|
|
203
244
|
|
|
204
245
|
elif mtype == "error":
|
|
205
246
|
# keep the traceback html-friendly
|
|
206
247
|
traceback_html = "<br>".join(content["traceback"])
|
|
207
248
|
errors.append(f"<pre style='color:red;'>{traceback_html}</pre>")
|
|
249
|
+
# --- surface the locally captured commentary (stdout/stderr) back to the UI ---
|
|
250
|
+
if _local_stdout.strip():
|
|
251
|
+
# Put commentary first so the user sees it above plots/tables
|
|
252
|
+
output_blocks.insert(0, f"<pre>{_html.escape(_local_stdout)}</pre>")
|
|
253
|
+
if _local_stderr.strip():
|
|
254
|
+
errors.insert(0, f"<pre style='color:#b00;'>{_html.escape(_local_stderr)}</pre>")
|
|
255
|
+
|
|
256
|
+
def _smx_strip_display_reprs(text: str) -> str:
|
|
257
|
+
if not text:
|
|
258
|
+
return text
|
|
259
|
+
# remove tokens like "<IPython.core.display.HTML object>"
|
|
260
|
+
text = _re.sub(r"<IPython\.core\.display\.[A-Za-z]+\s+object>", "", text)
|
|
261
|
+
# if these were printed as lists, remove leftover brackets/commas
|
|
262
|
+
text = _re.sub(r"[\[\],]", " ", text)
|
|
263
|
+
# collapse whitespace
|
|
264
|
+
text = _re.sub(r"\s+", " ", text).strip()
|
|
265
|
+
return text
|
|
266
|
+
|
|
267
|
+
_cleaned_blocks = []
|
|
268
|
+
for blk in output_blocks:
|
|
269
|
+
# pre-wrapped plaintext
|
|
270
|
+
if blk.startswith("<pre>") and blk.endswith("</pre>"):
|
|
271
|
+
inner = blk[5:-6]
|
|
272
|
+
inner = _smx_strip_display_reprs(_html.unescape(inner))
|
|
273
|
+
if inner:
|
|
274
|
+
_cleaned_blocks.append(f"<pre>{_html.escape(inner)}</pre>")
|
|
275
|
+
# if empty after cleaning, drop it
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
# html/img payloads: just remove stray repr tokens if they slipped in
|
|
279
|
+
cleaned = _re.sub(r"<IPython\.core\.display\.[A-Za-z]+\s+object>", "", blk)
|
|
280
|
+
_cleaned_blocks.append(cleaned)
|
|
281
|
+
output_blocks = _cleaned_blocks
|
|
208
282
|
|
|
209
283
|
return output_blocks, errors
|