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.
Files changed (152) hide show
  1. createsonline/__init__.py +46 -0
  2. createsonline/admin/__init__.py +7 -0
  3. createsonline/admin/content.py +526 -0
  4. createsonline/admin/crud.py +805 -0
  5. createsonline/admin/field_builder.py +559 -0
  6. createsonline/admin/integration.py +482 -0
  7. createsonline/admin/interface.py +2562 -0
  8. createsonline/admin/model_creator.py +513 -0
  9. createsonline/admin/model_manager.py +388 -0
  10. createsonline/admin/modern_dashboard.py +498 -0
  11. createsonline/admin/permissions.py +264 -0
  12. createsonline/admin/user_forms.py +594 -0
  13. createsonline/ai/__init__.py +202 -0
  14. createsonline/ai/fields.py +1226 -0
  15. createsonline/ai/orm.py +325 -0
  16. createsonline/ai/services.py +1244 -0
  17. createsonline/app.py +506 -0
  18. createsonline/auth/__init__.py +8 -0
  19. createsonline/auth/management.py +228 -0
  20. createsonline/auth/models.py +552 -0
  21. createsonline/cli/__init__.py +5 -0
  22. createsonline/cli/commands/__init__.py +122 -0
  23. createsonline/cli/commands/database.py +416 -0
  24. createsonline/cli/commands/info.py +173 -0
  25. createsonline/cli/commands/initdb.py +218 -0
  26. createsonline/cli/commands/project.py +545 -0
  27. createsonline/cli/commands/serve.py +173 -0
  28. createsonline/cli/commands/shell.py +93 -0
  29. createsonline/cli/commands/users.py +148 -0
  30. createsonline/cli/main.py +2041 -0
  31. createsonline/cli/manage.py +274 -0
  32. createsonline/config/__init__.py +9 -0
  33. createsonline/config/app.py +2577 -0
  34. createsonline/config/database.py +179 -0
  35. createsonline/config/docs.py +384 -0
  36. createsonline/config/errors.py +160 -0
  37. createsonline/config/orm.py +43 -0
  38. createsonline/config/request.py +93 -0
  39. createsonline/config/settings.py +176 -0
  40. createsonline/data/__init__.py +23 -0
  41. createsonline/data/dataframe.py +925 -0
  42. createsonline/data/io.py +453 -0
  43. createsonline/data/series.py +557 -0
  44. createsonline/database/__init__.py +60 -0
  45. createsonline/database/abstraction.py +440 -0
  46. createsonline/database/assistant.py +585 -0
  47. createsonline/database/fields.py +442 -0
  48. createsonline/database/migrations.py +132 -0
  49. createsonline/database/models.py +604 -0
  50. createsonline/database.py +438 -0
  51. createsonline/http/__init__.py +28 -0
  52. createsonline/http/client.py +535 -0
  53. createsonline/ml/__init__.py +55 -0
  54. createsonline/ml/classification.py +552 -0
  55. createsonline/ml/clustering.py +680 -0
  56. createsonline/ml/metrics.py +542 -0
  57. createsonline/ml/neural.py +560 -0
  58. createsonline/ml/preprocessing.py +784 -0
  59. createsonline/ml/regression.py +501 -0
  60. createsonline/performance/__init__.py +19 -0
  61. createsonline/performance/cache.py +444 -0
  62. createsonline/performance/compression.py +335 -0
  63. createsonline/performance/core.py +419 -0
  64. createsonline/project_init.py +789 -0
  65. createsonline/routing.py +528 -0
  66. createsonline/security/__init__.py +34 -0
  67. createsonline/security/core.py +811 -0
  68. createsonline/security/encryption.py +349 -0
  69. createsonline/server.py +295 -0
  70. createsonline/static/css/admin.css +263 -0
  71. createsonline/static/css/common.css +358 -0
  72. createsonline/static/css/dashboard.css +89 -0
  73. createsonline/static/favicon.ico +0 -0
  74. createsonline/static/icons/icon-128x128.png +0 -0
  75. createsonline/static/icons/icon-128x128.webp +0 -0
  76. createsonline/static/icons/icon-16x16.png +0 -0
  77. createsonline/static/icons/icon-16x16.webp +0 -0
  78. createsonline/static/icons/icon-180x180.png +0 -0
  79. createsonline/static/icons/icon-180x180.webp +0 -0
  80. createsonline/static/icons/icon-192x192.png +0 -0
  81. createsonline/static/icons/icon-192x192.webp +0 -0
  82. createsonline/static/icons/icon-256x256.png +0 -0
  83. createsonline/static/icons/icon-256x256.webp +0 -0
  84. createsonline/static/icons/icon-32x32.png +0 -0
  85. createsonline/static/icons/icon-32x32.webp +0 -0
  86. createsonline/static/icons/icon-384x384.png +0 -0
  87. createsonline/static/icons/icon-384x384.webp +0 -0
  88. createsonline/static/icons/icon-48x48.png +0 -0
  89. createsonline/static/icons/icon-48x48.webp +0 -0
  90. createsonline/static/icons/icon-512x512.png +0 -0
  91. createsonline/static/icons/icon-512x512.webp +0 -0
  92. createsonline/static/icons/icon-64x64.png +0 -0
  93. createsonline/static/icons/icon-64x64.webp +0 -0
  94. createsonline/static/image/android-chrome-192x192.png +0 -0
  95. createsonline/static/image/android-chrome-512x512.png +0 -0
  96. createsonline/static/image/apple-touch-icon.png +0 -0
  97. createsonline/static/image/favicon-16x16.png +0 -0
  98. createsonline/static/image/favicon-32x32.png +0 -0
  99. createsonline/static/image/favicon.ico +0 -0
  100. createsonline/static/image/favicon.svg +17 -0
  101. createsonline/static/image/icon-128x128.png +0 -0
  102. createsonline/static/image/icon-128x128.webp +0 -0
  103. createsonline/static/image/icon-16x16.png +0 -0
  104. createsonline/static/image/icon-16x16.webp +0 -0
  105. createsonline/static/image/icon-180x180.png +0 -0
  106. createsonline/static/image/icon-180x180.webp +0 -0
  107. createsonline/static/image/icon-192x192.png +0 -0
  108. createsonline/static/image/icon-192x192.webp +0 -0
  109. createsonline/static/image/icon-256x256.png +0 -0
  110. createsonline/static/image/icon-256x256.webp +0 -0
  111. createsonline/static/image/icon-32x32.png +0 -0
  112. createsonline/static/image/icon-32x32.webp +0 -0
  113. createsonline/static/image/icon-384x384.png +0 -0
  114. createsonline/static/image/icon-384x384.webp +0 -0
  115. createsonline/static/image/icon-48x48.png +0 -0
  116. createsonline/static/image/icon-48x48.webp +0 -0
  117. createsonline/static/image/icon-512x512.png +0 -0
  118. createsonline/static/image/icon-512x512.webp +0 -0
  119. createsonline/static/image/icon-64x64.png +0 -0
  120. createsonline/static/image/icon-64x64.webp +0 -0
  121. createsonline/static/image/logo-header-h100.png +0 -0
  122. createsonline/static/image/logo-header-h100.webp +0 -0
  123. createsonline/static/image/logo-header-h200@2x.png +0 -0
  124. createsonline/static/image/logo-header-h200@2x.webp +0 -0
  125. createsonline/static/image/logo.png +0 -0
  126. createsonline/static/js/admin.js +274 -0
  127. createsonline/static/site.webmanifest +35 -0
  128. createsonline/static/templates/admin/base.html +87 -0
  129. createsonline/static/templates/admin/dashboard.html +217 -0
  130. createsonline/static/templates/admin/model_form.html +270 -0
  131. createsonline/static/templates/admin/model_list.html +202 -0
  132. createsonline/static/test_script.js +15 -0
  133. createsonline/static/test_styles.css +59 -0
  134. createsonline/static_files.py +365 -0
  135. createsonline/templates/404.html +100 -0
  136. createsonline/templates/admin_login.html +169 -0
  137. createsonline/templates/base.html +102 -0
  138. createsonline/templates/index.html +151 -0
  139. createsonline/templates.py +205 -0
  140. createsonline/testing.py +322 -0
  141. createsonline/utils.py +448 -0
  142. createsonline/validation/__init__.py +49 -0
  143. createsonline/validation/fields.py +598 -0
  144. createsonline/validation/models.py +504 -0
  145. createsonline/validation/validators.py +561 -0
  146. createsonline/views.py +184 -0
  147. createsonline-0.1.26.dist-info/METADATA +46 -0
  148. createsonline-0.1.26.dist-info/RECORD +152 -0
  149. createsonline-0.1.26.dist-info/WHEEL +5 -0
  150. createsonline-0.1.26.dist-info/entry_points.txt +2 -0
  151. createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
  152. createsonline-0.1.26.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1226 @@
1
+ # createsonline/ai/fields.py
2
+ """
3
+ CREATESONLINE AI Field Types - COMPLETE INTERNAL IMPLEMENTATION
4
+
5
+ Intelligent field types that automatically compute values using AI models,
6
+ generate content with LLMs, and store vector embeddings for similarity search.
7
+ """
8
+ import hashlib
9
+ import json
10
+ import re
11
+ import math
12
+ import random
13
+ from datetime import datetime
14
+ from typing import Any, Dict, List, Optional
15
+
16
+ # Internal fallbacks for external dependencies
17
+ try:
18
+ import sqlalchemy as sa
19
+ from sqlalchemy import Column, Float, Integer, String, Text, JSON
20
+ from sqlalchemy.types import TypeDecorator, UserDefinedType
21
+ SA_AVAILABLE = True
22
+ except ImportError:
23
+ SA_AVAILABLE = False
24
+ # Create mock SQLAlchemy components
25
+ class MockSQLAlchemy:
26
+ Float = "Float"
27
+ Integer = "Integer"
28
+ String = lambda x: f"String({x})"
29
+ Text = "Text"
30
+ JSON = "JSON"
31
+ Column = lambda *args, **kwargs: f"Column({args}, {kwargs})"
32
+ sa = MockSQLAlchemy()
33
+
34
+ # ========================================
35
+ # INTERNAL AI SERVICES
36
+ # ========================================
37
+
38
+ class InternalAIEngine:
39
+ """Pure Python AI engine with mock/basic implementations"""
40
+
41
+ def __init__(self):
42
+ self.cache = {}
43
+ self.models = {}
44
+
45
+ def hash_text(self, text: str) -> str:
46
+ """Generate consistent hash for text"""
47
+ return hashlib.md5(text.encode()).hexdigest()
48
+
49
+ def generate_embedding(self, text: str, dimensions: int = 768) -> List[float]:
50
+ """Generate consistent mock embedding from text"""
51
+ hash_val = self.hash_text(text)
52
+
53
+ # Use hash to seed deterministic "embedding"
54
+ embedding = []
55
+ for i in range(dimensions):
56
+ # Create pseudo-random but deterministic values
57
+ seed_char = hash_val[i % len(hash_val)]
58
+ seed_value = ord(seed_char) / 255.0 # Normalize to [0,1]
59
+
60
+ # Apply some math to spread values
61
+ value = math.sin(seed_value * math.pi * 2) * 0.5
62
+ embedding.append(value)
63
+
64
+ return embedding
65
+
66
+ def similarity(self, vec1: List[float], vec2: List[float]) -> float:
67
+ """Calculate cosine similarity"""
68
+ try:
69
+ # Dot product
70
+ dot_product = sum(a * b for a, b in zip(vec1, vec2))
71
+
72
+ # Magnitudes
73
+ mag1 = math.sqrt(sum(a * a for a in vec1))
74
+ mag2 = math.sqrt(sum(b * b for b in vec2))
75
+
76
+ if mag1 == 0 or mag2 == 0:
77
+ return 0.0
78
+
79
+ return dot_product / (mag1 * mag2)
80
+ except:
81
+ return 0.0
82
+
83
+ def generate_text(self, prompt: str, max_tokens: int = 100) -> str:
84
+ """Generate mock text based on prompt"""
85
+ prompt_words = prompt.lower().split()
86
+
87
+ # Simple rule-based generation
88
+ if any(word in prompt_words for word in ['summary', 'summarize']):
89
+ return f"Summary: {prompt[:50]}... (Generated by CREATESONLINE AI)"
90
+ elif any(word in prompt_words for word in ['title', 'headline']):
91
+ return f"Title: {prompt.split()[-3:]} - AI Generated"
92
+ elif any(word in prompt_words for word in ['description', 'explain']):
93
+ return f"This is an AI-generated description based on: {prompt[:40]}..."
94
+ else:
95
+ return f"AI Response: Generated content for '{prompt[:30]}...' using CREATESONLINE"
96
+
97
+ def classify_text(self, text: str, categories: List[str] = None) -> Dict[str, float]:
98
+ """Basic text classification"""
99
+ if not categories:
100
+ categories = ["positive", "negative", "neutral"]
101
+
102
+ text_lower = text.lower()
103
+ scores = {}
104
+
105
+ # Simple keyword-based classification
106
+ positive_words = {"good", "great", "excellent", "amazing", "wonderful", "fantastic"}
107
+ negative_words = {"bad", "terrible", "awful", "horrible", "disappointing", "poor"}
108
+
109
+ positive_count = sum(1 for word in positive_words if word in text_lower)
110
+ negative_count = sum(1 for word in negative_words if word in text_lower)
111
+
112
+ if "positive" in categories:
113
+ scores["positive"] = min(1.0, positive_count * 0.3 + 0.1)
114
+ if "negative" in categories:
115
+ scores["negative"] = min(1.0, negative_count * 0.3 + 0.1)
116
+ if "neutral" in categories:
117
+ scores["neutral"] = 1.0 - max(scores.get("positive", 0), scores.get("negative", 0))
118
+
119
+ return scores
120
+
121
+ def predict_numeric(self, features: Dict[str, Any]) -> float:
122
+ """Mock numeric prediction"""
123
+ # Simple linear combination with some randomness
124
+ feature_sum = 0
125
+ for key, value in features.items():
126
+ if isinstance(value, (int, float)):
127
+ feature_sum += value
128
+ elif isinstance(value, str):
129
+ feature_sum += len(value) * 0.1
130
+
131
+ # Add some deterministic "AI magic"
132
+ hash_val = self.hash_text(str(features))
133
+ seed = int(hash_val[:8], 16) % 100
134
+ prediction = (feature_sum * 0.1 + seed * 0.01) % 1.0
135
+
136
+ return prediction
137
+
138
+ # Global AI engine instance
139
+ _ai_engine = InternalAIEngine()
140
+
141
+ # ========================================
142
+ # BASE AI FIELD FUNCTIONALITY
143
+ # ========================================
144
+
145
+ class AIFieldMixin:
146
+ """Base mixin for AI-enhanced fields with internal implementations"""
147
+
148
+ def __init__(self, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
149
+ """Initialize AI field with configuration"""
150
+ self.ai_config = ai_config or {}
151
+ self.ai_enabled = True
152
+ self.ai_cache_enabled = True
153
+ self.ai_cache_ttl = 3600 # 1 hour
154
+ self._ai_cache = {}
155
+
156
+ # Default AI configuration
157
+ self._setup_ai_defaults()
158
+
159
+ def _setup_ai_defaults(self):
160
+ """Setup default AI configuration"""
161
+ defaults = {
162
+ "enable_caching": True,
163
+ "cache_ttl": 3600,
164
+ "fallback_value": None,
165
+ "confidence_threshold": 0.5,
166
+ "mock_mode": True, # Use internal implementations by default
167
+ "provider": "internal"
168
+ }
169
+
170
+ for key, value in defaults.items():
171
+ if key not in self.ai_config:
172
+ self.ai_config[key] = value
173
+
174
+ def get_ai_service(self, service_type: str = "internal"):
175
+ """Get AI service - always returns internal engine"""
176
+ return _ai_engine
177
+
178
+ def generate_cache_key(self, input_data: Any) -> str:
179
+ """Generate cache key for AI operations"""
180
+ if isinstance(input_data, (dict, list)):
181
+ input_str = json.dumps(input_data, sort_keys=True, default=str)
182
+ else:
183
+ input_str = str(input_data)
184
+
185
+ cache_data = {
186
+ "input": input_str,
187
+ "config": {k: v for k, v in self.ai_config.items() if k != "api_key"},
188
+ "field_type": self.__class__.__name__
189
+ }
190
+
191
+ cache_str = json.dumps(cache_data, sort_keys=True)
192
+ return hashlib.md5(cache_str.encode()).hexdigest()
193
+
194
+ def is_cache_valid(self, cache_key: str) -> bool:
195
+ """Check if cached result is still valid"""
196
+ if not self.ai_cache_enabled or cache_key not in self._ai_cache:
197
+ return False
198
+
199
+ cached_time = self._ai_cache[cache_key].get("timestamp", 0)
200
+ return (datetime.utcnow().timestamp() - cached_time) < self.ai_cache_ttl
201
+
202
+ def get_cached_result(self, cache_key: str) -> Any:
203
+ """Get cached AI result"""
204
+ if self.is_cache_valid(cache_key):
205
+ return self._ai_cache[cache_key]["result"]
206
+ return None
207
+
208
+ def set_cached_result(self, cache_key: str, result: Any):
209
+ """Cache AI result"""
210
+ if self.ai_cache_enabled:
211
+ self._ai_cache[cache_key] = {
212
+ "result": result,
213
+ "timestamp": datetime.utcnow().timestamp()
214
+ }
215
+
216
+ # ========================================
217
+ # AI FIELD UTILITIES AND HELPERS
218
+ # ========================================
219
+
220
+ class AIFieldManager:
221
+ """Manager for AI field operations across models"""
222
+
223
+ def __init__(self):
224
+ self.registered_fields = {}
225
+ self.compute_queue = []
226
+ self.stats = {
227
+ "computations": 0,
228
+ "cache_hits": 0,
229
+ "cache_misses": 0,
230
+ "errors": 0
231
+ }
232
+
233
+ def register_field(self, model_class, field_name, field_instance):
234
+ """Register an AI field for management"""
235
+ model_key = f"{model_class.__module__}.{model_class.__name__}"
236
+ if model_key not in self.registered_fields:
237
+ self.registered_fields[model_key] = {}
238
+
239
+ self.registered_fields[model_key][field_name] = field_instance
240
+
241
+ async def compute_all_fields(self, instance):
242
+ """Compute all AI fields for a model instance"""
243
+ model_key = f"{instance.__class__.__module__}.{instance.__class__.__name__}"
244
+
245
+ if model_key not in self.registered_fields:
246
+ return
247
+
248
+ for field_name, field_instance in self.registered_fields[model_key].items():
249
+ try:
250
+ await self._compute_field(instance, field_name, field_instance)
251
+ self.stats["computations"] += 1
252
+ except Exception as e:
253
+ self.stats["errors"] += 1
254
+
255
+ async def _compute_field(self, instance, field_name, field_instance):
256
+ """Compute a specific AI field"""
257
+ if isinstance(field_instance, AIComputedField):
258
+ features = self._extract_features(instance, field_instance)
259
+ value = await field_instance.compute_value(instance, features)
260
+ setattr(instance, field_name, value)
261
+
262
+ elif isinstance(field_instance, LLMField):
263
+ template_data = self._extract_template_data(instance, field_instance)
264
+ content = await field_instance.generate_content(instance, template_data)
265
+ setattr(instance, field_name, content)
266
+
267
+ elif isinstance(field_instance, VectorField):
268
+ source_data = self._extract_source_data(instance, field_instance)
269
+ embedding = await field_instance.generate_embedding(instance, source_data)
270
+ setattr(instance, field_name, embedding)
271
+
272
+ elif isinstance(field_instance, SmartTextField):
273
+ text_value = getattr(instance, field_name, "")
274
+ if text_value:
275
+ analysis = await field_instance.analyze_text(text_value)
276
+ # Store analysis in a related field or instance metadata
277
+ setattr(instance, f"{field_name}_analysis", analysis)
278
+
279
+ def _extract_features(self, instance, field_instance):
280
+ """Extract features for AI computation"""
281
+ features = {}
282
+ feature_fields = field_instance.ai_config.get('features', [])
283
+ source_field = field_instance.ai_config.get('source_field')
284
+
285
+ if feature_fields:
286
+ for feature_field in feature_fields:
287
+ if hasattr(instance, feature_field):
288
+ features[feature_field] = getattr(instance, feature_field)
289
+ elif source_field:
290
+ if hasattr(instance, source_field):
291
+ features[source_field] = getattr(instance, source_field)
292
+ else:
293
+ # Extract all non-AI fields as features
294
+ for attr_name in dir(instance):
295
+ if not attr_name.startswith('_') and hasattr(instance, attr_name):
296
+ value = getattr(instance, attr_name)
297
+ if isinstance(value, (str, int, float, bool)) and value is not None:
298
+ features[attr_name] = value
299
+
300
+ return features
301
+
302
+ def _extract_template_data(self, instance, field_instance):
303
+ """Extract template data for LLM generation"""
304
+ template_data = {}
305
+
306
+ # Extract all suitable fields as template variables
307
+ for attr_name in dir(instance):
308
+ if not attr_name.startswith('_') and hasattr(instance, attr_name):
309
+ value = getattr(instance, attr_name)
310
+ if isinstance(value, (str, int, float, bool)) and value is not None:
311
+ template_data[attr_name] = value
312
+
313
+ return template_data
314
+
315
+ def _extract_source_data(self, instance, field_instance):
316
+ """Extract source data for vector embedding"""
317
+ source_field = field_instance.ai_config.get('source_field')
318
+
319
+ if source_field and hasattr(instance, source_field):
320
+ return getattr(instance, source_field)
321
+
322
+ # Fallback to common text fields
323
+ for fallback_field in ['description', 'content', 'text', 'name', 'title']:
324
+ if hasattr(instance, fallback_field):
325
+ value = getattr(instance, fallback_field)
326
+ if value:
327
+ return value
328
+
329
+ return str(instance)
330
+
331
+ def get_stats(self):
332
+ """Get AI field computation statistics"""
333
+ return self.stats.copy()
334
+
335
+ # Global AI field manager
336
+ _ai_field_manager = AIFieldManager()
337
+
338
+ def get_ai_field_manager():
339
+ """Get the global AI field manager"""
340
+ return _ai_field_manager
341
+
342
+ # ========================================
343
+ # MODEL INTEGRATION HELPERS
344
+ # ========================================
345
+
346
+ class AIModelMixin:
347
+ """Mixin for models that use AI fields"""
348
+
349
+ def __init__(self, *args, **kwargs):
350
+ super().__init__(*args, **kwargs)
351
+ self._register_ai_fields()
352
+
353
+ def _register_ai_fields(self):
354
+ """Register AI fields with the field manager"""
355
+ for attr_name in dir(self.__class__):
356
+ attr = getattr(self.__class__, attr_name)
357
+ if isinstance(attr, AIFieldMixin):
358
+ _ai_field_manager.register_field(self.__class__, attr_name, attr)
359
+
360
+ async def compute_ai_fields(self):
361
+ """Compute all AI fields for this instance"""
362
+ await _ai_field_manager.compute_all_fields(self)
363
+
364
+ async def compute_field(self, field_name):
365
+ """Compute a specific AI field"""
366
+ field_instance = getattr(self.__class__, field_name, None)
367
+ if field_instance and isinstance(field_instance, AIFieldMixin):
368
+ await _ai_field_manager._compute_field(self, field_name, field_instance)
369
+
370
+ # ========================================
371
+ # VALIDATION AND TYPE CHECKING
372
+ # ========================================
373
+
374
+ def validate_ai_config(config: Dict[str, Any], field_type: str) -> Dict[str, Any]:
375
+ """Validate and normalize AI configuration"""
376
+
377
+ # Common validation
378
+ validated = config.copy()
379
+
380
+ # Ensure required fields exist
381
+ if "provider" not in validated:
382
+ validated["provider"] = "internal"
383
+
384
+ if "enable_caching" not in validated:
385
+ validated["enable_caching"] = True
386
+
387
+ # Field-specific validation
388
+ if field_type == "AIComputedField":
389
+ if "prediction_type" not in validated:
390
+ validated["prediction_type"] = "regression"
391
+
392
+ if validated["prediction_type"] not in ["classification", "regression"]:
393
+ validated["prediction_type"] = "regression"
394
+
395
+ elif field_type == "LLMField":
396
+ if "max_tokens" not in validated:
397
+ validated["max_tokens"] = 500
398
+
399
+ if "temperature" not in validated:
400
+ validated["temperature"] = 0.7
401
+
402
+ # Ensure temperature is in valid range
403
+ validated["temperature"] = max(0.0, min(2.0, validated["temperature"]))
404
+
405
+ elif field_type == "VectorField":
406
+ if "similarity_metric" not in validated:
407
+ validated["similarity_metric"] = "cosine"
408
+
409
+ if validated["similarity_metric"] not in ["cosine", "euclidean", "dot_product"]:
410
+ validated["similarity_metric"] = "cosine"
411
+
412
+ return validated
413
+
414
+ def check_ai_field_compatibility(field_instance, model_class):
415
+ """Check if AI field is compatible with model"""
416
+
417
+ issues = []
418
+
419
+ # Check if model has required source fields
420
+ if hasattr(field_instance, 'ai_config'):
421
+ source_field = field_instance.ai_config.get('source_field')
422
+ if source_field and not hasattr(model_class, source_field):
423
+ issues.append(f"Source field '{source_field}' not found in model {model_class.__name__}")
424
+
425
+ features = field_instance.ai_config.get('features', [])
426
+ for feature in features:
427
+ if not hasattr(model_class, feature):
428
+ issues.append(f"Feature field '{feature}' not found in model {model_class.__name__}")
429
+
430
+ return issues
431
+
432
+ # ========================================
433
+ # CREATESONLINE AI FIELD TYPES
434
+ # ========================================
435
+
436
+ class CreatesonlineField:
437
+ """Base CREATESONLINE field that works with or without SQLAlchemy"""
438
+
439
+ def __init__(self, field_type=None, *args, **kwargs):
440
+ self.field_type = field_type or "Text"
441
+ self.args = args
442
+ self.kwargs = kwargs
443
+ self.name = None
444
+ self.value = None
445
+
446
+ def __set_name__(self, owner, name):
447
+ """Called when field is assigned to a class"""
448
+ self.name = name
449
+
450
+ def __get__(self, instance, owner):
451
+ """Get field value"""
452
+ if instance is None:
453
+ return self
454
+ return getattr(instance, f"_{self.name}", self.value)
455
+
456
+ def __set__(self, instance, value):
457
+ """Set field value"""
458
+ setattr(instance, f"_{self.name}", value)
459
+
460
+ class AIComputedField(CreatesonlineField, AIFieldMixin):
461
+ """
462
+ Field that automatically computes values using AI models
463
+
464
+ Examples:
465
+ # Predict customer lifetime value
466
+ clv = AIComputedField("Float", ai_config={
467
+ "model": "customer_lifetime_value",
468
+ "features": ["age", "purchase_history", "engagement_score"],
469
+ "prediction_type": "regression"
470
+ })
471
+
472
+ # Classify content category
473
+ category = AIComputedField("String", ai_config={
474
+ "model": "content_classifier",
475
+ "source_field": "description",
476
+ "prediction_type": "classification"
477
+ })
478
+ """
479
+
480
+ def __init__(self, field_type="Float", *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
481
+ """Initialize AI computed field"""
482
+
483
+ # Default AI configuration for computed fields
484
+ default_config = {
485
+ "model": "default_predictor",
486
+ "prediction_type": "regression",
487
+ "confidence_threshold": 0.5,
488
+ "fallback_value": 0.0,
489
+ "enable_async": True,
490
+ "timeout": 30,
491
+ "features": [],
492
+ "source_field": None
493
+ }
494
+
495
+ ai_config = {**default_config, **(ai_config or {})}
496
+
497
+ # Initialize base classes
498
+ CreatesonlineField.__init__(self, field_type, *args, **kwargs)
499
+ AIFieldMixin.__init__(self, ai_config=ai_config)
500
+
501
+ # SQLAlchemy integration if available
502
+ if SA_AVAILABLE and field_type in ["Float", "Integer", "String", "Text"]:
503
+ try:
504
+ if field_type == "Float":
505
+ self.sql_field = sa.Column(sa.Float, *args, **kwargs)
506
+ elif field_type == "Integer":
507
+ self.sql_field = sa.Column(sa.Integer, *args, **kwargs)
508
+ elif field_type == "String":
509
+ length = kwargs.get("length", 255)
510
+ self.sql_field = sa.Column(sa.String(length), *args, **kwargs)
511
+ elif field_type == "Text":
512
+ self.sql_field = sa.Column(sa.Text, *args, **kwargs)
513
+ except:
514
+ self.sql_field = None
515
+
516
+ async def compute_value(self, instance, features_data: Dict[str, Any]) -> Any:
517
+ """Compute field value using AI model"""
518
+ if not self.ai_enabled:
519
+ return self.ai_config.get("fallback_value")
520
+
521
+ # Generate cache key
522
+ cache_key = self.generate_cache_key(features_data)
523
+
524
+ # Check cache first
525
+ cached_result = self.get_cached_result(cache_key)
526
+ if cached_result is not None:
527
+ return cached_result
528
+
529
+ try:
530
+ # Get AI service
531
+ ai_service = self.get_ai_service()
532
+
533
+ # Prepare features
534
+ processed_features = await self._preprocess_features(features_data)
535
+
536
+ # Make prediction based on type
537
+ if self.ai_config["prediction_type"] == "classification":
538
+ categories = self.ai_config.get("categories", ["positive", "negative", "neutral"])
539
+ prediction_result = ai_service.classify_text(
540
+ str(processed_features.get("text", processed_features)),
541
+ categories
542
+ )
543
+ # Return the category with highest score
544
+ final_result = max(prediction_result.items(), key=lambda x: x[1])[0]
545
+ confidence = max(prediction_result.values())
546
+ else: # regression
547
+ prediction_value = ai_service.predict_numeric(processed_features)
548
+ final_result = prediction_value
549
+ confidence = 0.8 + random.random() * 0.15 # Mock confidence
550
+
551
+ # Validate confidence
552
+ if confidence < self.ai_config["confidence_threshold"]:
553
+ return self.ai_config.get("fallback_value")
554
+
555
+ # Cache result
556
+ self.set_cached_result(cache_key, final_result)
557
+
558
+ return final_result
559
+
560
+ except Exception as e:
561
+ return self.ai_config.get("fallback_value")
562
+
563
+ async def _preprocess_features(self, features_data: Dict[str, Any]) -> Dict[str, Any]:
564
+ """Preprocess features before AI computation"""
565
+ preprocessing_func = self.ai_config.get("preprocessing")
566
+ if preprocessing_func and callable(preprocessing_func):
567
+ return await preprocessing_func(features_data)
568
+ return features_data
569
+
570
+ class LLMField(CreatesonlineField, AIFieldMixin):
571
+ """
572
+ Field that generates content using Large Language Models
573
+
574
+ Examples:
575
+ # Generate product description
576
+ description = LLMField(ai_config={
577
+ "model": "gpt-4",
578
+ "prompt_template": "Write a compelling product description for {name} with features: {features}",
579
+ "max_tokens": 200,
580
+ "temperature": 0.7
581
+ })
582
+
583
+ # Generate email subject line
584
+ subject = LLMField(ai_config={
585
+ "model": "gpt-3.5-turbo",
586
+ "prompt_template": "Create an engaging email subject for: {content}",
587
+ "max_tokens": 50
588
+ })
589
+ """
590
+
591
+ def __init__(self, field_type="Text", *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
592
+ """Initialize LLM field"""
593
+
594
+ # Default LLM configuration
595
+ default_config = {
596
+ "model": "internal-llm",
597
+ "max_tokens": 500,
598
+ "temperature": 0.7,
599
+ "provider": "internal",
600
+ "regenerate_on_change": True,
601
+ "enable_streaming": False,
602
+ "timeout": 30,
603
+ "prompt_template": "Generate content based on: {input}",
604
+ "fallback_content": ""
605
+ }
606
+
607
+ ai_config = {**default_config, **(ai_config or {})}
608
+
609
+ # Initialize base classes
610
+ CreatesonlineField.__init__(self, field_type, *args, **kwargs)
611
+ AIFieldMixin.__init__(self, ai_config=ai_config)
612
+
613
+ # SQLAlchemy integration
614
+ if SA_AVAILABLE:
615
+ try:
616
+ self.sql_field = sa.Column(sa.Text, *args, **kwargs)
617
+ except:
618
+ self.sql_field = None
619
+
620
+ async def generate_content(self, instance, template_data: Dict[str, Any]) -> str:
621
+ """Generate content using LLM"""
622
+ if not self.ai_enabled:
623
+ return self.ai_config.get("fallback_content", "")
624
+
625
+ # Generate cache key
626
+ cache_key = self.generate_cache_key(template_data)
627
+
628
+ # Check cache first
629
+ cached_result = self.get_cached_result(cache_key)
630
+ if cached_result is not None:
631
+ return cached_result
632
+
633
+ try:
634
+ # Get AI service
635
+ ai_service = self.get_ai_service()
636
+
637
+ # Build prompt from template
638
+ prompt = await self._build_prompt(template_data)
639
+
640
+ # Generate content using internal engine
641
+ generated_content = ai_service.generate_text(
642
+ prompt=prompt,
643
+ max_tokens=self.ai_config["max_tokens"]
644
+ )
645
+
646
+ # Post-process content
647
+ final_content = await self._postprocess_content(generated_content)
648
+
649
+ # Cache result
650
+ self.set_cached_result(cache_key, final_content)
651
+
652
+ return final_content
653
+
654
+ except Exception as e:
655
+ return self.ai_config.get("fallback_content", "")
656
+
657
+ async def _build_prompt(self, template_data: Dict[str, Any]) -> str:
658
+ """Build prompt from template and data"""
659
+ prompt_template = self.ai_config.get("prompt_template", "Generate content based on: {input}")
660
+
661
+ try:
662
+ return prompt_template.format(**template_data)
663
+ except KeyError as e:
664
+ # Fallback to simple input
665
+ return f"Generate content based on: {template_data}"
666
+
667
+ async def _postprocess_content(self, content: str) -> str:
668
+ """Post-process generated content"""
669
+ # Basic cleanup
670
+ content = content.strip()
671
+
672
+ # Apply custom post-processing if provided
673
+ postprocessing_func = self.ai_config.get("postprocessing")
674
+ if postprocessing_func and callable(postprocessing_func):
675
+ content = await postprocessing_func(content)
676
+
677
+ return content
678
+
679
+ class VectorField(CreatesonlineField, AIFieldMixin):
680
+ """
681
+ Field that stores vector embeddings for similarity search
682
+
683
+ Examples:
684
+ # Store document embeddings
685
+ embedding = VectorField(dimensions=768, ai_config={
686
+ "model": "text-embedding-ada-002",
687
+ "source_field": "content",
688
+ "normalize": True
689
+ })
690
+
691
+ # Store image embeddings
692
+ image_embedding = VectorField(dimensions=512, ai_config={
693
+ "model": "clip-vit-base-patch32",
694
+ "source_field": "image_path",
695
+ "provider": "internal"
696
+ })
697
+ """
698
+
699
+ def __init__(self, dimensions: int = 768, field_type="JSON", *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
700
+ """Initialize vector field"""
701
+ self.dimensions = dimensions
702
+
703
+ # Default vector configuration
704
+ default_config = {
705
+ "model": "internal-embeddings",
706
+ "provider": "internal",
707
+ "normalize": True,
708
+ "batch_size": 100,
709
+ "similarity_metric": "cosine",
710
+ "enable_indexing": True,
711
+ "source_field": None
712
+ }
713
+
714
+ ai_config = {**default_config, **(ai_config or {})}
715
+
716
+ # Initialize base classes
717
+ CreatesonlineField.__init__(self, field_type, *args, **kwargs)
718
+ AIFieldMixin.__init__(self, ai_config=ai_config)
719
+
720
+ # SQLAlchemy integration
721
+ if SA_AVAILABLE:
722
+ try:
723
+ self.sql_field = sa.Column(sa.JSON, *args, **kwargs)
724
+ except:
725
+ self.sql_field = None
726
+
727
+ def process_value(self, value):
728
+ """Process value before storing"""
729
+ if value is None:
730
+ return None
731
+
732
+ if isinstance(value, list):
733
+ # Validate dimensions
734
+ if len(value) != self.dimensions:
735
+ raise ValueError(f"Vector must have {self.dimensions} dimensions, got {len(value)}")
736
+ return json.dumps(value)
737
+
738
+ if hasattr(value, 'tolist'): # numpy array
739
+ if len(value) != self.dimensions:
740
+ raise ValueError(f"Vector must have {self.dimensions} dimensions, got {len(value)}")
741
+ return json.dumps(value.tolist())
742
+
743
+ if isinstance(value, str):
744
+ try:
745
+ parsed = json.loads(value)
746
+ if isinstance(parsed, list) and len(parsed) == self.dimensions:
747
+ return value
748
+ except:
749
+ pass
750
+
751
+ raise ValueError(f"Unsupported vector type: {type(value)}")
752
+
753
+ def parse_value(self, value):
754
+ """Parse value when loading"""
755
+ if value is None:
756
+ return None
757
+
758
+ if isinstance(value, str):
759
+ return json.loads(value)
760
+
761
+ return value
762
+
763
+ async def generate_embedding(self, instance, source_data: Any) -> List[float]:
764
+ """Generate vector embedding from source data"""
765
+ if not self.ai_enabled:
766
+ return [0.0] * self.dimensions
767
+
768
+ # Generate cache key
769
+ cache_key = self.generate_cache_key(source_data)
770
+
771
+ # Check cache first
772
+ cached_result = self.get_cached_result(cache_key)
773
+ if cached_result is not None:
774
+ return cached_result
775
+
776
+ try:
777
+ # Preprocess source data
778
+ processed_data = await self._preprocess_data(source_data)
779
+
780
+ # Get embedding service (always internal)
781
+ ai_service = self.get_ai_service()
782
+
783
+ # Generate embedding
784
+ embedding = ai_service.generate_embedding(
785
+ text=processed_data,
786
+ dimensions=self.dimensions
787
+ )
788
+
789
+ # Normalize if requested
790
+ if self.ai_config["normalize"]:
791
+ embedding = self._normalize_vector(embedding)
792
+
793
+ # Validate dimensions
794
+ if len(embedding) != self.dimensions:
795
+ # Pad or truncate to match dimensions
796
+ if len(embedding) < self.dimensions:
797
+ embedding.extend([0.0] * (self.dimensions - len(embedding)))
798
+ else:
799
+ embedding = embedding[:self.dimensions]
800
+
801
+ # Cache result
802
+ self.set_cached_result(cache_key, embedding)
803
+
804
+ return embedding
805
+
806
+ except Exception as e:
807
+ return [0.0] * self.dimensions
808
+
809
+ async def _preprocess_data(self, data: Any) -> str:
810
+ """Preprocess data before embedding generation"""
811
+ if isinstance(data, str):
812
+ return data
813
+ elif isinstance(data, (dict, list)):
814
+ return json.dumps(data, default=str)
815
+ else:
816
+ return str(data)
817
+
818
+ def _normalize_vector(self, vector: List[float]) -> List[float]:
819
+ """Normalize vector to unit length"""
820
+ try:
821
+ norm = math.sqrt(sum(x * x for x in vector))
822
+ if norm == 0:
823
+ return vector
824
+ return [x / norm for x in vector]
825
+ except:
826
+ return vector
827
+
828
+ def similarity(self, vector1: List[float], vector2: List[float]) -> float:
829
+ """Calculate similarity between two vectors"""
830
+ ai_service = self.get_ai_service()
831
+ return ai_service.similarity(vector1, vector2)
832
+
833
+ class SmartTextField(CreatesonlineField, AIFieldMixin):
834
+ """
835
+ Enhanced text field with AI analysis capabilities
836
+
837
+ Examples:
838
+ # Analyze sentiment and extract keywords
839
+ content = SmartTextField(ai_config={
840
+ "analyze_sentiment": True,
841
+ "extract_keywords": True,
842
+ "detect_language": True,
843
+ "content_moderation": True
844
+ })
845
+ """
846
+
847
+ def __init__(self, field_type="Text", *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
848
+ """Initialize smart text field"""
849
+
850
+ default_config = {
851
+ "analyze_sentiment": False,
852
+ "extract_keywords": False,
853
+ "detect_language": False,
854
+ "content_moderation": False,
855
+ "summarize": False,
856
+ "auto_enhance": False
857
+ }
858
+
859
+ ai_config = {**default_config, **(ai_config or {})}
860
+
861
+ # Initialize base classes
862
+ CreatesonlineField.__init__(self, field_type, *args, **kwargs)
863
+ AIFieldMixin.__init__(self, ai_config=ai_config)
864
+
865
+ # SQLAlchemy integration
866
+ if SA_AVAILABLE:
867
+ try:
868
+ self.sql_field = sa.Column(sa.Text, *args, **kwargs)
869
+ except:
870
+ self.sql_field = None
871
+
872
+ async def analyze_text(self, text: str) -> Dict[str, Any]:
873
+ """Perform AI analysis on text content"""
874
+ if not self.ai_enabled or not text:
875
+ return {}
876
+
877
+ cache_key = self.generate_cache_key(text)
878
+ cached_result = self.get_cached_result(cache_key)
879
+ if cached_result is not None:
880
+ return cached_result
881
+
882
+ analysis_results = {}
883
+
884
+ try:
885
+ ai_service = self.get_ai_service()
886
+
887
+ # Sentiment analysis
888
+ if self.ai_config["analyze_sentiment"]:
889
+ sentiment_scores = ai_service.classify_text(text, ["positive", "negative", "neutral"])
890
+ analysis_results["sentiment"] = {
891
+ "label": max(sentiment_scores.items(), key=lambda x: x[1])[0],
892
+ "scores": sentiment_scores
893
+ }
894
+
895
+ # Keyword extraction (simple implementation)
896
+ if self.ai_config["extract_keywords"]:
897
+ words = re.findall(r'\b\w+\b', text.lower())
898
+ # Filter common words and get unique words by frequency
899
+ common_words = {"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "by"}
900
+ keywords = [word for word in set(words) if len(word) > 3 and word not in common_words]
901
+ analysis_results["keywords"] = keywords[:10] # Top 10
902
+
903
+ # Language detection (simple heuristic)
904
+ if self.ai_config["detect_language"]:
905
+ if any(word in text.lower() for word in ['hola', 'gracias', 'por favor', 'español']):
906
+ language = 'es'
907
+ elif any(word in text.lower() for word in ['bonjour', 'merci', 'français']):
908
+ language = 'fr'
909
+ elif any(word in text.lower() for word in ['guten tag', 'danke', 'deutsch']):
910
+ language = 'de'
911
+ else:
912
+ language = 'en'
913
+ analysis_results["language"] = language
914
+
915
+ # Content moderation (basic)
916
+ if self.ai_config["content_moderation"]:
917
+ flagged_words = {"spam", "scam", "offensive", "inappropriate"}
918
+ is_flagged = any(word in text.lower() for word in flagged_words)
919
+ analysis_results["moderation"] = {
920
+ "flagged": is_flagged,
921
+ "confidence": 0.8 if is_flagged else 0.1
922
+ }
923
+
924
+ # Summarization
925
+ if self.ai_config["summarize"] and len(text) > 100:
926
+ summary = ai_service.generate_text(f"Summarize: {text[:200]}")
927
+ analysis_results["summary"] = summary
928
+
929
+ # Cache results
930
+ self.set_cached_result(cache_key, analysis_results)
931
+
932
+ return analysis_results
933
+
934
+ except Exception as e:
935
+ return {}
936
+
937
+ class PredictionField(AIComputedField):
938
+ """
939
+ Field that provides real-time predictions based on current data
940
+
941
+ Examples:
942
+ # Predict next purchase date
943
+ next_purchase = PredictionField("Date", ai_config={
944
+ "model": "purchase_predictor",
945
+ "features": ["last_purchase", "purchase_frequency", "user_engagement"],
946
+ "prediction_horizon": "30_days"
947
+ })
948
+ """
949
+
950
+ def __init__(self, field_type="Float", *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
951
+ """Initialize prediction field"""
952
+
953
+ default_config = {
954
+ "model": "default_predictor",
955
+ "update_frequency": "daily",
956
+ "confidence_threshold": 0.7,
957
+ "prediction_horizon": "7_days",
958
+ "prediction_type": "regression"
959
+ }
960
+
961
+ ai_config = {**default_config, **(ai_config or {})}
962
+
963
+ super().__init__(field_type, *args, ai_config=ai_config, **kwargs)
964
+
965
+ class EmbeddingField(VectorField):
966
+ """
967
+ Specialized vector field optimized for embedding storage and retrieval
968
+
969
+ Examples:
970
+ # Store product embeddings for recommendation
971
+ product_embedding = EmbeddingField(
972
+ dimensions=768,
973
+ ai_config={
974
+ "model": "sentence-transformers/all-MiniLM-L6-v2",
975
+ "source_field": "description",
976
+ "enable_similarity_search": True
977
+ }
978
+ )
979
+ """
980
+
981
+ def __init__(self, dimensions: int = 768, *args, ai_config: Optional[Dict[str, Any]] = None, **kwargs):
982
+ """Initialize embedding field with optimized defaults"""
983
+
984
+ default_config = {
985
+ "model": "internal-embeddings",
986
+ "provider": "internal",
987
+ "normalize": True,
988
+ "enable_similarity_search": True,
989
+ "similarity_threshold": 0.8,
990
+ "index_type": "flat"
991
+ }
992
+
993
+ ai_config = {**default_config, **(ai_config or {})}
994
+
995
+ super().__init__(dimensions=dimensions, ai_config=ai_config, *args, **kwargs)
996
+
997
+ async def find_similar(self, query_vector: List[float], candidates: List[Dict[str, Any]], top_k: int = 10) -> List[Dict[str, Any]]:
998
+ """Find similar embeddings using vector search"""
999
+
1000
+ if not candidates:
1001
+ return []
1002
+
1003
+ # Calculate similarities
1004
+ similarities = []
1005
+ for candidate in candidates:
1006
+ if "embedding" in candidate and candidate["embedding"]:
1007
+ similarity = self.similarity(query_vector, candidate["embedding"])
1008
+ if similarity >= self.ai_config["similarity_threshold"]:
1009
+ similarities.append({
1010
+ **candidate,
1011
+ "similarity": similarity
1012
+ })
1013
+
1014
+ # Sort by similarity and return top_k
1015
+ similarities.sort(key=lambda x: x["similarity"], reverse=True)
1016
+ # ========================================
1017
+ # EXPORT AND MODULE INTERFACE
1018
+ # ========================================
1019
+
1020
+ # Main field types for export
1021
+ __all__ = [
1022
+ # Core AI field types
1023
+ "AIComputedField",
1024
+ "LLMField",
1025
+ "VectorField",
1026
+ "SmartTextField",
1027
+ "PredictionField",
1028
+ "EmbeddingField",
1029
+
1030
+ # Base classes and mixins
1031
+ "AIFieldMixin",
1032
+ "CreatesonlineField",
1033
+ "AIModelMixin",
1034
+
1035
+ # Utilities
1036
+ "AIFieldManager",
1037
+ "get_ai_field_manager",
1038
+ "validate_ai_config",
1039
+ "check_ai_field_compatibility",
1040
+
1041
+ # Internal engine (for testing)
1042
+ "InternalAIEngine",
1043
+ ]
1044
+
1045
+ # ========================================
1046
+ # CONVENIENCE FUNCTIONS
1047
+ # ========================================
1048
+
1049
+ def create_smart_model(model_name: str, fields: Dict[str, Any]) -> type:
1050
+ """Create a model class with AI fields dynamically"""
1051
+
1052
+ class_attrs = {
1053
+ "__tablename__": model_name.lower(),
1054
+ "__module__": __name__,
1055
+ }
1056
+
1057
+ # Add standard fields
1058
+ if SA_AVAILABLE:
1059
+ class_attrs["id"] = sa.Column(sa.Integer, primary_key=True)
1060
+ class_attrs["created_at"] = sa.Column(sa.DateTime, default=datetime.utcnow)
1061
+ class_attrs["updated_at"] = sa.Column(sa.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
1062
+
1063
+ # Add AI fields
1064
+ for field_name, field_config in fields.items():
1065
+ field_type = field_config.get("type", "AIComputedField")
1066
+ ai_config = field_config.get("ai_config", {})
1067
+
1068
+ if field_type == "AIComputedField":
1069
+ data_type = field_config.get("data_type", "Float")
1070
+ class_attrs[field_name] = AIComputedField(data_type, ai_config=ai_config)
1071
+ elif field_type == "LLMField":
1072
+ class_attrs[field_name] = LLMField(ai_config=ai_config)
1073
+ elif field_type == "VectorField":
1074
+ dimensions = field_config.get("dimensions", 768)
1075
+ class_attrs[field_name] = VectorField(dimensions=dimensions, ai_config=ai_config)
1076
+ elif field_type == "SmartTextField":
1077
+ class_attrs[field_name] = SmartTextField(ai_config=ai_config)
1078
+
1079
+ # Create the class
1080
+ if SA_AVAILABLE:
1081
+ from sqlalchemy.ext.declarative import declarative_base
1082
+ Base = declarative_base()
1083
+ return type(model_name, (Base, AIModelMixin), class_attrs)
1084
+ else:
1085
+ return type(model_name, (AIModelMixin,), class_attrs)
1086
+
1087
+ def get_field_info() -> Dict[str, Any]:
1088
+ """Get information about available AI field types"""
1089
+ return {
1090
+ "framework": "CREATESONLINE",
1091
+ "version": "0.1.0",
1092
+ "ai_fields": {
1093
+ "AIComputedField": {
1094
+ "description": "Automatically computes values using ML models",
1095
+ "use_cases": ["predictions", "scoring", "classification"],
1096
+ "data_types": ["Float", "Integer", "String", "Text"],
1097
+ "ai_config_options": [
1098
+ "model", "prediction_type", "features", "source_field",
1099
+ "confidence_threshold", "fallback_value"
1100
+ ]
1101
+ },
1102
+ "LLMField": {
1103
+ "description": "Generates content using Large Language Models",
1104
+ "use_cases": ["content generation", "summarization", "translation"],
1105
+ "data_types": ["Text"],
1106
+ "ai_config_options": [
1107
+ "model", "prompt_template", "max_tokens", "temperature",
1108
+ "provider", "fallback_content"
1109
+ ]
1110
+ },
1111
+ "VectorField": {
1112
+ "description": "Stores vector embeddings for similarity search",
1113
+ "use_cases": ["semantic search", "recommendations", "clustering"],
1114
+ "data_types": ["JSON"],
1115
+ "ai_config_options": [
1116
+ "model", "dimensions", "normalize", "similarity_metric",
1117
+ "source_field", "provider"
1118
+ ]
1119
+ },
1120
+ "SmartTextField": {
1121
+ "description": "Enhanced text field with AI analysis",
1122
+ "use_cases": ["sentiment analysis", "keyword extraction", "language detection"],
1123
+ "data_types": ["Text"],
1124
+ "ai_config_options": [
1125
+ "analyze_sentiment", "extract_keywords", "detect_language",
1126
+ "content_moderation", "summarize"
1127
+ ]
1128
+ },
1129
+ "PredictionField": {
1130
+ "description": "Real-time predictions based on current data",
1131
+ "use_cases": ["forecasting", "trend analysis", "risk assessment"],
1132
+ "data_types": ["Float", "Integer", "Date"],
1133
+ "ai_config_options": [
1134
+ "model", "prediction_horizon", "update_frequency",
1135
+ "features", "confidence_threshold"
1136
+ ]
1137
+ },
1138
+ "EmbeddingField": {
1139
+ "description": "Optimized vector field for embeddings",
1140
+ "use_cases": ["document similarity", "product recommendations", "search"],
1141
+ "data_types": ["JSON"],
1142
+ "ai_config_options": [
1143
+ "model", "dimensions", "similarity_threshold",
1144
+ "enable_similarity_search", "index_type"
1145
+ ]
1146
+ }
1147
+ },
1148
+ "providers": {
1149
+ "internal": {
1150
+ "description": "Built-in CREATESONLINE AI engine",
1151
+ "features": ["Mock predictions", "Hash-based embeddings", "Rule-based text analysis"],
1152
+ "dependencies": "None - Pure Python"
1153
+ },
1154
+ "openai": {
1155
+ "description": "OpenAI API integration",
1156
+ "features": ["GPT models", "Text embeddings", "Moderation"],
1157
+ "dependencies": "openai package + API key"
1158
+ },
1159
+ "anthropic": {
1160
+ "description": "Anthropic Claude integration",
1161
+ "features": ["Claude models", "Text generation"],
1162
+ "dependencies": "anthropic package + API key"
1163
+ }
1164
+ },
1165
+ "configuration": {
1166
+ "global_settings": [
1167
+ "default_provider", "cache_ttl", "enable_async",
1168
+ "timeout", "batch_size"
1169
+ ],
1170
+ "caching": {
1171
+ "enabled": True,
1172
+ "ttl": 3600,
1173
+ "size_limit": "100MB"
1174
+ }
1175
+ }
1176
+ }
1177
+
1178
+ # ========================================
1179
+ # DEMONSTRATION AND EXAMPLES
1180
+ # ========================================
1181
+
1182
+ def create_example_model():
1183
+ """Create an example model with AI fields for demonstration"""
1184
+
1185
+ # Example AI field configurations
1186
+ ai_fields = {
1187
+ "lead_score": {
1188
+ "type": "AIComputedField",
1189
+ "data_type": "Float",
1190
+ "ai_config": {
1191
+ "model": "lead_classifier",
1192
+ "prediction_type": "regression",
1193
+ "features": ["company_size", "industry", "engagement_score"],
1194
+ "confidence_threshold": 0.7,
1195
+ "fallback_value": 0.5
1196
+ }
1197
+ },
1198
+ "summary": {
1199
+ "type": "LLMField",
1200
+ "ai_config": {
1201
+ "model": "gpt-4",
1202
+ "prompt_template": "Summarize this lead: {company_name} - {description}",
1203
+ "max_tokens": 150,
1204
+ "temperature": 0.3
1205
+ }
1206
+ },
1207
+ "content_embedding": {
1208
+ "type": "VectorField",
1209
+ "dimensions": 768,
1210
+ "ai_config": {
1211
+ "model": "text-embedding-ada-002",
1212
+ "source_field": "description",
1213
+ "normalize": True
1214
+ }
1215
+ },
1216
+ "sentiment": {
1217
+ "type": "SmartTextField",
1218
+ "ai_config": {
1219
+ "analyze_sentiment": True,
1220
+ "extract_keywords": True,
1221
+ "detect_language": True
1222
+ }
1223
+ }
1224
+ }
1225
+
1226
+ return create_smart_model("ExampleLead", ai_fields)