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.
Files changed (71) hide show
  1. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/PKG-INFO +1 -1
  2. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/PKG-INFO +1 -1
  3. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/SOURCES.txt +1 -1
  4. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/setup.py +1 -1
  5. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/commentary.py +18 -37
  6. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/core.py +66 -75
  7. syntaxmatrix-2.2.5/syntaxmatrix/display.py +54 -0
  8. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/kernel_manager.py +91 -17
  9. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/routes.py +168 -54
  10. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/prompts.py +18 -74
  11. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/docs.md +2 -2
  12. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/dashboard.html +59 -8
  13. syntaxmatrix-2.2.5/syntaxmatrix/templates/docs.html +72 -0
  14. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/utils.py +41 -0
  15. syntaxmatrix-2.2.3/syntaxmatrix/display.py +0 -132
  16. syntaxmatrix-2.2.3/syntaxmatrix/templates/docs_page_embed.html +0 -20
  17. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/LICENSE.txt +0 -0
  18. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/README.md +0 -0
  19. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/dependency_links.txt +0 -0
  20. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/requires.txt +0 -0
  21. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/SyntaxMatrix.egg-info/top_level.txt +0 -0
  22. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/pyproject.toml +0 -0
  23. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/setup.cfg +0 -0
  24. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/__init__.py +0 -0
  25. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/auth.py +0 -0
  26. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/bootstrap.py +0 -0
  27. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/db.py +0 -0
  28. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/emailer.py +0 -0
  29. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/file_processor.py +0 -0
  30. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/generate_page.py +0 -0
  31. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/gpt_models_latest.py +0 -0
  32. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/history_store.py +0 -0
  33. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/llm_store.py +0 -0
  34. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/model_templates.py +0 -0
  35. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/models.py +0 -0
  36. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/plottings.py +0 -0
  37. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/profiles.py +0 -0
  38. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/project_root.py +0 -0
  39. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/session.py +0 -0
  40. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/__init__.py +0 -0
  41. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/default.yaml +0 -0
  42. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/logging.py +0 -0
  43. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/model_map.py +0 -0
  44. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/settings/string_navbar.py +0 -0
  45. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/smiv.py +0 -0
  46. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/smpv.py +0 -0
  47. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/css/style.css +0 -0
  48. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/favicon.png +0 -0
  49. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/hero_bg.jpg +0 -0
  50. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/logo.png +0 -0
  51. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/svg_497526.svg +0 -0
  52. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/icons/svg_497528.svg +0 -0
  53. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/chat.js +0 -0
  54. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/sidebar.js +0 -0
  55. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/static/js/widgets.js +0 -0
  56. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/code_cell.html +0 -0
  57. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/error.html +0 -0
  58. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/login.html +0 -0
  59. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/templates/register.html +0 -0
  60. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/themes.py +0 -0
  61. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/ui_modes.py +0 -0
  62. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vector_db.py +0 -0
  63. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/__init__.py +0 -0
  64. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/__init__.py +0 -0
  65. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/milvus_adapter.py +0 -0
  66. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/pgvector_adapter.py +0 -0
  67. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/adapters/sqlite_adapter.py +0 -0
  68. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/base.py +0 -0
  69. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectordb/registry.py +0 -0
  70. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/vectorizer.py +0 -0
  71. {syntaxmatrix-2.2.3 → syntaxmatrix-2.2.5}/syntaxmatrix/workspace_db.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syntaxmatrix
3
- Version: 2.2.3
3
+ Version: 2.2.5
4
4
  Summary: SyntaxMUI: A customizable framework for Python AI Assistant Projects.
5
5
  Home-page: https://github.com/bobganti/syntaxmatrix_demo
6
6
  Author: Bob Nti
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syntaxmatrix
3
- Version: 2.2.3
3
+ Version: 2.2.5
4
4
  Summary: SyntaxMUI: A customizable framework for Python AI Assistant Projects.
5
5
  Home-page: https://github.com/bobganti/syntaxmatrix_demo
6
6
  Author: Bob Nti
@@ -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/docs_page_embed.html
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.3",
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 (~140-200 words) with:
173
- - Headline (one sentence answering the question).
174
- - Evidence (4-5 bullets referencing panels/axes/legend groups seen in the figures).
175
- - Limitations (1-2 bullets; avoid quoting numbers unless present in context).
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("vision2text") or _prof.get_profile("admin")
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 'Vision2Text'. Please contact your Administrator."
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 GenAI (Gemini) — multimodal
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
- pass # fall through to text-only
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
- # If the Responses path fails for any reason, fall through to the
244
- # chat.completions fallback implemented below.
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
- pass # fall through
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.2,
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
- pass # fall through
283
+ pass # Fall through to the chat.completions fallback implemented below.
284
284
 
285
285
  # Text-only fallback via Responses API
286
- try:
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 SMX_PROMPT_PROFILE, SMX_PROMPT_INSTRUCTIONS, SMX_WEBSITE_DESCRIPTION
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.prompt_profile = SMX_PROMPT_PROFILE
73
- self.prompt_instructions = SMX_PROMPT_INSTRUCTIONS
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.prompt_profile = profile
446
+ self.ai_chat_id = profile
447
447
 
448
448
 
449
449
  def set_prompt_instructions(self, instructions):
450
- self.prompt_instructions = instructions
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.prompt_instructions}\n\n
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.prompt_profile}\n\n{_contents}"),
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.prompt_instructions}\n\n"
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.prompt_profile, input=input_prompt, previous_id=prev_id, store=True)
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.prompt_profile}\n\n {_contents}"},],
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.prompt_profile,
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.prompt_profile},
801
- {"role": "user", "content": f"{self.prompt_instructions}\n\nGenerate response to this query: {query}\nbased on this context:\n{context}\nand history:\n{history}\n\nUse conversation continuity if available.)"},
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
- yield """<p style='color:red;'>Error: Chat profile is not configured. Add a chat profile inside the admin panel or contact your administrator.</p>
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.prompt_instructions}\n\n
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.prompt_profile},
838
- {"role": "user", "content": f"""{self.prompt_instructions}\n\n
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.prompt_profile}\n\n{_contents}"
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.prompt_instructions}\n\n"
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.prompt_profile,
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.prompt_profile,
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
- Linear_regression = """
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 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`).
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
- Write clean, working Python code that answers the question below.
1011
- DO NOT explain, just output the code only.
1012
- Question: {question}\n
1013
- Context: {context}\n\n
1014
- Output only the working code needed. Assume df is already defined.
1015
- Produce at least one visible result: (syntaxmatrix.display.show(), display(), plt.show()).
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.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 uuid
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=None):
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
- exec(code, exec_namespace, exec_namespace)
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
- # cache df for next call
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
- output_blocks.append(f"<pre>{content['text']}</pre>")
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["data"]
227
+ data = content.get("data", {})
194
228
  if "text/html" in data:
195
- output_blocks.append(data["text/html"])
229
+ output_blocks.append(data["text/html"])
196
230
  elif "image/png" in data:
197
- output_blocks.append(
198
- f"<img src='data:image/png;base64,{data['image/png']}' "
199
- f"style='max-width:100%;'/>"
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
- output_blocks.append(f"<pre>{data.get('text/plain','')}</pre>")
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