createsonline 0.1.26__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.
- createsonline/__init__.py +46 -0
- createsonline/admin/__init__.py +7 -0
- createsonline/admin/content.py +526 -0
- createsonline/admin/crud.py +805 -0
- createsonline/admin/field_builder.py +559 -0
- createsonline/admin/integration.py +482 -0
- createsonline/admin/interface.py +2562 -0
- createsonline/admin/model_creator.py +513 -0
- createsonline/admin/model_manager.py +388 -0
- createsonline/admin/modern_dashboard.py +498 -0
- createsonline/admin/permissions.py +264 -0
- createsonline/admin/user_forms.py +594 -0
- createsonline/ai/__init__.py +202 -0
- createsonline/ai/fields.py +1226 -0
- createsonline/ai/orm.py +325 -0
- createsonline/ai/services.py +1244 -0
- createsonline/app.py +506 -0
- createsonline/auth/__init__.py +8 -0
- createsonline/auth/management.py +228 -0
- createsonline/auth/models.py +552 -0
- createsonline/cli/__init__.py +5 -0
- createsonline/cli/commands/__init__.py +122 -0
- createsonline/cli/commands/database.py +416 -0
- createsonline/cli/commands/info.py +173 -0
- createsonline/cli/commands/initdb.py +218 -0
- createsonline/cli/commands/project.py +545 -0
- createsonline/cli/commands/serve.py +173 -0
- createsonline/cli/commands/shell.py +93 -0
- createsonline/cli/commands/users.py +148 -0
- createsonline/cli/main.py +2041 -0
- createsonline/cli/manage.py +274 -0
- createsonline/config/__init__.py +9 -0
- createsonline/config/app.py +2577 -0
- createsonline/config/database.py +179 -0
- createsonline/config/docs.py +384 -0
- createsonline/config/errors.py +160 -0
- createsonline/config/orm.py +43 -0
- createsonline/config/request.py +93 -0
- createsonline/config/settings.py +176 -0
- createsonline/data/__init__.py +23 -0
- createsonline/data/dataframe.py +925 -0
- createsonline/data/io.py +453 -0
- createsonline/data/series.py +557 -0
- createsonline/database/__init__.py +60 -0
- createsonline/database/abstraction.py +440 -0
- createsonline/database/assistant.py +585 -0
- createsonline/database/fields.py +442 -0
- createsonline/database/migrations.py +132 -0
- createsonline/database/models.py +604 -0
- createsonline/database.py +438 -0
- createsonline/http/__init__.py +28 -0
- createsonline/http/client.py +535 -0
- createsonline/ml/__init__.py +55 -0
- createsonline/ml/classification.py +552 -0
- createsonline/ml/clustering.py +680 -0
- createsonline/ml/metrics.py +542 -0
- createsonline/ml/neural.py +560 -0
- createsonline/ml/preprocessing.py +784 -0
- createsonline/ml/regression.py +501 -0
- createsonline/performance/__init__.py +19 -0
- createsonline/performance/cache.py +444 -0
- createsonline/performance/compression.py +335 -0
- createsonline/performance/core.py +419 -0
- createsonline/project_init.py +789 -0
- createsonline/routing.py +528 -0
- createsonline/security/__init__.py +34 -0
- createsonline/security/core.py +811 -0
- createsonline/security/encryption.py +349 -0
- createsonline/server.py +295 -0
- createsonline/static/css/admin.css +263 -0
- createsonline/static/css/common.css +358 -0
- createsonline/static/css/dashboard.css +89 -0
- createsonline/static/favicon.ico +0 -0
- createsonline/static/icons/icon-128x128.png +0 -0
- createsonline/static/icons/icon-128x128.webp +0 -0
- createsonline/static/icons/icon-16x16.png +0 -0
- createsonline/static/icons/icon-16x16.webp +0 -0
- createsonline/static/icons/icon-180x180.png +0 -0
- createsonline/static/icons/icon-180x180.webp +0 -0
- createsonline/static/icons/icon-192x192.png +0 -0
- createsonline/static/icons/icon-192x192.webp +0 -0
- createsonline/static/icons/icon-256x256.png +0 -0
- createsonline/static/icons/icon-256x256.webp +0 -0
- createsonline/static/icons/icon-32x32.png +0 -0
- createsonline/static/icons/icon-32x32.webp +0 -0
- createsonline/static/icons/icon-384x384.png +0 -0
- createsonline/static/icons/icon-384x384.webp +0 -0
- createsonline/static/icons/icon-48x48.png +0 -0
- createsonline/static/icons/icon-48x48.webp +0 -0
- createsonline/static/icons/icon-512x512.png +0 -0
- createsonline/static/icons/icon-512x512.webp +0 -0
- createsonline/static/icons/icon-64x64.png +0 -0
- createsonline/static/icons/icon-64x64.webp +0 -0
- createsonline/static/image/android-chrome-192x192.png +0 -0
- createsonline/static/image/android-chrome-512x512.png +0 -0
- createsonline/static/image/apple-touch-icon.png +0 -0
- createsonline/static/image/favicon-16x16.png +0 -0
- createsonline/static/image/favicon-32x32.png +0 -0
- createsonline/static/image/favicon.ico +0 -0
- createsonline/static/image/favicon.svg +17 -0
- createsonline/static/image/icon-128x128.png +0 -0
- createsonline/static/image/icon-128x128.webp +0 -0
- createsonline/static/image/icon-16x16.png +0 -0
- createsonline/static/image/icon-16x16.webp +0 -0
- createsonline/static/image/icon-180x180.png +0 -0
- createsonline/static/image/icon-180x180.webp +0 -0
- createsonline/static/image/icon-192x192.png +0 -0
- createsonline/static/image/icon-192x192.webp +0 -0
- createsonline/static/image/icon-256x256.png +0 -0
- createsonline/static/image/icon-256x256.webp +0 -0
- createsonline/static/image/icon-32x32.png +0 -0
- createsonline/static/image/icon-32x32.webp +0 -0
- createsonline/static/image/icon-384x384.png +0 -0
- createsonline/static/image/icon-384x384.webp +0 -0
- createsonline/static/image/icon-48x48.png +0 -0
- createsonline/static/image/icon-48x48.webp +0 -0
- createsonline/static/image/icon-512x512.png +0 -0
- createsonline/static/image/icon-512x512.webp +0 -0
- createsonline/static/image/icon-64x64.png +0 -0
- createsonline/static/image/icon-64x64.webp +0 -0
- createsonline/static/image/logo-header-h100.png +0 -0
- createsonline/static/image/logo-header-h100.webp +0 -0
- createsonline/static/image/logo-header-h200@2x.png +0 -0
- createsonline/static/image/logo-header-h200@2x.webp +0 -0
- createsonline/static/image/logo.png +0 -0
- createsonline/static/js/admin.js +274 -0
- createsonline/static/site.webmanifest +35 -0
- createsonline/static/templates/admin/base.html +87 -0
- createsonline/static/templates/admin/dashboard.html +217 -0
- createsonline/static/templates/admin/model_form.html +270 -0
- createsonline/static/templates/admin/model_list.html +202 -0
- createsonline/static/test_script.js +15 -0
- createsonline/static/test_styles.css +59 -0
- createsonline/static_files.py +365 -0
- createsonline/templates/404.html +100 -0
- createsonline/templates/admin_login.html +169 -0
- createsonline/templates/base.html +102 -0
- createsonline/templates/index.html +151 -0
- createsonline/templates.py +205 -0
- createsonline/testing.py +322 -0
- createsonline/utils.py +448 -0
- createsonline/validation/__init__.py +49 -0
- createsonline/validation/fields.py +598 -0
- createsonline/validation/models.py +504 -0
- createsonline/validation/validators.py +561 -0
- createsonline/views.py +184 -0
- createsonline-0.1.26.dist-info/METADATA +46 -0
- createsonline-0.1.26.dist-info/RECORD +152 -0
- createsonline-0.1.26.dist-info/WHEEL +5 -0
- createsonline-0.1.26.dist-info/entry_points.txt +2 -0
- createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
- createsonline-0.1.26.dist-info/top_level.txt +1 -0
createsonline/app.py
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
# createsonline/app.py
|
|
2
|
+
"""
|
|
3
|
+
CREATESONLINE Application Core
|
|
4
|
+
|
|
5
|
+
Main application class and request handling
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import hashlib
|
|
11
|
+
import logging
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Dict, Any, Optional, List, Callable, Union
|
|
14
|
+
|
|
15
|
+
# System requirements check
|
|
16
|
+
if sys.version_info < (3, 9):
|
|
17
|
+
raise RuntimeError(f"CREATESONLINE requires Python 3.9+. Current: {sys.version}")
|
|
18
|
+
|
|
19
|
+
# Setup logging
|
|
20
|
+
logger = logging.getLogger("createsonline")
|
|
21
|
+
|
|
22
|
+
# Get version
|
|
23
|
+
from . import __version__
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CreatesonlineInternalApp:
|
|
27
|
+
"""
|
|
28
|
+
Pure CREATESONLINE core application - ZERO external dependencies
|
|
29
|
+
|
|
30
|
+
This is the internal implementation that works with just Python stdlib.
|
|
31
|
+
Provides full AI-native framework capabilities without any external packages.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
title: str = "CREATESONLINE Application",
|
|
37
|
+
description: str = "AI-powered application built with CREATESONLINE",
|
|
38
|
+
version: str = "1.0.0",
|
|
39
|
+
ai_config: Optional[Dict[str, Any]] = None,
|
|
40
|
+
debug: bool = False,
|
|
41
|
+
**kwargs
|
|
42
|
+
):
|
|
43
|
+
# Core application metadata
|
|
44
|
+
self.title = title
|
|
45
|
+
self.description = description
|
|
46
|
+
self.version = version
|
|
47
|
+
self.debug = debug
|
|
48
|
+
self.ai_config = ai_config or {}
|
|
49
|
+
|
|
50
|
+
# Internal routing system
|
|
51
|
+
self.routes = {}
|
|
52
|
+
self.middleware = []
|
|
53
|
+
self.startup_handlers = []
|
|
54
|
+
self.shutdown_handlers = []
|
|
55
|
+
|
|
56
|
+
# AI-native features (internal implementations)
|
|
57
|
+
self.ai_enabled = True
|
|
58
|
+
self.ai_features = []
|
|
59
|
+
self.ai_services = CreatesonlineInternalAI()
|
|
60
|
+
|
|
61
|
+
# Setup framework routes
|
|
62
|
+
self._setup_framework_routes()
|
|
63
|
+
|
|
64
|
+
logger.info(f"CREATESONLINE v{__version__} initialized (Internal Core)")
|
|
65
|
+
logger.info(f"{self.title} - AI-Native Framework Ready")
|
|
66
|
+
|
|
67
|
+
def _setup_framework_routes(self):
|
|
68
|
+
"""Setup built-in CREATESONLINE framework routes"""
|
|
69
|
+
|
|
70
|
+
@self.get("/health")
|
|
71
|
+
async def health_check(request):
|
|
72
|
+
return {
|
|
73
|
+
"status": "healthy",
|
|
74
|
+
"framework": "CREATESONLINE",
|
|
75
|
+
"version": __version__,
|
|
76
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ========================================
|
|
80
|
+
# PURE ASGI IMPLEMENTATION
|
|
81
|
+
# ========================================
|
|
82
|
+
|
|
83
|
+
async def __call__(self, scope, receive, send):
|
|
84
|
+
"""Pure ASGI interface - no external dependencies"""
|
|
85
|
+
|
|
86
|
+
if scope['type'] == 'http':
|
|
87
|
+
await self._handle_http(scope, receive, send)
|
|
88
|
+
elif scope['type'] == 'websocket':
|
|
89
|
+
await self._handle_websocket(scope, receive, send)
|
|
90
|
+
|
|
91
|
+
async def _handle_http(self, scope, receive, send):
|
|
92
|
+
"""Handle HTTP requests with internal router"""
|
|
93
|
+
|
|
94
|
+
# On first request, discover routes from routes.py to override decorators
|
|
95
|
+
if getattr(self, '_needs_route_discovery', False):
|
|
96
|
+
try:
|
|
97
|
+
from .project_init import auto_discover_routes
|
|
98
|
+
auto_discover_routes(self)
|
|
99
|
+
self._needs_route_discovery = False
|
|
100
|
+
except Exception:
|
|
101
|
+
self._needs_route_discovery = False
|
|
102
|
+
|
|
103
|
+
path = scope['path']
|
|
104
|
+
method = scope['method']
|
|
105
|
+
route_key = f"{method}:{path}"
|
|
106
|
+
|
|
107
|
+
# Create internal request object
|
|
108
|
+
request = CreatesonlineInternalRequest(scope, receive)
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
# Check for static files first (before routing)
|
|
112
|
+
if method == 'GET' and self._is_static_path(path):
|
|
113
|
+
print(f"[DEBUG] Static file detected: {path}")
|
|
114
|
+
await self._serve_static_file(path, send)
|
|
115
|
+
return
|
|
116
|
+
else:
|
|
117
|
+
if method == 'GET':
|
|
118
|
+
print(f"[DEBUG] Not a static path: {path}")
|
|
119
|
+
|
|
120
|
+
# Find matching route
|
|
121
|
+
if route_key in self.routes:
|
|
122
|
+
handler = self.routes[route_key]
|
|
123
|
+
response_data = await handler(request)
|
|
124
|
+
status = 200
|
|
125
|
+
else:
|
|
126
|
+
# 404 handler - check for custom not_found handler
|
|
127
|
+
not_found_handler = self.routes.get('not_found') or self.routes.get('GET /404')
|
|
128
|
+
if not_found_handler:
|
|
129
|
+
response_data = await not_found_handler(request)
|
|
130
|
+
status = 404
|
|
131
|
+
else:
|
|
132
|
+
# Default 404 response
|
|
133
|
+
response_data = {
|
|
134
|
+
"error": "Not Found",
|
|
135
|
+
"path": path,
|
|
136
|
+
"method": method,
|
|
137
|
+
"framework": "CREATESONLINE",
|
|
138
|
+
"available_routes": list(self.routes.keys())
|
|
139
|
+
}
|
|
140
|
+
status = 404
|
|
141
|
+
|
|
142
|
+
# Send response
|
|
143
|
+
if isinstance(response_data, dict):
|
|
144
|
+
await self._send_json_response(send, response_data, status=status)
|
|
145
|
+
else:
|
|
146
|
+
await self._send_text_response(send, str(response_data))
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
# Error handling - log the full traceback
|
|
150
|
+
logger.exception(f"Request handling error for {method} {path}")
|
|
151
|
+
error_data = {
|
|
152
|
+
"error": "Internal Server Error",
|
|
153
|
+
"message": str(e) if self.debug else "Something went wrong",
|
|
154
|
+
"framework": "CREATESONLINE"
|
|
155
|
+
}
|
|
156
|
+
await self._send_json_response(send, error_data, status=500)
|
|
157
|
+
|
|
158
|
+
async def _handle_websocket(self, scope, receive, send):
|
|
159
|
+
"""Handle WebSocket connections with security measures"""
|
|
160
|
+
await send({'type': 'websocket.accept'})
|
|
161
|
+
|
|
162
|
+
message_count = 0
|
|
163
|
+
max_messages = 100
|
|
164
|
+
|
|
165
|
+
while True:
|
|
166
|
+
message = await receive()
|
|
167
|
+
if message['type'] == 'websocket.disconnect':
|
|
168
|
+
break
|
|
169
|
+
elif message['type'] == 'websocket.receive':
|
|
170
|
+
message_count += 1
|
|
171
|
+
if message_count > max_messages:
|
|
172
|
+
logger.warning("WebSocket rate limit exceeded")
|
|
173
|
+
await send({'type': 'websocket.close', 'code': 1008})
|
|
174
|
+
break
|
|
175
|
+
|
|
176
|
+
user_text = message.get('text', '')
|
|
177
|
+
if user_text:
|
|
178
|
+
logger.info(f"WebSocket message received (length: {len(user_text)})")
|
|
179
|
+
|
|
180
|
+
await send({
|
|
181
|
+
'type': 'websocket.send',
|
|
182
|
+
'text': json.dumps({
|
|
183
|
+
"framework": "CREATESONLINE",
|
|
184
|
+
"message": "WebSocket message processed",
|
|
185
|
+
"message_count": message_count
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
async def _send_json_response(self, send, data, status=200):
|
|
190
|
+
"""Send JSON response"""
|
|
191
|
+
response_body = json.dumps(data, indent=2 if self.debug else None).encode('utf-8')
|
|
192
|
+
|
|
193
|
+
await send({
|
|
194
|
+
'type': 'http.response.start',
|
|
195
|
+
'status': status,
|
|
196
|
+
'headers': [
|
|
197
|
+
[b'content-type', b'application/json'],
|
|
198
|
+
[b'content-length', str(len(response_body)).encode()],
|
|
199
|
+
[b'x-framework', b'CREATESONLINE'],
|
|
200
|
+
[b'x-version', __version__.encode()],
|
|
201
|
+
],
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
await send({
|
|
205
|
+
'type': 'http.response.body',
|
|
206
|
+
'body': response_body,
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
async def _send_text_response(self, send, text, status=200):
|
|
210
|
+
"""Send plain text or HTML response"""
|
|
211
|
+
response_body = text.encode('utf-8')
|
|
212
|
+
|
|
213
|
+
# Detect if it's HTML
|
|
214
|
+
content_type = b'text/html; charset=utf-8' if text.strip().startswith('<!DOCTYPE') or text.strip().startswith('<html') else b'text/plain'
|
|
215
|
+
|
|
216
|
+
await send({
|
|
217
|
+
'type': 'http.response.start',
|
|
218
|
+
'status': status,
|
|
219
|
+
'headers': [
|
|
220
|
+
[b'content-type', content_type],
|
|
221
|
+
[b'content-length', str(len(response_body)).encode()],
|
|
222
|
+
[b'x-framework', b'CREATESONLINE'],
|
|
223
|
+
],
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
await send({
|
|
227
|
+
'type': 'http.response.body',
|
|
228
|
+
'body': response_body,
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
def _is_static_path(self, path: str) -> bool:
|
|
232
|
+
"""Check if path is a static file request"""
|
|
233
|
+
static_prefixes = ['/static/', '/css/', '/js/', '/images/', '/img/', '/assets/', '/media/', '/icons/']
|
|
234
|
+
static_extensions = {'.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp',
|
|
235
|
+
'.woff', '.woff2', '.ttf', '.eot', '.pdf', '.txt', '.json', '.xml'}
|
|
236
|
+
|
|
237
|
+
for prefix in static_prefixes:
|
|
238
|
+
if path.startswith(prefix):
|
|
239
|
+
return True
|
|
240
|
+
|
|
241
|
+
for ext in static_extensions:
|
|
242
|
+
if path.endswith(ext):
|
|
243
|
+
return True
|
|
244
|
+
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
async def _serve_static_file(self, path, send):
|
|
248
|
+
"""Serve static files using StaticFileHandler"""
|
|
249
|
+
try:
|
|
250
|
+
print(f"[DEBUG] _serve_static_file called with: {path}")
|
|
251
|
+
logger.info(f"=== SERVING STATIC FILE: {path} ===")
|
|
252
|
+
from .static_files import static_handler
|
|
253
|
+
|
|
254
|
+
print(f"[DEBUG] Static dirs: {[str(d) for d in static_handler.static_dirs]}")
|
|
255
|
+
logger.info(f"Static dirs: {[str(d) for d in static_handler.static_dirs]}")
|
|
256
|
+
content, status_code, headers = static_handler.serve_file(path)
|
|
257
|
+
print(f"[DEBUG] serve_file returned: status={status_code}, content_length={len(content)}")
|
|
258
|
+
logger.info(f"Result: status={status_code}, content_length={len(content)}")
|
|
259
|
+
|
|
260
|
+
header_list = [[k.encode() if isinstance(k, str) else k,
|
|
261
|
+
v.encode() if isinstance(v, str) else v]
|
|
262
|
+
for k, v in headers.items()]
|
|
263
|
+
|
|
264
|
+
header_list.append([b'x-framework', b'CREATESONLINE'])
|
|
265
|
+
|
|
266
|
+
await send({
|
|
267
|
+
'type': 'http.response.start',
|
|
268
|
+
'status': status_code,
|
|
269
|
+
'headers': header_list,
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
await send({
|
|
273
|
+
'type': 'http.response.body',
|
|
274
|
+
'body': content if isinstance(content, bytes) else content.encode('utf-8'),
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
except Exception as e:
|
|
278
|
+
logger.error(f"Error serving static file {path}: {e}")
|
|
279
|
+
import traceback
|
|
280
|
+
traceback.print_exc()
|
|
281
|
+
await self._send_json_response(send, {"error": "Static file error", "message": str(e)}, status=500)
|
|
282
|
+
|
|
283
|
+
# ========================================
|
|
284
|
+
# ROUTING DECORATORS
|
|
285
|
+
# ========================================
|
|
286
|
+
|
|
287
|
+
def get(self, path: str):
|
|
288
|
+
"""GET route decorator"""
|
|
289
|
+
def decorator(func):
|
|
290
|
+
self.routes[f"GET:{path}"] = func
|
|
291
|
+
return func
|
|
292
|
+
return decorator
|
|
293
|
+
|
|
294
|
+
def post(self, path: str):
|
|
295
|
+
"""POST route decorator"""
|
|
296
|
+
def decorator(func):
|
|
297
|
+
self.routes[f"POST:{path}"] = func
|
|
298
|
+
return func
|
|
299
|
+
return decorator
|
|
300
|
+
|
|
301
|
+
def put(self, path: str):
|
|
302
|
+
"""PUT route decorator"""
|
|
303
|
+
def decorator(func):
|
|
304
|
+
self.routes[f"PUT:{path}"] = func
|
|
305
|
+
return func
|
|
306
|
+
return decorator
|
|
307
|
+
|
|
308
|
+
def delete(self, path: str):
|
|
309
|
+
"""DELETE route decorator"""
|
|
310
|
+
def decorator(func):
|
|
311
|
+
self.routes[f"DELETE:{path}"] = func
|
|
312
|
+
return func
|
|
313
|
+
return decorator
|
|
314
|
+
|
|
315
|
+
def route(self, path: str, methods: List[str] = None):
|
|
316
|
+
"""Multi-method route decorator"""
|
|
317
|
+
if methods is None:
|
|
318
|
+
methods = ["GET"]
|
|
319
|
+
|
|
320
|
+
def decorator(func):
|
|
321
|
+
for method in methods:
|
|
322
|
+
self.routes[f"{method.upper()}:{path}"] = func
|
|
323
|
+
return func
|
|
324
|
+
return decorator
|
|
325
|
+
|
|
326
|
+
# ========================================
|
|
327
|
+
# AI-NATIVE FEATURES
|
|
328
|
+
# ========================================
|
|
329
|
+
|
|
330
|
+
def enable_ai_features(self, features: List[str]):
|
|
331
|
+
"""Enable AI features"""
|
|
332
|
+
for feature in features:
|
|
333
|
+
if feature not in self.ai_features:
|
|
334
|
+
self.ai_features.append(feature)
|
|
335
|
+
logger.info(f"AI Feature enabled: {feature}")
|
|
336
|
+
return self
|
|
337
|
+
|
|
338
|
+
# ========================================
|
|
339
|
+
# LIFECYCLE EVENTS
|
|
340
|
+
# ========================================
|
|
341
|
+
|
|
342
|
+
def on_startup(self, func: Callable):
|
|
343
|
+
"""Register startup handler"""
|
|
344
|
+
self.startup_handlers.append(func)
|
|
345
|
+
return func
|
|
346
|
+
|
|
347
|
+
def on_shutdown(self, func: Callable):
|
|
348
|
+
"""Register shutdown handler"""
|
|
349
|
+
self.shutdown_handlers.append(func)
|
|
350
|
+
return func
|
|
351
|
+
|
|
352
|
+
# ========================================
|
|
353
|
+
# SERVER RUNNER
|
|
354
|
+
# ========================================
|
|
355
|
+
|
|
356
|
+
def run(self, host: str = "127.0.0.1", port: int = 8000, reload: bool = False):
|
|
357
|
+
"""Run the application"""
|
|
358
|
+
from .server import run_server
|
|
359
|
+
|
|
360
|
+
logger.info("Starting CREATESONLINE Pure Python Server")
|
|
361
|
+
logger.info(f"Framework: CREATESONLINE v{__version__}")
|
|
362
|
+
run_server(self, host=host, port=port, reload=reload)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
class CreatesonlineInternalRequest:
|
|
366
|
+
"""Internal request object"""
|
|
367
|
+
|
|
368
|
+
def __init__(self, scope, receive):
|
|
369
|
+
self.scope = scope
|
|
370
|
+
self.receive = receive
|
|
371
|
+
self.path = scope['path']
|
|
372
|
+
self.method = scope['method']
|
|
373
|
+
self.headers = dict(scope.get('headers', []))
|
|
374
|
+
self.query_params = self._parse_query_string(scope.get('query_string', b''))
|
|
375
|
+
self.path_params = scope.get('path_params', {})
|
|
376
|
+
|
|
377
|
+
def _parse_query_string(self, query_string):
|
|
378
|
+
"""Parse query string into dict"""
|
|
379
|
+
if not query_string:
|
|
380
|
+
return {}
|
|
381
|
+
|
|
382
|
+
params = {}
|
|
383
|
+
for pair in query_string.decode().split('&'):
|
|
384
|
+
if '=' in pair:
|
|
385
|
+
key, value = pair.split('=', 1)
|
|
386
|
+
params[key] = value
|
|
387
|
+
return params
|
|
388
|
+
|
|
389
|
+
async def json(self):
|
|
390
|
+
"""Parse JSON body"""
|
|
391
|
+
body = await self._get_body()
|
|
392
|
+
return json.loads(body.decode())
|
|
393
|
+
|
|
394
|
+
async def _get_body(self):
|
|
395
|
+
"""Get request body"""
|
|
396
|
+
body = b''
|
|
397
|
+
while True:
|
|
398
|
+
message = await self.receive()
|
|
399
|
+
if message['type'] == 'http.request':
|
|
400
|
+
body += message.get('body', b'')
|
|
401
|
+
if not message.get('more_body', False):
|
|
402
|
+
break
|
|
403
|
+
return body
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class CreatesonlineInternalAI:
|
|
407
|
+
"""Internal AI services"""
|
|
408
|
+
|
|
409
|
+
def __init__(self):
|
|
410
|
+
self.cache = {}
|
|
411
|
+
|
|
412
|
+
async def generate_text(self, prompt: str, **kwargs) -> str:
|
|
413
|
+
"""Generate text using internal algorithms"""
|
|
414
|
+
templates = {
|
|
415
|
+
"hello": "Hello! Welcome to CREATESONLINE - the AI-Native framework.",
|
|
416
|
+
"describe": f"CREATESONLINE is an innovative AI-native web framework.",
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
prompt_lower = prompt.lower()
|
|
420
|
+
for key, template in templates.items():
|
|
421
|
+
if key in prompt_lower:
|
|
422
|
+
return template
|
|
423
|
+
|
|
424
|
+
return f"CREATESONLINE AI Response: Generated content for '{prompt[:50]}...'"
|
|
425
|
+
|
|
426
|
+
def get_embedding(self, text: str, dimensions: int = 128) -> List[float]:
|
|
427
|
+
"""Generate hash-based embeddings"""
|
|
428
|
+
hash_obj = hashlib.md5(text.encode())
|
|
429
|
+
hash_bytes = hash_obj.digest()
|
|
430
|
+
|
|
431
|
+
embedding = []
|
|
432
|
+
for i in range(dimensions):
|
|
433
|
+
byte_index = i % len(hash_bytes)
|
|
434
|
+
value = (hash_bytes[byte_index] / 255.0) - 0.5
|
|
435
|
+
embedding.append(value)
|
|
436
|
+
|
|
437
|
+
return embedding
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
# ========================================
|
|
441
|
+
# MAIN FRAMEWORK API
|
|
442
|
+
# ========================================
|
|
443
|
+
|
|
444
|
+
def create_app(
|
|
445
|
+
title: str = "CREATESONLINE Application",
|
|
446
|
+
description: str = "AI-powered application built with CREATESONLINE",
|
|
447
|
+
version: str = "1.0.0",
|
|
448
|
+
ai_config: Optional[Dict[str, Any]] = None,
|
|
449
|
+
debug: bool = False,
|
|
450
|
+
auto_init: bool = True,
|
|
451
|
+
**kwargs
|
|
452
|
+
) -> CreatesonlineInternalApp:
|
|
453
|
+
"""Create a CREATESONLINE application instance
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
title: Application title
|
|
457
|
+
description: Application description
|
|
458
|
+
version: Application version
|
|
459
|
+
ai_config: AI configuration dictionary
|
|
460
|
+
debug: Enable debug mode
|
|
461
|
+
auto_init: Automatically initialize project structure if needed (default: True)
|
|
462
|
+
**kwargs: Additional configuration
|
|
463
|
+
"""
|
|
464
|
+
|
|
465
|
+
# Auto-initialize project structure if needed (silent)
|
|
466
|
+
if auto_init:
|
|
467
|
+
try:
|
|
468
|
+
from .project_init import init_project_if_needed
|
|
469
|
+
init_project_if_needed(verbose=False) # Silent initialization
|
|
470
|
+
except Exception:
|
|
471
|
+
pass # Silent failure - don't break app startup
|
|
472
|
+
|
|
473
|
+
# TRY: Use full-featured app if available
|
|
474
|
+
try:
|
|
475
|
+
from createsonline.config.app import CreatesonlineApp
|
|
476
|
+
logger.info("Loading full-featured CREATESONLINE...")
|
|
477
|
+
app_instance = CreatesonlineApp(
|
|
478
|
+
title=title,
|
|
479
|
+
description=description,
|
|
480
|
+
version=version,
|
|
481
|
+
ai_config=ai_config or {},
|
|
482
|
+
debug=debug,
|
|
483
|
+
**kwargs
|
|
484
|
+
)
|
|
485
|
+
except ImportError:
|
|
486
|
+
# FALLBACK: Use internal core
|
|
487
|
+
logger.info("Using CREATESONLINE Internal Core")
|
|
488
|
+
app_instance = CreatesonlineInternalApp(
|
|
489
|
+
title=title,
|
|
490
|
+
description=description,
|
|
491
|
+
version=version,
|
|
492
|
+
ai_config=ai_config or {},
|
|
493
|
+
debug=debug,
|
|
494
|
+
**kwargs
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
# Auto-discover and register routes from routes.py (if exists)
|
|
498
|
+
# DEFERRED: Will be applied at first request to override any @app.get decorators
|
|
499
|
+
if auto_init:
|
|
500
|
+
try:
|
|
501
|
+
# Store the app instance for deferred route loading
|
|
502
|
+
app_instance._needs_route_discovery = True
|
|
503
|
+
except Exception:
|
|
504
|
+
pass
|
|
505
|
+
|
|
506
|
+
return app_instance
|