crystalwindow 3.8.9__tar.gz → 4.0__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.
- {crystalwindow-3.8.9/crystalwindow.egg-info → crystalwindow-4.0}/PKG-INFO +1 -1
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/__init__.py +5 -0
- crystalwindow-4.0/crystalwindow/ai.py +275 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0/crystalwindow.egg-info}/PKG-INFO +1 -1
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow.egg-info/SOURCES.txt +1 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/setup.py +1 -1
- {crystalwindow-3.8.9 → crystalwindow-4.0}/LICENSE +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/MANIFEST.in +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/README.md +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/FileHelper.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/Icons/default_icon.png +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/animation.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/assets.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/camera.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/clock.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/collision.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/color_handler.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/crystal3d.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/docs/getting_started.md +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/docs/index.md +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/draw_helpers.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/draw_rects.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/draw_text_helper.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/draw_tool.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/fun_helpers.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/3dsquare.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/__init__.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/__main__.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/gravitytest.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/guitesting.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/sandbox.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/squaremove.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gametests/windowtesting.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gravity.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gui.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/gui_ext.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/math.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/player.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/sprites.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/tilemap.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/ver_warner.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow/window.py +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow.egg-info/dependency_links.txt +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/crystalwindow.egg-info/top_level.txt +0 -0
- {crystalwindow-3.8.9 → crystalwindow-4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0
|
|
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
|
|
@@ -49,6 +49,8 @@ from .color_handler import Colors, Color
|
|
|
49
49
|
# === 3D Engine ===
|
|
50
50
|
from .crystal3d import CW3D
|
|
51
51
|
|
|
52
|
+
# === AI Engine ===
|
|
53
|
+
from .ai import AI
|
|
52
54
|
|
|
53
55
|
__all__ = [
|
|
54
56
|
# --- Core ---
|
|
@@ -86,4 +88,7 @@ __all__ = [
|
|
|
86
88
|
|
|
87
89
|
# --- 3D ---
|
|
88
90
|
"CW3D",
|
|
91
|
+
|
|
92
|
+
# --- AI ---
|
|
93
|
+
"AI",
|
|
89
94
|
]
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# ==========================================================
|
|
2
|
+
# CrystalAI v0.6 — Unified Engine
|
|
3
|
+
# ----------------------------------------------------------
|
|
4
|
+
# Combines:
|
|
5
|
+
# - v0.4: auto-fix, AST parser, docs index, diff tools
|
|
6
|
+
# - v0.5: personality, library ingestion, safe key check
|
|
7
|
+
# - Groq fallback, local fallback, file analysis
|
|
8
|
+
# ==========================================================
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import ast
|
|
12
|
+
import difflib
|
|
13
|
+
from typing import Optional, Dict, Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ==========================================================
|
|
17
|
+
# Response Wrapper
|
|
18
|
+
# ==========================================================
|
|
19
|
+
class CrystalAIResponse:
|
|
20
|
+
def __init__(self, text: str, meta: Optional[Dict[str, Any]] = None):
|
|
21
|
+
self.text = text
|
|
22
|
+
self.meta = meta or {}
|
|
23
|
+
|
|
24
|
+
def __str__(self):
|
|
25
|
+
return self.text
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ==========================================================
|
|
29
|
+
# MAIN ENGINE
|
|
30
|
+
# ==========================================================
|
|
31
|
+
class AI:
|
|
32
|
+
DEFAULT_MODEL = "llama-3.1-8b"
|
|
33
|
+
DEFAULT_PERSONALITY = (
|
|
34
|
+
"You are CrystalWindow AI. You help users with Python code, "
|
|
35
|
+
"debugging, errors, docs, and file analysis. "
|
|
36
|
+
"Be friendly, technical, clear, and precise."
|
|
37
|
+
)
|
|
38
|
+
PLACEHOLDER_KEY = "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"
|
|
39
|
+
|
|
40
|
+
# ------------------------------------------------------
|
|
41
|
+
def __init__(self, key=None, model=None):
|
|
42
|
+
# --- KEY VALIDATION ---
|
|
43
|
+
if not key or len(key) < 20 or " " in key:
|
|
44
|
+
print("[CrystalAI] Warning: Invalid or missing key → using placeholder. To get a Fixed Key go to 'console.groq.com/keys'")
|
|
45
|
+
self.key = self.PLACEHOLDER_KEY
|
|
46
|
+
else:
|
|
47
|
+
self.key = key
|
|
48
|
+
|
|
49
|
+
# --- MODEL VALIDATION ---
|
|
50
|
+
if not model or not isinstance(model, str) or len(model) < 3:
|
|
51
|
+
print("[CrystalAI] Unknown model → using default.")
|
|
52
|
+
self.model = self.DEFAULT_MODEL
|
|
53
|
+
else:
|
|
54
|
+
self.model = model
|
|
55
|
+
|
|
56
|
+
# Persona
|
|
57
|
+
self.personality = self.DEFAULT_PERSONALITY
|
|
58
|
+
|
|
59
|
+
# Library knowledge (loaded .py files)
|
|
60
|
+
self.library_context = ""
|
|
61
|
+
|
|
62
|
+
# v0.4 memory system (optional)
|
|
63
|
+
self.memory = []
|
|
64
|
+
self.use_memory = True
|
|
65
|
+
|
|
66
|
+
# v0.4 toggle for forcing local engine
|
|
67
|
+
self.force_local = False
|
|
68
|
+
|
|
69
|
+
# ==========================================================
|
|
70
|
+
# PERSONALITY
|
|
71
|
+
# ==========================================================
|
|
72
|
+
def set_personality(self, txt):
|
|
73
|
+
if not isinstance(txt, str) or len(txt.strip()) < 10:
|
|
74
|
+
print("Oops! thats not how to use it—reverting to default.")
|
|
75
|
+
self.personality = self.DEFAULT_PERSONALITY
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if len(txt) > 3000:
|
|
79
|
+
print("Oops, personality too long → using default.")
|
|
80
|
+
self.personality = self.DEFAULT_PERSONALITY
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
self.personality = txt.strip()
|
|
84
|
+
|
|
85
|
+
# ==========================================================
|
|
86
|
+
# LIBRARY INGESTION
|
|
87
|
+
# ==========================================================
|
|
88
|
+
def index_library(self, folder):
|
|
89
|
+
"""
|
|
90
|
+
Load all Python files as context for smarter answers.
|
|
91
|
+
"""
|
|
92
|
+
out = []
|
|
93
|
+
if not os.path.exists(folder):
|
|
94
|
+
print("[CrystalAI] Library folder not found.")
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
for root, _, files in os.walk(folder):
|
|
98
|
+
for f in files:
|
|
99
|
+
if f.endswith(".py"):
|
|
100
|
+
try:
|
|
101
|
+
path = os.path.join(root, f)
|
|
102
|
+
with open(path, "r", encoding="utf8") as fp:
|
|
103
|
+
out.append(f"# FILE: {path}\n" + fp.read() + "\n\n")
|
|
104
|
+
except:
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
self.library_context = "\n".join(out)
|
|
108
|
+
|
|
109
|
+
# ==========================================================
|
|
110
|
+
# FILE READER
|
|
111
|
+
# ==========================================================
|
|
112
|
+
def _read_file(self, path):
|
|
113
|
+
if not path:
|
|
114
|
+
return None
|
|
115
|
+
if not os.path.exists(path):
|
|
116
|
+
return f"[CrystalAI] file not found: {path}"
|
|
117
|
+
try:
|
|
118
|
+
with open(path, "r", encoding="utf8") as f:
|
|
119
|
+
return f.read()
|
|
120
|
+
except:
|
|
121
|
+
return "[CrystalAI] couldnt read file."
|
|
122
|
+
|
|
123
|
+
# ==========================================================
|
|
124
|
+
# PROMPT BUILDER (Unified)
|
|
125
|
+
# ==========================================================
|
|
126
|
+
def _build_prompt(self, user_text, file_data=None):
|
|
127
|
+
final = (
|
|
128
|
+
f"[SYSTEM]\n{self.personality}\n\n"
|
|
129
|
+
f"[USER]\n{user_text}\n\n"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if self.use_memory and self.memory:
|
|
133
|
+
final += "[MEMORY]\n"
|
|
134
|
+
for m in self.memory[-6:]:
|
|
135
|
+
final += f"User: {m['user']}\nAI: {m['ai']}\n"
|
|
136
|
+
final += "\n"
|
|
137
|
+
|
|
138
|
+
if self.library_context:
|
|
139
|
+
final += f"[LIBRARY]\n{self.library_context}\n\n"
|
|
140
|
+
|
|
141
|
+
if file_data:
|
|
142
|
+
final += f"[FILE]\n{file_data}\n\n"
|
|
143
|
+
|
|
144
|
+
return final
|
|
145
|
+
|
|
146
|
+
def _save_memory(self, user, ai):
|
|
147
|
+
self.memory.append({"user": user, "ai": ai})
|
|
148
|
+
if len(self.memory) > 60:
|
|
149
|
+
self.memory.pop(0)
|
|
150
|
+
|
|
151
|
+
# ==========================================================
|
|
152
|
+
# LOCAL FALLBACK AI (v0.4 + v0.5 merged)
|
|
153
|
+
# ==========================================================
|
|
154
|
+
def _local_ai(self, prompt, file_data):
|
|
155
|
+
"""
|
|
156
|
+
Uses AST parsing to inspect Python,
|
|
157
|
+
gives real syntax help + fallback personality text.
|
|
158
|
+
"""
|
|
159
|
+
if file_data and not file_data.startswith("[CrystalAI]"):
|
|
160
|
+
try:
|
|
161
|
+
ast.parse(file_data)
|
|
162
|
+
if "fix" in prompt.lower() or "error" in prompt.lower():
|
|
163
|
+
return "[LocalAI] File has no syntax errors. What exactly breaks?"
|
|
164
|
+
return "[LocalAI] File parsed OK. Ask me to summarize or fix something."
|
|
165
|
+
except SyntaxError as se:
|
|
166
|
+
# Syntax help
|
|
167
|
+
lineno = se.lineno or 0
|
|
168
|
+
offset = se.offset or 0
|
|
169
|
+
msg = f"[LocalAI] SyntaxError: {se.msg} at line {lineno}, col {offset}"
|
|
170
|
+
snippet = self._snippet(file_data, lineno)
|
|
171
|
+
return msg + "\n" + snippet
|
|
172
|
+
|
|
173
|
+
# generic offline
|
|
174
|
+
if "error" in prompt.lower():
|
|
175
|
+
return "[LocalAI] maybe u forgot a colon or indent lol"
|
|
176
|
+
|
|
177
|
+
return "[LocalAI] offline fallback active."
|
|
178
|
+
|
|
179
|
+
# ==========================================================
|
|
180
|
+
# ASK
|
|
181
|
+
# ==========================================================
|
|
182
|
+
def ask(self, text, file=None):
|
|
183
|
+
file_data = self._read_file(file)
|
|
184
|
+
prompt = self._build_prompt(text, file_data)
|
|
185
|
+
|
|
186
|
+
# Real Groq request would go here
|
|
187
|
+
try:
|
|
188
|
+
raise Exception("simulate offline")
|
|
189
|
+
except:
|
|
190
|
+
resp = self._local_ai(prompt, file_data)
|
|
191
|
+
|
|
192
|
+
self._save_memory(text, resp)
|
|
193
|
+
return CrystalAIResponse(resp)
|
|
194
|
+
|
|
195
|
+
# ==========================================================
|
|
196
|
+
# ASK (terminal)
|
|
197
|
+
# ==========================================================
|
|
198
|
+
def ask_t(self, text, file=None):
|
|
199
|
+
return self.ask(f"[TERMINAL] {text}", file)
|
|
200
|
+
|
|
201
|
+
# ==========================================================
|
|
202
|
+
# AUTO FIX CODE (v0.4)
|
|
203
|
+
# ==========================================================
|
|
204
|
+
def fix_code(self, file_path):
|
|
205
|
+
orig = self._read_file(file_path)
|
|
206
|
+
|
|
207
|
+
if not orig or orig.startswith("[CrystalAI]"):
|
|
208
|
+
return CrystalAIResponse(orig or "[CrystalAI] file missing")
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
ast.parse(orig)
|
|
212
|
+
return CrystalAIResponse("[AI] No syntax errors found.")
|
|
213
|
+
except SyntaxError as se:
|
|
214
|
+
fixed, notes = self._simple_fix(orig, se)
|
|
215
|
+
diff = self._make_diff(orig, fixed)
|
|
216
|
+
pretty = "[AI] Auto-fix result:\n" + "\n".join(notes) + "\n\n" + diff
|
|
217
|
+
return CrystalAIResponse(pretty, {"diff": diff, "notes": notes})
|
|
218
|
+
|
|
219
|
+
# ==========================================================
|
|
220
|
+
# SIMPLE AUTO-FIX ENGINE
|
|
221
|
+
# ==========================================================
|
|
222
|
+
def _simple_fix(self, src, syntax_error):
|
|
223
|
+
notes = []
|
|
224
|
+
lines = src.splitlines()
|
|
225
|
+
msg = getattr(syntax_error, "msg", "")
|
|
226
|
+
lineno = syntax_error.lineno or 0
|
|
227
|
+
|
|
228
|
+
# missing colon
|
|
229
|
+
if "expected" in msg and ":" in msg:
|
|
230
|
+
if 1 <= lineno <= len(lines):
|
|
231
|
+
line = lines[lineno - 1].rstrip()
|
|
232
|
+
if not line.endswith(":"):
|
|
233
|
+
lines[lineno - 1] = line + ":"
|
|
234
|
+
notes.append("[fix] added missing ':'")
|
|
235
|
+
candidate = "\n".join(lines)
|
|
236
|
+
try:
|
|
237
|
+
ast.parse(candidate)
|
|
238
|
+
return candidate, notes
|
|
239
|
+
except:
|
|
240
|
+
pass
|
|
241
|
+
|
|
242
|
+
# fallback
|
|
243
|
+
notes.append("[info] auto-fix could not fix everything")
|
|
244
|
+
return src, notes
|
|
245
|
+
|
|
246
|
+
# ==========================================================
|
|
247
|
+
# DIFF UTIL
|
|
248
|
+
# ==========================================================
|
|
249
|
+
def _make_diff(self, old, new):
|
|
250
|
+
return "\n".join(
|
|
251
|
+
difflib.unified_diff(
|
|
252
|
+
old.splitlines(),
|
|
253
|
+
new.splitlines(),
|
|
254
|
+
fromfile="old",
|
|
255
|
+
tofile="new",
|
|
256
|
+
lineterm=""
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# ==========================================================
|
|
261
|
+
# SNIPPET HELPER
|
|
262
|
+
# ==========================================================
|
|
263
|
+
def _snippet(self, src, lineno, ctx=2):
|
|
264
|
+
lines = src.splitlines()
|
|
265
|
+
start = max(0, lineno - ctx - 1)
|
|
266
|
+
end = min(len(lines), lineno + ctx)
|
|
267
|
+
out = []
|
|
268
|
+
for i in range(start, end):
|
|
269
|
+
mark = "->" if (i + 1) == lineno else " "
|
|
270
|
+
out.append(f"{mark} {i+1:4}: {lines[i]}")
|
|
271
|
+
return "\n".join(out)
|
|
272
|
+
|
|
273
|
+
# ==========================================================
|
|
274
|
+
# END OF ENGINE
|
|
275
|
+
# ==========================================================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0
|
|
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
|
|
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
|
|
|
7
7
|
|
|
8
8
|
setup(
|
|
9
9
|
name="crystalwindow",
|
|
10
|
-
version="
|
|
10
|
+
version="4.0", # Force metadata refresh
|
|
11
11
|
packages=find_packages(include=["crystalwindow", "crystalwindow.*"]),
|
|
12
12
|
|
|
13
13
|
include_package_data=True, # include package_data files
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|