django-cfg 1.1.82__py3-none-any.whl → 1.2.0__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.
- django_cfg/__init__.py +20 -448
- django_cfg/apps/accounts/README.md +3 -3
- django_cfg/apps/accounts/admin/__init__.py +0 -2
- django_cfg/apps/accounts/admin/activity.py +2 -9
- django_cfg/apps/accounts/admin/filters.py +0 -42
- django_cfg/apps/accounts/admin/inlines.py +8 -8
- django_cfg/apps/accounts/admin/otp.py +5 -5
- django_cfg/apps/accounts/admin/registration_source.py +1 -8
- django_cfg/apps/accounts/admin/user.py +12 -20
- django_cfg/apps/accounts/managers/user_manager.py +2 -129
- django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
- django_cfg/apps/accounts/models.py +3 -123
- django_cfg/apps/accounts/serializers/otp.py +40 -44
- django_cfg/apps/accounts/serializers/profile.py +0 -2
- django_cfg/apps/accounts/services/otp_service.py +98 -186
- django_cfg/apps/accounts/signals.py +25 -15
- django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
- django_cfg/apps/accounts/views/otp.py +35 -36
- django_cfg/apps/agents/README.md +129 -0
- django_cfg/apps/agents/__init__.py +68 -0
- django_cfg/apps/agents/admin/__init__.py +17 -0
- django_cfg/apps/agents/admin/execution_admin.py +460 -0
- django_cfg/apps/agents/admin/registry_admin.py +360 -0
- django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
- django_cfg/apps/agents/apps.py +29 -0
- django_cfg/apps/agents/core/__init__.py +20 -0
- django_cfg/apps/agents/core/agent.py +281 -0
- django_cfg/apps/agents/core/dependencies.py +154 -0
- django_cfg/apps/agents/core/exceptions.py +66 -0
- django_cfg/apps/agents/core/models.py +106 -0
- django_cfg/apps/agents/core/orchestrator.py +391 -0
- django_cfg/apps/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- django_cfg/apps/agents/integration/__init__.py +14 -0
- django_cfg/apps/agents/integration/middleware.py +80 -0
- django_cfg/apps/agents/integration/registry.py +345 -0
- django_cfg/apps/agents/integration/signals.py +50 -0
- django_cfg/apps/agents/management/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/create_agent.py +365 -0
- django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
- django_cfg/apps/agents/managers/__init__.py +23 -0
- django_cfg/apps/agents/managers/execution.py +236 -0
- django_cfg/apps/agents/managers/registry.py +254 -0
- django_cfg/apps/agents/managers/toolsets.py +496 -0
- django_cfg/apps/agents/migrations/0001_initial.py +286 -0
- django_cfg/apps/agents/migrations/__init__.py +5 -0
- django_cfg/apps/agents/models/__init__.py +15 -0
- django_cfg/apps/agents/models/execution.py +215 -0
- django_cfg/apps/agents/models/registry.py +220 -0
- django_cfg/apps/agents/models/toolsets.py +305 -0
- django_cfg/apps/agents/patterns/__init__.py +24 -0
- django_cfg/apps/agents/patterns/content_agents.py +234 -0
- django_cfg/apps/agents/toolsets/__init__.py +15 -0
- django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
- django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
- django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
- django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
- django_cfg/apps/agents/urls.py +46 -0
- django_cfg/apps/knowbase/README.md +150 -0
- django_cfg/apps/knowbase/__init__.py +27 -0
- django_cfg/apps/knowbase/admin/__init__.py +23 -0
- django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
- django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
- django_cfg/apps/knowbase/admin/document_admin.py +650 -0
- django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
- django_cfg/apps/knowbase/apps.py +81 -0
- django_cfg/apps/knowbase/config/README.md +176 -0
- django_cfg/apps/knowbase/config/__init__.py +51 -0
- django_cfg/apps/knowbase/config/constance_fields.py +186 -0
- django_cfg/apps/knowbase/config/constance_settings.py +200 -0
- django_cfg/apps/knowbase/config/settings.py +444 -0
- django_cfg/apps/knowbase/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- django_cfg/apps/knowbase/management/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
- django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
- django_cfg/apps/knowbase/managers/__init__.py +22 -0
- django_cfg/apps/knowbase/managers/archive.py +426 -0
- django_cfg/apps/knowbase/managers/base.py +32 -0
- django_cfg/apps/knowbase/managers/chat.py +141 -0
- django_cfg/apps/knowbase/managers/document.py +203 -0
- django_cfg/apps/knowbase/managers/external_data.py +471 -0
- django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
- django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
- django_cfg/apps/knowbase/migrations/__init__.py +5 -0
- django_cfg/apps/knowbase/mixins/__init__.py +15 -0
- django_cfg/apps/knowbase/mixins/config.py +108 -0
- django_cfg/apps/knowbase/mixins/creator.py +81 -0
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
- django_cfg/apps/knowbase/mixins/service.py +362 -0
- django_cfg/apps/knowbase/models/__init__.py +41 -0
- django_cfg/apps/knowbase/models/archive.py +599 -0
- django_cfg/apps/knowbase/models/base.py +58 -0
- django_cfg/apps/knowbase/models/chat.py +157 -0
- django_cfg/apps/knowbase/models/document.py +267 -0
- django_cfg/apps/knowbase/models/external_data.py +376 -0
- django_cfg/apps/knowbase/serializers/__init__.py +68 -0
- django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
- django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
- django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
- django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
- django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
- django_cfg/apps/knowbase/services/__init__.py +40 -0
- django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
- django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
- django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
- django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
- django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
- django_cfg/apps/knowbase/services/base.py +53 -0
- django_cfg/apps/knowbase/services/chat_service.py +239 -0
- django_cfg/apps/knowbase/services/document_service.py +144 -0
- django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
- django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
- django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
- django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
- django_cfg/apps/knowbase/services/embedding/models.py +229 -0
- django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
- django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
- django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
- django_cfg/apps/knowbase/services/search_service.py +293 -0
- django_cfg/apps/knowbase/signals/__init__.py +21 -0
- django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
- django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
- django_cfg/apps/knowbase/signals/document_signals.py +143 -0
- django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
- django_cfg/apps/knowbase/tasks/__init__.py +39 -0
- django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
- django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
- django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
- django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
- django_cfg/apps/knowbase/urls.py +43 -0
- django_cfg/apps/knowbase/utils/__init__.py +12 -0
- django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
- django_cfg/apps/knowbase/utils/text_processing.py +375 -0
- django_cfg/apps/knowbase/utils/validation.py +99 -0
- django_cfg/apps/knowbase/views/__init__.py +28 -0
- django_cfg/apps/knowbase/views/archive_views.py +469 -0
- django_cfg/apps/knowbase/views/base.py +49 -0
- django_cfg/apps/knowbase/views/chat_views.py +181 -0
- django_cfg/apps/knowbase/views/document_views.py +183 -0
- django_cfg/apps/knowbase/views/public_views.py +129 -0
- django_cfg/apps/leads/admin.py +70 -0
- django_cfg/apps/newsletter/admin.py +234 -0
- django_cfg/apps/newsletter/admin_filters.py +124 -0
- django_cfg/apps/support/admin.py +196 -0
- django_cfg/apps/support/admin_filters.py +71 -0
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
- django_cfg/apps/urls.py +5 -4
- django_cfg/cli/README.md +1 -1
- django_cfg/cli/commands/create_project.py +2 -2
- django_cfg/cli/commands/info.py +1 -1
- django_cfg/config.py +44 -0
- django_cfg/core/config.py +29 -82
- django_cfg/core/environment.py +1 -1
- django_cfg/core/generation.py +19 -107
- django_cfg/{integration.py → core/integration.py} +18 -16
- django_cfg/core/validation.py +1 -1
- django_cfg/management/__init__.py +1 -1
- django_cfg/management/commands/__init__.py +1 -1
- django_cfg/management/commands/auto_generate.py +482 -0
- django_cfg/management/commands/migrator.py +19 -101
- django_cfg/management/commands/test_email.py +1 -1
- django_cfg/middleware/README.md +0 -158
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/api.py +145 -0
- django_cfg/models/base.py +287 -0
- django_cfg/models/cache.py +4 -4
- django_cfg/models/constance.py +25 -88
- django_cfg/models/database.py +9 -9
- django_cfg/models/drf.py +3 -36
- django_cfg/models/email.py +163 -0
- django_cfg/models/environment.py +276 -0
- django_cfg/models/limits.py +1 -1
- django_cfg/models/logging.py +366 -0
- django_cfg/models/revolution.py +41 -2
- django_cfg/models/security.py +125 -0
- django_cfg/models/services.py +1 -1
- django_cfg/modules/__init__.py +2 -56
- django_cfg/modules/base.py +78 -52
- django_cfg/modules/django_currency/service.py +2 -2
- django_cfg/modules/django_email.py +2 -2
- django_cfg/modules/django_health.py +267 -0
- django_cfg/modules/django_llm/llm/client.py +79 -17
- django_cfg/modules/django_llm/translator/translator.py +2 -2
- django_cfg/modules/django_logger.py +2 -2
- django_cfg/modules/django_ngrok.py +2 -2
- django_cfg/modules/django_tasks.py +68 -3
- django_cfg/modules/django_telegram.py +3 -3
- django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
- django_cfg/modules/django_twilio/service.py +2 -2
- django_cfg/modules/django_twilio/simple_service.py +2 -2
- django_cfg/modules/django_twilio/twilio_service.py +2 -2
- django_cfg/modules/django_unfold/__init__.py +69 -0
- django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
- django_cfg/modules/django_unfold/dashboard.py +278 -0
- django_cfg/modules/django_unfold/icons/README.md +145 -0
- django_cfg/modules/django_unfold/icons/__init__.py +12 -0
- django_cfg/modules/django_unfold/icons/constants.py +2851 -0
- django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
- django_cfg/modules/django_unfold/models/__init__.py +42 -0
- django_cfg/modules/django_unfold/models/config.py +601 -0
- django_cfg/modules/django_unfold/models/dashboard.py +206 -0
- django_cfg/modules/django_unfold/models/dropdown.py +40 -0
- django_cfg/modules/django_unfold/models/navigation.py +73 -0
- django_cfg/modules/django_unfold/models/tabs.py +25 -0
- django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
- django_cfg/modules/django_unfold/utils.py +140 -0
- django_cfg/registry/__init__.py +23 -0
- django_cfg/registry/core.py +61 -0
- django_cfg/registry/exceptions.py +11 -0
- django_cfg/registry/modules.py +12 -0
- django_cfg/registry/services.py +26 -0
- django_cfg/registry/third_party.py +52 -0
- django_cfg/routing/__init__.py +19 -0
- django_cfg/routing/callbacks.py +198 -0
- django_cfg/routing/routers.py +48 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
- django_cfg/templatetags/__init__.py +0 -0
- django_cfg/templatetags/django_cfg.py +33 -0
- django_cfg/urls.py +33 -0
- django_cfg/utils/path_resolution.py +1 -1
- django_cfg/utils/smart_defaults.py +7 -61
- django_cfg/utils/toolkit.py +663 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
- django_cfg-1.2.0.dist-info/RECORD +441 -0
- django_cfg/archive/django_sample.zip +0 -0
- django_cfg/models/unfold.py +0 -271
- django_cfg/modules/unfold/__init__.py +0 -29
- django_cfg/modules/unfold/dashboard.py +0 -318
- django_cfg/pyproject.toml +0 -370
- django_cfg/routers.py +0 -83
- django_cfg-1.1.82.dist-info/RECORD +0 -278
- /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
- /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
- /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
- /django_cfg/{version_check.py → utils/version_check.py} +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,376 @@
|
|
1
|
+
"""
|
2
|
+
External Data models for integrating external Django models into django_cfg.apps.knowbase.
|
3
|
+
|
4
|
+
Provides a unified way to vectorize and search any external data source.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.db import models
|
8
|
+
from django.conf import settings
|
9
|
+
from pgvector.django import VectorField
|
10
|
+
from typing import Optional, List, Dict, Any
|
11
|
+
import json
|
12
|
+
from enum import Enum
|
13
|
+
|
14
|
+
from .base import UserScopedModel, ProcessingStatus, TimestampedModel
|
15
|
+
from .document import DocumentCategory
|
16
|
+
|
17
|
+
|
18
|
+
class ExternalDataType(models.TextChoices):
|
19
|
+
"""Types of external data sources."""
|
20
|
+
MODEL = "model", "Django Model"
|
21
|
+
API = "api", "API Endpoint"
|
22
|
+
DATABASE = "database", "Database Query"
|
23
|
+
FILE = "file", "File System"
|
24
|
+
CUSTOM = "custom", "Custom Source"
|
25
|
+
|
26
|
+
|
27
|
+
class ExternalDataStatus(models.TextChoices):
|
28
|
+
"""Processing status for external data."""
|
29
|
+
PENDING = "pending", "Pending"
|
30
|
+
PROCESSING = "processing", "Processing"
|
31
|
+
COMPLETED = "completed", "Completed"
|
32
|
+
FAILED = "failed", "Failed"
|
33
|
+
OUTDATED = "outdated", "Outdated"
|
34
|
+
|
35
|
+
|
36
|
+
class ExternalData(UserScopedModel):
|
37
|
+
"""
|
38
|
+
External data source integrated into knowbase for AI search.
|
39
|
+
|
40
|
+
This model represents any external data source (Django models, APIs, etc.)
|
41
|
+
that has been integrated into the knowledge base for semantic search.
|
42
|
+
"""
|
43
|
+
|
44
|
+
# Manager will be set after class definition
|
45
|
+
from ..managers.external_data import ExternalDataManager
|
46
|
+
objects = ExternalDataManager()
|
47
|
+
|
48
|
+
# Basic information
|
49
|
+
title = models.CharField(
|
50
|
+
max_length=512,
|
51
|
+
help_text="Human-readable title for this external data source"
|
52
|
+
)
|
53
|
+
description = models.TextField(
|
54
|
+
blank=True,
|
55
|
+
help_text="Description of what this external data contains"
|
56
|
+
)
|
57
|
+
|
58
|
+
# Source configuration
|
59
|
+
source_type = models.CharField(
|
60
|
+
max_length=20,
|
61
|
+
choices=ExternalDataType.choices,
|
62
|
+
default=ExternalDataType.MODEL,
|
63
|
+
help_text="Type of external data source"
|
64
|
+
)
|
65
|
+
source_identifier = models.CharField(
|
66
|
+
max_length=255,
|
67
|
+
blank=True,
|
68
|
+
help_text="Unique identifier for the data source (e.g., 'vehicles_data.Vehicle')"
|
69
|
+
)
|
70
|
+
source_config = models.JSONField(
|
71
|
+
default=dict,
|
72
|
+
blank=True,
|
73
|
+
help_text="Configuration for data extraction (fields, filters, etc.)"
|
74
|
+
)
|
75
|
+
|
76
|
+
# Content and metadata
|
77
|
+
content = models.TextField(
|
78
|
+
blank=True,
|
79
|
+
help_text="Extracted text content for vectorization"
|
80
|
+
)
|
81
|
+
content_hash = models.CharField(
|
82
|
+
max_length=64,
|
83
|
+
blank=True,
|
84
|
+
db_index=True,
|
85
|
+
help_text="SHA256 hash of content for change detection"
|
86
|
+
)
|
87
|
+
metadata = models.JSONField(
|
88
|
+
default=dict,
|
89
|
+
blank=True,
|
90
|
+
help_text="Additional metadata from the source"
|
91
|
+
)
|
92
|
+
|
93
|
+
# Processing status
|
94
|
+
status = models.CharField(
|
95
|
+
max_length=20,
|
96
|
+
choices=ExternalDataStatus.choices,
|
97
|
+
default=ExternalDataStatus.PENDING,
|
98
|
+
help_text="Current processing status"
|
99
|
+
)
|
100
|
+
processing_error = models.TextField(
|
101
|
+
blank=True,
|
102
|
+
help_text="Error message if processing failed"
|
103
|
+
)
|
104
|
+
|
105
|
+
# Vectorization settings
|
106
|
+
chunk_size = models.PositiveIntegerField(
|
107
|
+
default=1000,
|
108
|
+
help_text="Size of text chunks for vectorization"
|
109
|
+
)
|
110
|
+
overlap_size = models.PositiveIntegerField(
|
111
|
+
default=200,
|
112
|
+
help_text="Overlap between chunks"
|
113
|
+
)
|
114
|
+
embedding_model = models.CharField(
|
115
|
+
max_length=100,
|
116
|
+
default="text-embedding-ada-002",
|
117
|
+
help_text="Embedding model used for vectorization"
|
118
|
+
)
|
119
|
+
|
120
|
+
# Search settings
|
121
|
+
similarity_threshold = models.FloatField(
|
122
|
+
default=0.5,
|
123
|
+
help_text="Similarity threshold for this external data (0.0-1.0). Lower = more results, higher = more precise"
|
124
|
+
)
|
125
|
+
|
126
|
+
# Processing timestamps
|
127
|
+
processed_at = models.DateTimeField(
|
128
|
+
null=True, blank=True,
|
129
|
+
help_text="When the data was last processed"
|
130
|
+
)
|
131
|
+
source_updated_at = models.DateTimeField(
|
132
|
+
null=True, blank=True,
|
133
|
+
help_text="When the source data was last updated"
|
134
|
+
)
|
135
|
+
|
136
|
+
# Statistics
|
137
|
+
total_chunks = models.PositiveIntegerField(
|
138
|
+
default=0,
|
139
|
+
help_text="Total number of chunks created"
|
140
|
+
)
|
141
|
+
total_tokens = models.PositiveIntegerField(
|
142
|
+
default=0,
|
143
|
+
help_text="Total tokens processed"
|
144
|
+
)
|
145
|
+
processing_cost = models.FloatField(
|
146
|
+
default=0.0,
|
147
|
+
help_text="Total cost for processing this data (USD)"
|
148
|
+
)
|
149
|
+
|
150
|
+
# Organization
|
151
|
+
category = models.ForeignKey(
|
152
|
+
DocumentCategory,
|
153
|
+
on_delete=models.SET_NULL,
|
154
|
+
null=True, blank=True,
|
155
|
+
help_text="Category for organization"
|
156
|
+
)
|
157
|
+
tags = models.JSONField(
|
158
|
+
default=list,
|
159
|
+
blank=True,
|
160
|
+
help_text="Tags for categorization and filtering"
|
161
|
+
)
|
162
|
+
|
163
|
+
# Access control
|
164
|
+
is_active = models.BooleanField(
|
165
|
+
default=True,
|
166
|
+
help_text="Whether this data source is active for search"
|
167
|
+
)
|
168
|
+
is_public = models.BooleanField(
|
169
|
+
default=False,
|
170
|
+
help_text="Whether this data is publicly searchable"
|
171
|
+
)
|
172
|
+
|
173
|
+
class Meta:
|
174
|
+
db_table = 'django_cfg_knowbase_external_data'
|
175
|
+
verbose_name = 'External Data'
|
176
|
+
verbose_name_plural = 'External Data'
|
177
|
+
unique_together = [['user', 'source_identifier']]
|
178
|
+
indexes = [
|
179
|
+
models.Index(fields=['user', 'source_type']),
|
180
|
+
models.Index(fields=['status']),
|
181
|
+
models.Index(fields=['is_active']),
|
182
|
+
models.Index(fields=['processed_at']),
|
183
|
+
models.Index(fields=['source_identifier']),
|
184
|
+
models.Index(fields=['content_hash']),
|
185
|
+
]
|
186
|
+
ordering = ['-processed_at', '-created_at']
|
187
|
+
|
188
|
+
def save(self, *args, **kwargs):
|
189
|
+
"""Override save to generate content_hash if not provided."""
|
190
|
+
# Store original hash for comparison in signals
|
191
|
+
if self.pk:
|
192
|
+
try:
|
193
|
+
original = ExternalData.objects.get(pk=self.pk)
|
194
|
+
self._original_content_hash = original.content_hash
|
195
|
+
except ExternalData.DoesNotExist:
|
196
|
+
self._original_content_hash = None
|
197
|
+
else:
|
198
|
+
self._original_content_hash = None
|
199
|
+
|
200
|
+
# Generate hash if not provided
|
201
|
+
if not self.content_hash and self.content:
|
202
|
+
import hashlib
|
203
|
+
self.content_hash = hashlib.sha256(self.content.encode()).hexdigest()
|
204
|
+
elif self.content:
|
205
|
+
# Regenerate hash if content exists (to catch manual content changes)
|
206
|
+
import hashlib
|
207
|
+
new_hash = hashlib.sha256(self.content.encode()).hexdigest()
|
208
|
+
if self.content_hash != new_hash:
|
209
|
+
self.content_hash = new_hash
|
210
|
+
|
211
|
+
super().save(*args, **kwargs)
|
212
|
+
|
213
|
+
def __str__(self) -> str:
|
214
|
+
return f"{self.title} ({self.source_type})"
|
215
|
+
|
216
|
+
@property
|
217
|
+
def full_name(self) -> str:
|
218
|
+
"""Full name including source type."""
|
219
|
+
return f"{self.title} ({self.get_source_type_display()})"
|
220
|
+
|
221
|
+
@property
|
222
|
+
def is_processed(self) -> bool:
|
223
|
+
"""Check if data has been successfully processed."""
|
224
|
+
return self.status == ExternalDataStatus.COMPLETED
|
225
|
+
|
226
|
+
@property
|
227
|
+
def is_outdated(self) -> bool:
|
228
|
+
"""Check if data needs reprocessing."""
|
229
|
+
return (
|
230
|
+
self.status == ExternalDataStatus.OUTDATED or
|
231
|
+
(self.source_updated_at and self.processed_at and
|
232
|
+
self.source_updated_at > self.processed_at)
|
233
|
+
)
|
234
|
+
|
235
|
+
@property
|
236
|
+
def chunks_count(self) -> int:
|
237
|
+
"""Get the number of chunks for this external data."""
|
238
|
+
return self.chunks.count()
|
239
|
+
|
240
|
+
def get_config_value(self, key: str, default=None):
|
241
|
+
"""Get a configuration value."""
|
242
|
+
return self.source_config.get(key, default)
|
243
|
+
|
244
|
+
def set_config_value(self, key: str, value):
|
245
|
+
"""Set a configuration value."""
|
246
|
+
self.source_config[key] = value
|
247
|
+
self.save(update_fields=['source_config'])
|
248
|
+
|
249
|
+
def add_tag(self, tag: str):
|
250
|
+
"""Add a tag if it doesn't exist."""
|
251
|
+
if tag not in self.tags:
|
252
|
+
self.tags.append(tag)
|
253
|
+
self.save(update_fields=['tags'])
|
254
|
+
|
255
|
+
def remove_tag(self, tag: str):
|
256
|
+
"""Remove a tag if it exists."""
|
257
|
+
if tag in self.tags:
|
258
|
+
self.tags.remove(tag)
|
259
|
+
self.save(update_fields=['tags'])
|
260
|
+
|
261
|
+
|
262
|
+
class ExternalDataChunk(TimestampedModel):
|
263
|
+
"""
|
264
|
+
Vectorized chunk of external data content.
|
265
|
+
|
266
|
+
Similar to DocumentChunk but for external data sources.
|
267
|
+
"""
|
268
|
+
|
269
|
+
# Manager will be set after class definition
|
270
|
+
objects = models.Manager() # Temporary default manager
|
271
|
+
|
272
|
+
# Relationships
|
273
|
+
user = models.ForeignKey(
|
274
|
+
settings.AUTH_USER_MODEL,
|
275
|
+
on_delete=models.CASCADE,
|
276
|
+
db_index=True,
|
277
|
+
help_text="Owner of this chunk"
|
278
|
+
)
|
279
|
+
external_data = models.ForeignKey(
|
280
|
+
ExternalData,
|
281
|
+
on_delete=models.CASCADE,
|
282
|
+
related_name='chunks',
|
283
|
+
help_text="External data this chunk belongs to"
|
284
|
+
)
|
285
|
+
|
286
|
+
# Content
|
287
|
+
content = models.TextField(
|
288
|
+
blank=True,
|
289
|
+
help_text="Text content of the chunk"
|
290
|
+
)
|
291
|
+
chunk_index = models.PositiveIntegerField(
|
292
|
+
default=0,
|
293
|
+
help_text="Sequential index of this chunk within the external data"
|
294
|
+
)
|
295
|
+
|
296
|
+
# Vector embedding
|
297
|
+
embedding = VectorField(
|
298
|
+
dimensions=1536, # OpenAI ada-002 default
|
299
|
+
null=True, blank=True,
|
300
|
+
help_text="Vector embedding for semantic search"
|
301
|
+
)
|
302
|
+
embedding_model = models.CharField(
|
303
|
+
max_length=100,
|
304
|
+
default="text-embedding-ada-002",
|
305
|
+
help_text="Model used for embedding generation"
|
306
|
+
)
|
307
|
+
|
308
|
+
# Metrics
|
309
|
+
token_count = models.PositiveIntegerField(
|
310
|
+
default=0,
|
311
|
+
help_text="Number of tokens in this chunk"
|
312
|
+
)
|
313
|
+
character_count = models.PositiveIntegerField(
|
314
|
+
default=0,
|
315
|
+
help_text="Number of characters in this chunk"
|
316
|
+
)
|
317
|
+
embedding_cost = models.FloatField(
|
318
|
+
default=0.0,
|
319
|
+
help_text="Cost for generating this embedding (USD)"
|
320
|
+
)
|
321
|
+
|
322
|
+
# Context information
|
323
|
+
chunk_metadata = models.JSONField(
|
324
|
+
default=dict,
|
325
|
+
blank=True,
|
326
|
+
help_text="Additional metadata for this specific chunk"
|
327
|
+
)
|
328
|
+
|
329
|
+
class Meta:
|
330
|
+
db_table = 'django_cfg_knowbase_external_data_chunk'
|
331
|
+
verbose_name = 'External Data Chunk'
|
332
|
+
verbose_name_plural = 'External Data Chunks'
|
333
|
+
unique_together = [['external_data', 'chunk_index']]
|
334
|
+
indexes = [
|
335
|
+
models.Index(fields=['user', 'external_data']),
|
336
|
+
models.Index(fields=['embedding_model']),
|
337
|
+
models.Index(fields=['token_count']),
|
338
|
+
models.Index(fields=['chunk_index']),
|
339
|
+
]
|
340
|
+
ordering = ['external_data', 'chunk_index']
|
341
|
+
|
342
|
+
def __str__(self) -> str:
|
343
|
+
return f"{self.external_data.title} - Chunk {self.chunk_index}"
|
344
|
+
|
345
|
+
@property
|
346
|
+
def content_preview(self) -> str:
|
347
|
+
"""Get a preview of the chunk content."""
|
348
|
+
if not self.content:
|
349
|
+
return "No content"
|
350
|
+
if len(self.content) <= 100:
|
351
|
+
return self.content
|
352
|
+
return self.content[:100] + "..."
|
353
|
+
|
354
|
+
@property
|
355
|
+
def embedding_info(self) -> str:
|
356
|
+
"""Get embedding information."""
|
357
|
+
if not self.embedding:
|
358
|
+
return "No embedding"
|
359
|
+
return f"{len(self.embedding)} dimensions"
|
360
|
+
|
361
|
+
@property
|
362
|
+
def similarity_search_ready(self) -> bool:
|
363
|
+
"""Check if chunk is ready for similarity search."""
|
364
|
+
return self.embedding is not None
|
365
|
+
|
366
|
+
@property
|
367
|
+
def source_info(self) -> Dict[str, Any]:
|
368
|
+
"""Get source information for this chunk."""
|
369
|
+
return {
|
370
|
+
'source_type': self.external_data.source_type,
|
371
|
+
'source_identifier': self.external_data.source_identifier,
|
372
|
+
'title': self.external_data.title,
|
373
|
+
'chunk_index': self.chunk_index,
|
374
|
+
'total_chunks': self.external_data.total_chunks,
|
375
|
+
}
|
376
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"""
|
2
|
+
Knowledge Base Serializers
|
3
|
+
|
4
|
+
Pydantic v2 models for API request/response validation.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .document_serializers import *
|
8
|
+
from .chat_serializers import *
|
9
|
+
from .public_serializers import *
|
10
|
+
from .archive_serializers import *
|
11
|
+
from .external_data_serializers import *
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
# Document serializers
|
15
|
+
'DocumentCreateSerializer',
|
16
|
+
'DocumentSerializer',
|
17
|
+
'DocumentStatsSerializer',
|
18
|
+
'DocumentProcessingStatusSerializer',
|
19
|
+
|
20
|
+
# Public serializers
|
21
|
+
'PublicCategorySerializer',
|
22
|
+
'PublicDocumentListSerializer',
|
23
|
+
'PublicDocumentSerializer',
|
24
|
+
|
25
|
+
# Chat serializers
|
26
|
+
'ChatSessionCreateRequest',
|
27
|
+
'ChatSessionResponse',
|
28
|
+
'ChatQueryRequest',
|
29
|
+
'ChatResponse',
|
30
|
+
'ChatHistoryResponse',
|
31
|
+
|
32
|
+
# Archive serializers
|
33
|
+
'DocumentArchiveCreateSerializer',
|
34
|
+
'DocumentArchiveSerializer',
|
35
|
+
'DocumentArchiveDetailSerializer',
|
36
|
+
'DocumentArchiveListSerializer',
|
37
|
+
'ArchiveItemSerializer',
|
38
|
+
'ArchiveItemDetailSerializer',
|
39
|
+
'ArchiveItemChunkSerializer',
|
40
|
+
'ArchiveItemChunkDetailSerializer',
|
41
|
+
'ArchiveProcessingResultSerializer',
|
42
|
+
'ArchiveSearchRequestSerializer',
|
43
|
+
'ArchiveSearchResultSerializer',
|
44
|
+
'ArchiveStatisticsSerializer',
|
45
|
+
'VectorizationStatisticsSerializer',
|
46
|
+
'ArchiveUploadSerializer',
|
47
|
+
'ChunkRevectorizationRequestSerializer',
|
48
|
+
'VectorizationResultSerializer',
|
49
|
+
|
50
|
+
# External data serializers
|
51
|
+
'ExternalDataCreateRequest',
|
52
|
+
'ExternalDataResponse',
|
53
|
+
'ExternalDataListResponse',
|
54
|
+
'ExternalDataChunkResponse',
|
55
|
+
'ExternalDataSearchRequest',
|
56
|
+
'ExternalDataSearchResult',
|
57
|
+
'ExternalDataSearchResponse',
|
58
|
+
'ExternalDataVectorizeRequest',
|
59
|
+
'ExternalDataVectorizeResponse',
|
60
|
+
'ExternalDataStatsResponse',
|
61
|
+
'ExternalDataHealthResponse',
|
62
|
+
'ExternalDataUpdateRequest',
|
63
|
+
'ExternalDataBulkActionRequest',
|
64
|
+
'ExternalDataBulkActionResponse',
|
65
|
+
'ExternalDataQuickAddRequest',
|
66
|
+
'ExternalDataImportRequest',
|
67
|
+
'ExternalDataImportResponse',
|
68
|
+
]
|