crystalwindow 4.2__py3-none-any.whl → 4.4__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.
- crystalwindow/ai.py +112 -80
- {crystalwindow-4.2.dist-info → crystalwindow-4.4.dist-info}/METADATA +1 -1
- {crystalwindow-4.2.dist-info → crystalwindow-4.4.dist-info}/RECORD +6 -6
- {crystalwindow-4.2.dist-info → crystalwindow-4.4.dist-info}/WHEEL +0 -0
- {crystalwindow-4.2.dist-info → crystalwindow-4.4.dist-info}/licenses/LICENSE +0 -0
- {crystalwindow-4.2.dist-info → crystalwindow-4.4.dist-info}/top_level.txt +0 -0
crystalwindow/ai.py
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
# ==========================================================
|
|
2
|
-
# CrystalAI v0.
|
|
2
|
+
# CrystalAI v0.8 — Hybrid Engine (Groq + Symbolic Fallback)
|
|
3
3
|
# ----------------------------------------------------------
|
|
4
4
|
# Combines:
|
|
5
|
-
# -
|
|
6
|
-
# -
|
|
7
|
-
# -
|
|
5
|
+
# - Groq API for general knowledge (Primary)
|
|
6
|
+
# - Pure Python Symbolic Engine for Code Analysis (Fallback)
|
|
7
|
+
# - Memory, File Reading, AST Parsing, and Diff Utilities
|
|
8
8
|
# ==========================================================
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
import ast
|
|
12
12
|
import difflib
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
|
|
13
|
+
import requests # Re-added for API communication
|
|
14
|
+
from typing import Optional, Dict, Any, List
|
|
15
|
+
# Removed groq import, using requests for simplicity
|
|
17
16
|
|
|
18
17
|
# ==========================================================
|
|
19
18
|
# Response Wrapper
|
|
@@ -34,10 +33,11 @@ class AI:
|
|
|
34
33
|
DEFAULT_MODEL = "llama-3.1-8b"
|
|
35
34
|
DEFAULT_PERSONALITY = (
|
|
36
35
|
"You are CrystalWindow AI. You help users with Python code, "
|
|
37
|
-
"debugging, errors, docs, and file analysis. "
|
|
38
|
-
"Be friendly, technical, clear, and precise."
|
|
36
|
+
"debugging, errors, docs, and file analysis. You are currently running in "
|
|
37
|
+
"Hybrid Mode. Be friendly, technical, clear, and precise."
|
|
39
38
|
)
|
|
40
|
-
|
|
39
|
+
# Placeholder Key for testing or when user key is invalid
|
|
40
|
+
PLACEHOLDER_KEY = "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"
|
|
41
41
|
|
|
42
42
|
# ------------------------------------------------------
|
|
43
43
|
def __init__(self, key=None, model=None):
|
|
@@ -47,10 +47,10 @@ class AI:
|
|
|
47
47
|
self.key = self.PLACEHOLDER_KEY
|
|
48
48
|
else:
|
|
49
49
|
self.key = key
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
# --- MODEL VALIDATION ---
|
|
52
52
|
if not model or not isinstance(model, str) or len(model) < 3:
|
|
53
|
-
print("[CrystalAI] Unknown model → using default.")
|
|
53
|
+
print(f"[CrystalAI] Unknown model → using default: {self.DEFAULT_MODEL}.")
|
|
54
54
|
self.model = self.DEFAULT_MODEL
|
|
55
55
|
else:
|
|
56
56
|
self.model = model
|
|
@@ -58,22 +58,25 @@ class AI:
|
|
|
58
58
|
# Persona
|
|
59
59
|
self.personality = self.DEFAULT_PERSONALITY
|
|
60
60
|
|
|
61
|
+
# Pure AI knowledge (used in symbolic fallback)
|
|
62
|
+
self.knowledge_graph: Dict[str, Any] = self._build_knowledge_graph()
|
|
63
|
+
|
|
61
64
|
# Library knowledge (loaded .py files)
|
|
62
65
|
self.library_context = ""
|
|
63
66
|
|
|
64
|
-
#
|
|
65
|
-
self.memory = []
|
|
67
|
+
# Memory system
|
|
68
|
+
self.memory: List[Dict[str, str]] = []
|
|
66
69
|
self.use_memory = True
|
|
67
70
|
|
|
68
|
-
#
|
|
69
|
-
self.force_local = False
|
|
71
|
+
# Force local toggle (currently not used as logic is based on Groq success)
|
|
72
|
+
self.force_local = False
|
|
70
73
|
|
|
71
74
|
# ==========================================================
|
|
72
75
|
# PERSONALITY
|
|
73
76
|
# ==========================================================
|
|
74
77
|
def set_personality(self, txt):
|
|
75
78
|
if not isinstance(txt, str) or len(txt.strip()) < 10:
|
|
76
|
-
print("Oops!
|
|
79
|
+
print("Oops! that's not how to use it—reverting to default.")
|
|
77
80
|
self.personality = self.DEFAULT_PERSONALITY
|
|
78
81
|
return
|
|
79
82
|
|
|
@@ -103,7 +106,7 @@ class AI:
|
|
|
103
106
|
path = os.path.join(root, f)
|
|
104
107
|
with open(path, "r", encoding="utf8") as fp:
|
|
105
108
|
out.append(f"# FILE: {path}\n" + fp.read() + "\n\n")
|
|
106
|
-
except:
|
|
109
|
+
except Exception:
|
|
107
110
|
pass
|
|
108
111
|
|
|
109
112
|
self.library_context = "\n".join(out)
|
|
@@ -119,8 +122,8 @@ class AI:
|
|
|
119
122
|
try:
|
|
120
123
|
with open(path, "r", encoding="utf8") as f:
|
|
121
124
|
return f.read()
|
|
122
|
-
except:
|
|
123
|
-
return "[CrystalAI]
|
|
125
|
+
except Exception:
|
|
126
|
+
return "[CrystalAI] couldn't read file."
|
|
124
127
|
|
|
125
128
|
# ==========================================================
|
|
126
129
|
# PROMPT BUILDER (Unified)
|
|
@@ -151,74 +154,98 @@ class AI:
|
|
|
151
154
|
self.memory.pop(0)
|
|
152
155
|
|
|
153
156
|
# ==========================================================
|
|
154
|
-
#
|
|
157
|
+
# PURE AI KNOWLEDGE BASE (Symbolic Core)
|
|
158
|
+
# ==========================================================
|
|
159
|
+
def _build_knowledge_graph(self) -> Dict[str, Any]:
|
|
160
|
+
"""
|
|
161
|
+
Defines the internal knowledge the symbolic AI can reason with.
|
|
162
|
+
"""
|
|
163
|
+
return {
|
|
164
|
+
"python": {
|
|
165
|
+
"desc": "A high-level, interpreted programming language.",
|
|
166
|
+
"keywords": ["language", "interpreted", "high-level"],
|
|
167
|
+
"syntax": {
|
|
168
|
+
"if_statement": "if condition: ... else: ...",
|
|
169
|
+
"loop": "for item in iterable: ..."
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"ast": {
|
|
173
|
+
"desc": "Abstract Syntax Tree. Used for parsing code structure.",
|
|
174
|
+
"keywords": ["parsing", "code", "structure", "tree"]
|
|
175
|
+
},
|
|
176
|
+
"fix_code": {
|
|
177
|
+
"rule": "look for SyntaxError, especially missing colons or mismatched brackets",
|
|
178
|
+
"keywords": ["fix", "error", "bug", "syntax"]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# ==========================================================
|
|
183
|
+
# PURE AI 'THINKING' ENGINE (Symbolic Fallback)
|
|
155
184
|
# ==========================================================
|
|
156
|
-
def
|
|
185
|
+
def _symbolic_engine(self, prompt: str, file_data: Optional[str]) -> str:
|
|
157
186
|
"""
|
|
158
|
-
|
|
159
|
-
- If file provided → real AST analysis
|
|
160
|
-
- If general question → helpful offline response
|
|
161
|
-
- No more random jokes or irrelevant "forgot a colon"
|
|
187
|
+
Fallback logic: Simulates 'thinking' using only internal rules and AST.
|
|
162
188
|
"""
|
|
189
|
+
output = ["[Local/SymbolicEngine] Processing request..."]
|
|
190
|
+
lower_prompt = prompt.lower()
|
|
163
191
|
|
|
164
|
-
# ---
|
|
192
|
+
# --- Stage 1: File Analysis (Real Python AST) ---
|
|
165
193
|
if file_data and not file_data.startswith("[CrystalAI]"):
|
|
194
|
+
output.append("\n[Stage 1: Code Parsing]")
|
|
166
195
|
try:
|
|
167
196
|
ast.parse(file_data)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"Ask me to explain, summarize, refactor, or improve something."
|
|
172
|
-
)
|
|
197
|
+
output.append("✅ **No Syntax Errors Detected** (via AST).")
|
|
198
|
+
output.append("The code is structurally sound. Ask for refactoring or explanation.")
|
|
199
|
+
return "\n".join(output)
|
|
173
200
|
except SyntaxError as se:
|
|
201
|
+
fix_rule = self.knowledge_graph["fix_code"]["rule"]
|
|
174
202
|
lineno = se.lineno or 0
|
|
175
|
-
offset = se.offset or 0
|
|
176
203
|
msg = (
|
|
177
|
-
f"
|
|
204
|
+
f"❌ **SyntaxError Detected** (via AST):\n"
|
|
178
205
|
f"• Message: {se.msg}\n"
|
|
179
206
|
f"• Line: {lineno}\n"
|
|
180
|
-
f"•
|
|
207
|
+
f"• Rule suggestion: {fix_rule}"
|
|
181
208
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
"
|
|
195
|
-
"
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
output.append(msg)
|
|
210
|
+
output.append(self._snippet(file_data, lineno))
|
|
211
|
+
return "\n".join(output)
|
|
212
|
+
|
|
213
|
+
# --- Stage 2: Knowledge Graph Lookup (Rule-Based Reasoning) ---
|
|
214
|
+
output.append("\n[Stage 2: Symbolic Lookup]")
|
|
215
|
+
|
|
216
|
+
found_concept = False
|
|
217
|
+
for key, knowledge in self.knowledge_graph.items():
|
|
218
|
+
if key in lower_prompt or any(k in lower_prompt for k in knowledge.get("keywords", [])):
|
|
219
|
+
if key == "fix_code": continue
|
|
220
|
+
|
|
221
|
+
output.append(f"🧠 Found Concept: **{key.upper()}**")
|
|
222
|
+
output.append(f"Description: {knowledge.get('desc', 'No detailed description.')}")
|
|
223
|
+
|
|
224
|
+
if 'syntax' in knowledge:
|
|
225
|
+
output.append("Related Syntax:")
|
|
226
|
+
for syn, code in knowledge['syntax'].items():
|
|
227
|
+
output.append(f" - {syn.replace('_', ' ')}: `{code}`")
|
|
228
|
+
|
|
229
|
+
found_concept = True
|
|
230
|
+
break
|
|
231
|
+
|
|
232
|
+
if not found_concept:
|
|
233
|
+
output.append("❓ Concept Unknown: I am currently offline and limited to my internal knowledge base (Python, AST, Fix Code).")
|
|
234
|
+
output.append("Please provide a file for AST analysis or try again later for a full Groq response.")
|
|
235
|
+
|
|
236
|
+
return "\n".join(output)
|
|
206
237
|
|
|
207
|
-
# Catch-all fallback
|
|
208
|
-
return (
|
|
209
|
-
"[LocalAI] Offline mode enabled.\n"
|
|
210
|
-
"I can still analyze Python code and help with general knowledge.\n"
|
|
211
|
-
"Once online, Groq will give full intelligent responses."
|
|
212
|
-
)
|
|
213
238
|
|
|
214
239
|
# ==========================================================
|
|
215
|
-
# ASK (Groq →
|
|
240
|
+
# ASK (Groq → Symbolic Fallback)
|
|
216
241
|
# ==========================================================
|
|
217
242
|
def ask(self, text, file=None):
|
|
218
243
|
file_data = self._read_file(file)
|
|
219
244
|
prompt = self._build_prompt(text, file_data)
|
|
245
|
+
|
|
246
|
+
resp = None
|
|
220
247
|
|
|
221
|
-
#
|
|
248
|
+
# --- Attempt 1: Call External API (Groq) ---
|
|
222
249
|
try:
|
|
223
250
|
url = "https://api.groq.com/openai/v1/chat/completions"
|
|
224
251
|
headers = {
|
|
@@ -227,7 +254,7 @@ class AI:
|
|
|
227
254
|
}
|
|
228
255
|
|
|
229
256
|
payload = {
|
|
230
|
-
"model":
|
|
257
|
+
"model": self.model,
|
|
231
258
|
"messages": [
|
|
232
259
|
{"role": "system", "content": self.personality},
|
|
233
260
|
{"role": "user", "content": prompt}
|
|
@@ -235,18 +262,23 @@ class AI:
|
|
|
235
262
|
"temperature": 0.3
|
|
236
263
|
}
|
|
237
264
|
|
|
238
|
-
|
|
239
|
-
r = requests.post(url, json=payload, headers=headers, timeout=8)
|
|
265
|
+
r = requests.post(url, json=payload, headers=headers, timeout=10)
|
|
240
266
|
data = r.json()
|
|
241
267
|
|
|
242
268
|
if "error" in data:
|
|
243
|
-
|
|
269
|
+
# If the API returns an error (e.g., bad key), we force the fallback
|
|
270
|
+
raise RuntimeError(f"API Error: {data['error'].get('message', 'Unknown API Error')}")
|
|
244
271
|
|
|
245
272
|
resp = data["choices"][0]["message"]["content"]
|
|
246
273
|
|
|
247
|
-
except Exception:
|
|
248
|
-
#
|
|
249
|
-
|
|
274
|
+
except Exception as e:
|
|
275
|
+
# This block handles API connection failures (timeout) or API-side errors (bad key)
|
|
276
|
+
print(f"[CrystalAI] Groq connection failed or returned error: {e.__class__.__name__}")
|
|
277
|
+
print("[CrystalAI] Falling back to self-contained Symbolic Engine...")
|
|
278
|
+
|
|
279
|
+
# --- Attempt 2: Fallback to Symbolic Engine ---
|
|
280
|
+
resp = self._symbolic_engine(prompt, file_data)
|
|
281
|
+
|
|
250
282
|
|
|
251
283
|
self._save_memory(text, resp)
|
|
252
284
|
return CrystalAIResponse(resp)
|
|
@@ -284,7 +316,7 @@ class AI:
|
|
|
284
316
|
msg = getattr(syntax_error, "msg", "")
|
|
285
317
|
lineno = syntax_error.lineno or 0
|
|
286
318
|
|
|
287
|
-
# missing colon
|
|
319
|
+
# missing colon fix
|
|
288
320
|
if "expected" in msg and ":" in msg:
|
|
289
321
|
if 1 <= lineno <= len(lines):
|
|
290
322
|
line = lines[lineno - 1].rstrip()
|
|
@@ -295,7 +327,7 @@ class AI:
|
|
|
295
327
|
try:
|
|
296
328
|
ast.parse(candidate)
|
|
297
329
|
return candidate, notes
|
|
298
|
-
except:
|
|
330
|
+
except Exception:
|
|
299
331
|
pass
|
|
300
332
|
|
|
301
333
|
# fallback
|
|
@@ -326,9 +358,9 @@ class AI:
|
|
|
326
358
|
out = []
|
|
327
359
|
for i in range(start, end):
|
|
328
360
|
mark = "->" if (i + 1) == lineno else " "
|
|
329
|
-
out.append(f"{mark} {i+1
|
|
361
|
+
out.append(f"{mark} {i+1:<4}: {lines[i]}")
|
|
330
362
|
return "\n".join(out)
|
|
331
363
|
|
|
332
364
|
# ==========================================================
|
|
333
|
-
# END OF ENGINE
|
|
334
|
-
# ==========================================================
|
|
365
|
+
# END OF HYBRID ENGINE
|
|
366
|
+
# ==========================================================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
crystalwindow/FileHelper.py,sha256=aUnnRG7UwvzJt-idjWjmpwy3RM6nqLlC3-7Bae6Yb94,5471
|
|
2
2
|
crystalwindow/__init__.py,sha256=a2kdMZ29QZ4kSQ3M8jLvCR6g3OUQxNhdaT3ycxoames,2264
|
|
3
|
-
crystalwindow/ai.py,sha256=
|
|
3
|
+
crystalwindow/ai.py,sha256=4CN3_Fi5zERxyqoHcUyXPvm4MVWaicA7JGK0lRb-ybQ,14661
|
|
4
4
|
crystalwindow/animation.py,sha256=zHjrdBXQeyNaLAuaGPldJueX05OZ5j31YR8NizmR0uQ,427
|
|
5
5
|
crystalwindow/assets.py,sha256=2Cj0zdhMWo3mWjdr9KU5n-9_8iKj_fJ9uShMFA-27HU,5193
|
|
6
6
|
crystalwindow/camera.py,sha256=tbn4X-jxMIszAUg3Iu-89gJN5nij0mjPMEzGotcLbJI,712
|
|
@@ -33,8 +33,8 @@ crystalwindow/gametests/guitesting.py,sha256=SrOssY5peCQEV6TQ1AiOWtjb9phVGdRzW-Q
|
|
|
33
33
|
crystalwindow/gametests/sandbox.py,sha256=Oo2tU2N0y3BPVa6T5vs_h9N6islhQrjSrr_78XLut5I,1007
|
|
34
34
|
crystalwindow/gametests/squaremove.py,sha256=poP2Zjl2oc2HVvIAgIK34H2jVj6otL4jEdvAOR6L9sI,572
|
|
35
35
|
crystalwindow/gametests/windowtesting.py,sha256=_9X6wnV1-_X_PtNS-0zu-k209NtFIwAc4vpxLPp7V2o,97
|
|
36
|
-
crystalwindow-4.
|
|
37
|
-
crystalwindow-4.
|
|
38
|
-
crystalwindow-4.
|
|
39
|
-
crystalwindow-4.
|
|
40
|
-
crystalwindow-4.
|
|
36
|
+
crystalwindow-4.4.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
|
|
37
|
+
crystalwindow-4.4.dist-info/METADATA,sha256=8j8_X2PPPAo6OmZELS5-KpjARhkwJcnYcC4r2qur-7M,7338
|
|
38
|
+
crystalwindow-4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
39
|
+
crystalwindow-4.4.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
|
|
40
|
+
crystalwindow-4.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|