django-cfg 1.3.5__py3-none-any.whl → 1.3.9__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 +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +258 -0
- django_cfg/apps/payments/admin/payments_admin.py +171 -461
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +105 -34
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +1 -1
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +95 -39
- django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
- django_cfg/apps/payments/services/providers/models/base.py +122 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/{nowpayments.py → nowpayments/provider.py} +240 -209
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +4 -32
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
- django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +5 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +4 -3
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/urls.py +1 -2
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/app_agent_diagnose.py +470 -0
- django_cfg/management/commands/app_agent_generate.py +342 -0
- django_cfg/management/commands/app_agent_info.py +308 -0
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_app_agent/__init__.py +87 -0
- django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
- django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
- django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
- django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
- django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
- django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
- django_cfg/modules/django_app_agent/core/__init__.py +33 -0
- django_cfg/modules/django_app_agent/core/config.py +300 -0
- django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
- django_cfg/modules/django_app_agent/models/__init__.py +71 -0
- django_cfg/modules/django_app_agent/models/base.py +283 -0
- django_cfg/modules/django_app_agent/models/context.py +496 -0
- django_cfg/modules/django_app_agent/models/enums.py +481 -0
- django_cfg/modules/django_app_agent/models/requests.py +500 -0
- django_cfg/modules/django_app_agent/models/responses.py +585 -0
- django_cfg/modules/django_app_agent/pytest.ini +6 -0
- django_cfg/modules/django_app_agent/services/__init__.py +42 -0
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
- django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
- django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
- django_cfg/modules/django_app_agent/services/base.py +437 -0
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
- django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
- django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
- django_cfg/modules/django_app_agent/services/report_service.py +332 -0
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
- django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
- django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
- django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
- django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
- django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
- django_cfg/modules/django_app_agent/ui/cli.py +419 -0
- django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
- django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
- django_cfg/modules/django_app_agent/utils/logging.py +360 -0
- django_cfg/modules/django_app_agent/utils/validation.py +417 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +3 -0
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/RECORD +224 -118
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,251 @@
|
|
1
|
+
"""
|
2
|
+
Question Generator for Intelligent Questioning Service.
|
3
|
+
|
4
|
+
This module handles the generation of context-aware questions
|
5
|
+
using AI agents and project analysis.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import List, Dict, Any, Optional
|
9
|
+
import uuid
|
10
|
+
import asyncio
|
11
|
+
|
12
|
+
from pydantic import BaseModel, Field
|
13
|
+
|
14
|
+
from ...core.config import AgentConfig
|
15
|
+
from ...models.context import ProjectContext
|
16
|
+
from ...agents.interfaces import (
|
17
|
+
get_agent_client, AgentRequest, QuestionGenerationRequest, QuestionGenerationResponse
|
18
|
+
)
|
19
|
+
from ..base import ServiceDependencies
|
20
|
+
from .models import QuestioningRequest, ContextualQuestion
|
21
|
+
|
22
|
+
|
23
|
+
class QuestionGenerator(BaseModel):
|
24
|
+
"""Generates context-aware questions using AI agents."""
|
25
|
+
|
26
|
+
config: AgentConfig = Field(description="Agent configuration")
|
27
|
+
|
28
|
+
# Question generation strategies
|
29
|
+
agent_types: List[str] = Field(
|
30
|
+
default_factory=lambda: [
|
31
|
+
"architecture_agent",
|
32
|
+
"business_logic_agent",
|
33
|
+
"integration_agent",
|
34
|
+
"security_agent",
|
35
|
+
"performance_agent"
|
36
|
+
],
|
37
|
+
description="Types of AI agents to use for question generation"
|
38
|
+
)
|
39
|
+
|
40
|
+
async def generate_questions(
|
41
|
+
self,
|
42
|
+
request: QuestioningRequest,
|
43
|
+
project_context: ProjectContext,
|
44
|
+
dependencies: ServiceDependencies
|
45
|
+
) -> List[ContextualQuestion]:
|
46
|
+
"""Generate context-aware questions using multiple AI agents."""
|
47
|
+
dependencies.log_operation(
|
48
|
+
"Generating questions via AI agents",
|
49
|
+
max_questions=request.max_questions,
|
50
|
+
focus_areas=request.focus_areas,
|
51
|
+
agent_types=len(self.agent_types)
|
52
|
+
)
|
53
|
+
|
54
|
+
all_questions = []
|
55
|
+
|
56
|
+
try:
|
57
|
+
# Generate questions from each agent type
|
58
|
+
generation_tasks = []
|
59
|
+
for agent_type in self.agent_types:
|
60
|
+
task = self._generate_questions_from_agent(
|
61
|
+
agent_type, request, project_context, dependencies
|
62
|
+
)
|
63
|
+
generation_tasks.append(task)
|
64
|
+
|
65
|
+
# Run all agents concurrently
|
66
|
+
agent_results = await asyncio.gather(*generation_tasks, return_exceptions=True)
|
67
|
+
|
68
|
+
# Collect questions from all agents
|
69
|
+
for i, result in enumerate(agent_results):
|
70
|
+
if isinstance(result, Exception):
|
71
|
+
dependencies.log_error(f"Agent {self.agent_types[i]} failed", result)
|
72
|
+
continue
|
73
|
+
|
74
|
+
all_questions.extend(result)
|
75
|
+
|
76
|
+
# Optimize and filter questions
|
77
|
+
optimized_questions = await self._optimize_question_flow(
|
78
|
+
all_questions, request, dependencies
|
79
|
+
)
|
80
|
+
|
81
|
+
dependencies.log_operation(
|
82
|
+
"Question generation completed",
|
83
|
+
total_generated=len(all_questions),
|
84
|
+
optimized_count=len(optimized_questions)
|
85
|
+
)
|
86
|
+
|
87
|
+
return optimized_questions
|
88
|
+
|
89
|
+
except Exception as e:
|
90
|
+
dependencies.log_error("Question generation failed", e)
|
91
|
+
# Return fallback questions
|
92
|
+
return self._generate_fallback_questions(request, project_context)
|
93
|
+
|
94
|
+
async def _generate_questions_from_agent(
|
95
|
+
self,
|
96
|
+
agent_type: str,
|
97
|
+
request: QuestioningRequest,
|
98
|
+
project_context: ProjectContext,
|
99
|
+
dependencies: ServiceDependencies
|
100
|
+
) -> List[ContextualQuestion]:
|
101
|
+
"""Generate questions from a specific AI agent."""
|
102
|
+
try:
|
103
|
+
# Get agent client
|
104
|
+
agent_client = get_agent_client(agent_type, self.config)
|
105
|
+
|
106
|
+
# Prepare agent request
|
107
|
+
agent_request = QuestionGenerationRequest(
|
108
|
+
user_intent=request.user_intent,
|
109
|
+
project_context=project_context,
|
110
|
+
generation_request=request.generation_request,
|
111
|
+
max_questions=min(request.max_questions // len(self.agent_types) + 2, 8),
|
112
|
+
focus_areas=request.focus_areas,
|
113
|
+
agent_specialty=agent_type
|
114
|
+
)
|
115
|
+
|
116
|
+
# Call agent
|
117
|
+
response = await agent_client.process(agent_request)
|
118
|
+
|
119
|
+
if isinstance(response, QuestionGenerationResponse):
|
120
|
+
# Convert agent response to ContextualQuestion objects
|
121
|
+
questions = []
|
122
|
+
for q in response.questions:
|
123
|
+
question = ContextualQuestion(
|
124
|
+
id=str(uuid.uuid4()),
|
125
|
+
text=q.get("text", ""),
|
126
|
+
question_type=q.get("type", "text"),
|
127
|
+
priority=q.get("priority", 5),
|
128
|
+
impact_level=q.get("impact_level", "medium"),
|
129
|
+
context_evidence=q.get("evidence", []),
|
130
|
+
architectural_implications=q.get("implications", []),
|
131
|
+
options=q.get("options"),
|
132
|
+
default_value=q.get("default"),
|
133
|
+
generated_by=agent_type,
|
134
|
+
generation_reasoning=q.get("reasoning", "")
|
135
|
+
)
|
136
|
+
questions.append(question)
|
137
|
+
|
138
|
+
return questions
|
139
|
+
|
140
|
+
except Exception as e:
|
141
|
+
dependencies.log_error(f"Failed to generate questions from {agent_type}", e)
|
142
|
+
|
143
|
+
return []
|
144
|
+
|
145
|
+
async def _optimize_question_flow(
|
146
|
+
self,
|
147
|
+
questions: List[ContextualQuestion],
|
148
|
+
request: QuestioningRequest,
|
149
|
+
dependencies: ServiceDependencies
|
150
|
+
) -> List[ContextualQuestion]:
|
151
|
+
"""Optimize question flow and remove duplicates."""
|
152
|
+
if not questions:
|
153
|
+
return []
|
154
|
+
|
155
|
+
# Remove duplicates based on similar text
|
156
|
+
unique_questions = []
|
157
|
+
seen_texts = set()
|
158
|
+
|
159
|
+
for question in questions:
|
160
|
+
# Simple deduplication based on text similarity
|
161
|
+
text_key = question.text.lower().strip()
|
162
|
+
if text_key not in seen_texts:
|
163
|
+
seen_texts.add(text_key)
|
164
|
+
unique_questions.append(question)
|
165
|
+
|
166
|
+
# Sort by priority and impact
|
167
|
+
priority_weights = {"critical": 4, "high": 3, "medium": 2, "low": 1}
|
168
|
+
|
169
|
+
def question_score(q: ContextualQuestion) -> float:
|
170
|
+
priority_score = (11 - q.priority) / 10 # Convert 1-10 to 1.0-0.1
|
171
|
+
impact_score = priority_weights.get(q.impact_level, 2) / 4
|
172
|
+
return priority_score * 0.6 + impact_score * 0.4
|
173
|
+
|
174
|
+
sorted_questions = sorted(unique_questions, key=question_score, reverse=True)
|
175
|
+
|
176
|
+
# Limit to max_questions
|
177
|
+
limited_questions = sorted_questions[:request.max_questions]
|
178
|
+
|
179
|
+
dependencies.log_operation(
|
180
|
+
"Question optimization completed",
|
181
|
+
original_count=len(questions),
|
182
|
+
unique_count=len(unique_questions),
|
183
|
+
final_count=len(limited_questions)
|
184
|
+
)
|
185
|
+
|
186
|
+
return limited_questions
|
187
|
+
|
188
|
+
def _generate_fallback_questions(
|
189
|
+
self,
|
190
|
+
request: QuestioningRequest,
|
191
|
+
project_context: ProjectContext
|
192
|
+
) -> List[ContextualQuestion]:
|
193
|
+
"""Generate fallback questions when AI agents fail."""
|
194
|
+
fallback_questions = [
|
195
|
+
{
|
196
|
+
"text": "What is the primary purpose of this application?",
|
197
|
+
"type": "text",
|
198
|
+
"priority": 1,
|
199
|
+
"impact_level": "critical",
|
200
|
+
"reasoning": "Understanding the core purpose is essential for proper architecture"
|
201
|
+
},
|
202
|
+
{
|
203
|
+
"text": "Will this application need user authentication?",
|
204
|
+
"type": "yes_no",
|
205
|
+
"priority": 2,
|
206
|
+
"impact_level": "high",
|
207
|
+
"reasoning": "Authentication affects security architecture and user management"
|
208
|
+
},
|
209
|
+
{
|
210
|
+
"text": "What type of data will this application primarily handle?",
|
211
|
+
"type": "choice",
|
212
|
+
"priority": 3,
|
213
|
+
"impact_level": "high",
|
214
|
+
"options": ["User data", "Business data", "Content/Media", "Analytics", "Other"],
|
215
|
+
"reasoning": "Data type influences model design and security requirements"
|
216
|
+
},
|
217
|
+
{
|
218
|
+
"text": "Do you need an API for external integrations?",
|
219
|
+
"type": "yes_no",
|
220
|
+
"priority": 4,
|
221
|
+
"impact_level": "medium",
|
222
|
+
"reasoning": "API requirements affect architecture and serialization needs"
|
223
|
+
},
|
224
|
+
{
|
225
|
+
"text": "What level of admin interface do you need?",
|
226
|
+
"type": "choice",
|
227
|
+
"priority": 5,
|
228
|
+
"impact_level": "medium",
|
229
|
+
"options": ["Basic Django admin", "Custom admin interface", "No admin needed"],
|
230
|
+
"reasoning": "Admin interface complexity affects development time and features"
|
231
|
+
}
|
232
|
+
]
|
233
|
+
|
234
|
+
questions = []
|
235
|
+
for i, q_data in enumerate(fallback_questions[:request.max_questions]):
|
236
|
+
question = ContextualQuestion(
|
237
|
+
id=str(uuid.uuid4()),
|
238
|
+
text=q_data["text"],
|
239
|
+
question_type=q_data["type"],
|
240
|
+
priority=q_data["priority"],
|
241
|
+
impact_level=q_data["impact_level"],
|
242
|
+
context_evidence=["Fallback question due to AI agent unavailability"],
|
243
|
+
architectural_implications=[],
|
244
|
+
options=q_data.get("options"),
|
245
|
+
default_value=q_data.get("default"),
|
246
|
+
generated_by="fallback_generator",
|
247
|
+
generation_reasoning=q_data["reasoning"]
|
248
|
+
)
|
249
|
+
questions.append(question)
|
250
|
+
|
251
|
+
return questions
|
@@ -0,0 +1,347 @@
|
|
1
|
+
"""
|
2
|
+
Response Processor for Intelligent Questioning Service.
|
3
|
+
|
4
|
+
This module handles processing user responses and building
|
5
|
+
refined generation requests based on the collected answers.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import List, Dict, Any, Optional, Set
|
9
|
+
from datetime import datetime, timezone
|
10
|
+
|
11
|
+
from pydantic import BaseModel, Field
|
12
|
+
|
13
|
+
from ...core.config import AgentConfig
|
14
|
+
from ...models.requests import AppGenerationRequest
|
15
|
+
from ...models.enums import AppType, AppComplexity, AppFeature
|
16
|
+
from ...models.context import ProjectContext
|
17
|
+
from ..base import ServiceDependencies
|
18
|
+
from .models import QuestioningSession, QuestionResponse, ContextualQuestion
|
19
|
+
|
20
|
+
|
21
|
+
class ResponseProcessor(BaseModel):
|
22
|
+
"""Processes user responses and builds refined generation requests."""
|
23
|
+
|
24
|
+
config: AgentConfig = Field(description="Agent configuration")
|
25
|
+
|
26
|
+
# Response interpretation rules
|
27
|
+
feature_keywords: Dict[str, List[str]] = Field(
|
28
|
+
default_factory=lambda: {
|
29
|
+
"authentication": ["auth", "login", "user", "account", "permission"],
|
30
|
+
"api": ["api", "rest", "endpoint", "integration", "external"],
|
31
|
+
"admin": ["admin", "management", "backend", "dashboard"],
|
32
|
+
"forms": ["form", "input", "validation", "submit"],
|
33
|
+
"tests": ["test", "testing", "quality", "coverage"],
|
34
|
+
"security": ["security", "secure", "protection", "safe"],
|
35
|
+
"models": ["data", "database", "model", "entity"],
|
36
|
+
"views": ["view", "page", "display", "interface"],
|
37
|
+
"serializers": ["serialize", "json", "api", "data format"],
|
38
|
+
"tasks": ["background", "async", "queue", "job", "task"]
|
39
|
+
},
|
40
|
+
description="Keywords for inferring features from responses"
|
41
|
+
)
|
42
|
+
|
43
|
+
async def process_responses(
|
44
|
+
self,
|
45
|
+
session: QuestioningSession,
|
46
|
+
dependencies: ServiceDependencies
|
47
|
+
) -> AppGenerationRequest:
|
48
|
+
"""Process all responses and build refined generation request."""
|
49
|
+
dependencies.log_operation(
|
50
|
+
"Processing questioning responses",
|
51
|
+
session_id=session.session_id,
|
52
|
+
responses_count=len(session.responses),
|
53
|
+
questions_count=len(session.questions)
|
54
|
+
)
|
55
|
+
|
56
|
+
try:
|
57
|
+
# Extract insights from responses
|
58
|
+
insights = await self._extract_insights(session, dependencies)
|
59
|
+
|
60
|
+
# Build refined request
|
61
|
+
refined_request = await self._build_refined_request(
|
62
|
+
session, insights, dependencies
|
63
|
+
)
|
64
|
+
|
65
|
+
dependencies.log_operation(
|
66
|
+
"Response processing completed",
|
67
|
+
app_name=refined_request.app_name,
|
68
|
+
app_type=refined_request.app_type.value,
|
69
|
+
features_count=len(refined_request.features),
|
70
|
+
complexity=refined_request.complexity.value
|
71
|
+
)
|
72
|
+
|
73
|
+
return refined_request
|
74
|
+
|
75
|
+
except Exception as e:
|
76
|
+
dependencies.log_error("Response processing failed", e)
|
77
|
+
raise
|
78
|
+
|
79
|
+
async def _extract_insights(
|
80
|
+
self,
|
81
|
+
session: QuestioningSession,
|
82
|
+
dependencies: ServiceDependencies
|
83
|
+
) -> Dict[str, Any]:
|
84
|
+
"""Extract structured insights from user responses."""
|
85
|
+
insights = {
|
86
|
+
"inferred_features": set(),
|
87
|
+
"app_characteristics": {},
|
88
|
+
"user_preferences": {},
|
89
|
+
"technical_requirements": {},
|
90
|
+
"business_requirements": {},
|
91
|
+
"confidence_indicators": []
|
92
|
+
}
|
93
|
+
|
94
|
+
# Process each response
|
95
|
+
for response in session.responses:
|
96
|
+
question = self._find_question_by_id(session.questions, response.question_id)
|
97
|
+
if not question:
|
98
|
+
continue
|
99
|
+
|
100
|
+
# Extract feature implications
|
101
|
+
features = self._infer_features_from_response(question, response)
|
102
|
+
insights["inferred_features"].update(features)
|
103
|
+
|
104
|
+
# Extract characteristics
|
105
|
+
characteristics = self._extract_characteristics(question, response)
|
106
|
+
insights["app_characteristics"].update(characteristics)
|
107
|
+
|
108
|
+
# Track confidence
|
109
|
+
insights["confidence_indicators"].append({
|
110
|
+
"question_id": response.question_id,
|
111
|
+
"confidence": response.confidence,
|
112
|
+
"impact_level": question.impact_level
|
113
|
+
})
|
114
|
+
|
115
|
+
return insights
|
116
|
+
|
117
|
+
async def _build_refined_request(
|
118
|
+
self,
|
119
|
+
session: QuestioningSession,
|
120
|
+
insights: Dict[str, Any],
|
121
|
+
dependencies: ServiceDependencies
|
122
|
+
) -> AppGenerationRequest:
|
123
|
+
"""Build refined generation request from insights."""
|
124
|
+
# Start with original request if available
|
125
|
+
base_request = session.project_context.generation_request
|
126
|
+
|
127
|
+
# Determine app name
|
128
|
+
app_name = self._determine_app_name(session, insights, base_request)
|
129
|
+
|
130
|
+
# Determine app type
|
131
|
+
app_type = self._determine_app_type(session, insights, base_request)
|
132
|
+
|
133
|
+
# Determine complexity
|
134
|
+
complexity = self._determine_complexity(session, insights, base_request)
|
135
|
+
|
136
|
+
# Determine features
|
137
|
+
features = self._determine_features(session, insights, base_request)
|
138
|
+
|
139
|
+
# Build description
|
140
|
+
description = self._build_description(session, insights, base_request)
|
141
|
+
|
142
|
+
# Determine output directory
|
143
|
+
output_dir = base_request.output_dir if base_request else str(session.project_context.project_root)
|
144
|
+
|
145
|
+
refined_request = AppGenerationRequest(
|
146
|
+
app_name=app_name,
|
147
|
+
description=description,
|
148
|
+
app_type=app_type,
|
149
|
+
complexity=complexity,
|
150
|
+
features=list(features),
|
151
|
+
output_dir=output_dir,
|
152
|
+
max_questions=0, # No more questions needed
|
153
|
+
quality_threshold=base_request.quality_threshold if base_request else 8.0
|
154
|
+
)
|
155
|
+
|
156
|
+
return refined_request
|
157
|
+
|
158
|
+
def _find_question_by_id(
|
159
|
+
self,
|
160
|
+
questions: List[ContextualQuestion],
|
161
|
+
question_id: str
|
162
|
+
) -> Optional[ContextualQuestion]:
|
163
|
+
"""Find question by ID."""
|
164
|
+
for question in questions:
|
165
|
+
if question.id == question_id:
|
166
|
+
return question
|
167
|
+
return None
|
168
|
+
|
169
|
+
def _infer_features_from_response(
|
170
|
+
self,
|
171
|
+
question: ContextualQuestion,
|
172
|
+
response: QuestionResponse
|
173
|
+
) -> Set[AppFeature]:
|
174
|
+
"""Infer required features from a response."""
|
175
|
+
features = set()
|
176
|
+
answer_lower = response.answer.lower()
|
177
|
+
|
178
|
+
# Check for feature keywords in the answer
|
179
|
+
for feature_name, keywords in self.feature_keywords.items():
|
180
|
+
if any(keyword in answer_lower for keyword in keywords):
|
181
|
+
try:
|
182
|
+
feature = AppFeature(feature_name.upper())
|
183
|
+
features.add(feature)
|
184
|
+
except ValueError:
|
185
|
+
# Feature name doesn't match enum
|
186
|
+
pass
|
187
|
+
|
188
|
+
# Question-specific feature inference
|
189
|
+
if question.question_type == "yes_no":
|
190
|
+
if response.answer.lower() in ["yes", "y", "true", "1"]:
|
191
|
+
# Infer features based on question content
|
192
|
+
question_lower = question.text.lower()
|
193
|
+
|
194
|
+
if "auth" in question_lower or "login" in question_lower:
|
195
|
+
features.add(AppFeature.AUTHENTICATION)
|
196
|
+
elif "api" in question_lower:
|
197
|
+
features.add(AppFeature.API)
|
198
|
+
features.add(AppFeature.SERIALIZERS)
|
199
|
+
elif "admin" in question_lower:
|
200
|
+
features.add(AppFeature.ADMIN)
|
201
|
+
elif "form" in question_lower:
|
202
|
+
features.add(AppFeature.FORMS)
|
203
|
+
elif "test" in question_lower:
|
204
|
+
features.add(AppFeature.TESTS)
|
205
|
+
|
206
|
+
return features
|
207
|
+
|
208
|
+
def _extract_characteristics(
|
209
|
+
self,
|
210
|
+
question: ContextualQuestion,
|
211
|
+
response: QuestionResponse
|
212
|
+
) -> Dict[str, Any]:
|
213
|
+
"""Extract app characteristics from response."""
|
214
|
+
characteristics = {}
|
215
|
+
|
216
|
+
# Extract based on question type and content
|
217
|
+
question_lower = question.text.lower()
|
218
|
+
answer_lower = response.answer.lower()
|
219
|
+
|
220
|
+
if "purpose" in question_lower or "what" in question_lower:
|
221
|
+
characteristics["primary_purpose"] = response.answer
|
222
|
+
|
223
|
+
if "data" in question_lower:
|
224
|
+
characteristics["data_type"] = response.answer
|
225
|
+
|
226
|
+
if "user" in question_lower and "how many" in question_lower:
|
227
|
+
characteristics["expected_users"] = response.answer
|
228
|
+
|
229
|
+
if "performance" in question_lower or "scale" in question_lower:
|
230
|
+
characteristics["performance_requirements"] = response.answer
|
231
|
+
|
232
|
+
return characteristics
|
233
|
+
|
234
|
+
def _determine_app_name(
|
235
|
+
self,
|
236
|
+
session: QuestioningSession,
|
237
|
+
insights: Dict[str, Any],
|
238
|
+
base_request: Optional[AppGenerationRequest]
|
239
|
+
) -> str:
|
240
|
+
"""Determine application name."""
|
241
|
+
if base_request and base_request.app_name:
|
242
|
+
return base_request.app_name
|
243
|
+
|
244
|
+
# Try to extract from user intent or responses
|
245
|
+
intent_words = session.user_intent.lower().split()
|
246
|
+
|
247
|
+
# Look for app-like words
|
248
|
+
app_words = [word for word in intent_words if len(word) > 3 and word.isalpha()]
|
249
|
+
|
250
|
+
if app_words:
|
251
|
+
return "_".join(app_words[:2]) # Take first 2 meaningful words
|
252
|
+
|
253
|
+
return "generated_app"
|
254
|
+
|
255
|
+
def _determine_app_type(
|
256
|
+
self,
|
257
|
+
session: QuestioningSession,
|
258
|
+
insights: Dict[str, Any],
|
259
|
+
base_request: Optional[AppGenerationRequest]
|
260
|
+
) -> AppType:
|
261
|
+
"""Determine application type."""
|
262
|
+
if base_request and base_request.app_type:
|
263
|
+
return base_request.app_type
|
264
|
+
|
265
|
+
# Check if django-cfg features are mentioned
|
266
|
+
django_cfg_indicators = ["config", "module", "django-cfg", "cfg"]
|
267
|
+
|
268
|
+
for response in session.responses:
|
269
|
+
if any(indicator in response.answer.lower() for indicator in django_cfg_indicators):
|
270
|
+
return AppType.DJANGO_CFG
|
271
|
+
|
272
|
+
return AppType.DJANGO
|
273
|
+
|
274
|
+
def _determine_complexity(
|
275
|
+
self,
|
276
|
+
session: QuestioningSession,
|
277
|
+
insights: Dict[str, Any],
|
278
|
+
base_request: Optional[AppGenerationRequest]
|
279
|
+
) -> AppComplexity:
|
280
|
+
"""Determine application complexity."""
|
281
|
+
if base_request and base_request.complexity:
|
282
|
+
return base_request.complexity
|
283
|
+
|
284
|
+
feature_count = len(insights["inferred_features"])
|
285
|
+
|
286
|
+
# Determine complexity based on features and responses
|
287
|
+
complexity_indicators = {
|
288
|
+
"enterprise": ["enterprise", "large scale", "complex", "advanced"],
|
289
|
+
"intermediate": ["medium", "moderate", "standard", "typical"],
|
290
|
+
"simple": ["simple", "basic", "minimal", "small"]
|
291
|
+
}
|
292
|
+
|
293
|
+
# Check responses for complexity indicators
|
294
|
+
for response in session.responses:
|
295
|
+
answer_lower = response.answer.lower()
|
296
|
+
for complexity, indicators in complexity_indicators.items():
|
297
|
+
if any(indicator in answer_lower for indicator in indicators):
|
298
|
+
try:
|
299
|
+
return AppComplexity(complexity.upper())
|
300
|
+
except ValueError:
|
301
|
+
pass
|
302
|
+
|
303
|
+
# Fallback based on feature count
|
304
|
+
if feature_count >= 8:
|
305
|
+
return AppComplexity.ENTERPRISE
|
306
|
+
elif feature_count >= 5:
|
307
|
+
return AppComplexity.INTERMEDIATE
|
308
|
+
else:
|
309
|
+
return AppComplexity.SIMPLE
|
310
|
+
|
311
|
+
def _determine_features(
|
312
|
+
self,
|
313
|
+
session: QuestioningSession,
|
314
|
+
insights: Dict[str, Any],
|
315
|
+
base_request: Optional[AppGenerationRequest]
|
316
|
+
) -> Set[AppFeature]:
|
317
|
+
"""Determine required features."""
|
318
|
+
features = set(insights["inferred_features"])
|
319
|
+
|
320
|
+
# Add base features if available
|
321
|
+
if base_request and base_request.features:
|
322
|
+
features.update(base_request.features)
|
323
|
+
|
324
|
+
# Ensure core features are included
|
325
|
+
core_features = {AppFeature.MODELS, AppFeature.VIEWS, AppFeature.URLS}
|
326
|
+
features.update(core_features)
|
327
|
+
|
328
|
+
return features
|
329
|
+
|
330
|
+
def _build_description(
|
331
|
+
self,
|
332
|
+
session: QuestioningSession,
|
333
|
+
insights: Dict[str, Any],
|
334
|
+
base_request: Optional[AppGenerationRequest]
|
335
|
+
) -> str:
|
336
|
+
"""Build application description."""
|
337
|
+
if base_request and base_request.description:
|
338
|
+
return base_request.description
|
339
|
+
|
340
|
+
# Build description from user intent and characteristics
|
341
|
+
description_parts = [session.user_intent]
|
342
|
+
|
343
|
+
if "primary_purpose" in insights["app_characteristics"]:
|
344
|
+
purpose = insights["app_characteristics"]["primary_purpose"]
|
345
|
+
description_parts.append(f"Primary purpose: {purpose}")
|
346
|
+
|
347
|
+
return ". ".join(description_parts)
|