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.
Files changed (252) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +258 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +171 -461
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +105 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
  48. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  49. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
  50. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  51. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  52. django_cfg/apps/payments/middleware/api_access.py +32 -6
  53. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
  54. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
  55. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -0
  56. django_cfg/apps/payments/models/balance.py +12 -0
  57. django_cfg/apps/payments/models/currencies.py +106 -32
  58. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  59. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  60. django_cfg/apps/payments/services/core/payment_service.py +1 -1
  61. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  62. django_cfg/apps/payments/services/providers/base.py +95 -39
  63. django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
  64. django_cfg/apps/payments/services/providers/models/base.py +122 -0
  65. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  66. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  67. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  68. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  69. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  70. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  71. django_cfg/apps/payments/services/providers/{nowpayments.py → nowpayments/provider.py} +240 -209
  72. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  73. django_cfg/apps/payments/services/providers/registry.py +4 -32
  74. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  75. django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
  76. django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
  77. django_cfg/apps/payments/tasks/__init__.py +39 -0
  78. django_cfg/apps/payments/tasks/types.py +73 -0
  79. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  80. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  81. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  82. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  83. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  84. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  85. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  86. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  87. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  88. django_cfg/apps/payments/urls_admin.py +1 -1
  89. django_cfg/apps/payments/views/api/currencies.py +5 -5
  90. django_cfg/apps/payments/views/overview/services.py +2 -2
  91. django_cfg/apps/payments/views/serializers/currencies.py +4 -3
  92. django_cfg/apps/support/admin/__init__.py +10 -1
  93. django_cfg/apps/support/admin/support_admin.py +338 -141
  94. django_cfg/apps/tasks/admin/__init__.py +11 -0
  95. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  96. django_cfg/apps/urls.py +1 -2
  97. django_cfg/config.py +1 -1
  98. django_cfg/core/config.py +10 -5
  99. django_cfg/core/generation.py +1 -1
  100. django_cfg/management/commands/__init__.py +13 -1
  101. django_cfg/management/commands/app_agent_diagnose.py +470 -0
  102. django_cfg/management/commands/app_agent_generate.py +342 -0
  103. django_cfg/management/commands/app_agent_info.py +308 -0
  104. django_cfg/management/commands/migrate_all.py +9 -3
  105. django_cfg/management/commands/migrator.py +11 -6
  106. django_cfg/management/commands/rundramatiq.py +3 -2
  107. django_cfg/middleware/__init__.py +0 -2
  108. django_cfg/models/api_keys.py +115 -0
  109. django_cfg/modules/django_admin/__init__.py +64 -0
  110. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  111. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  112. django_cfg/modules/django_admin/decorators/display.py +106 -0
  113. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  114. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  115. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  116. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  117. django_cfg/modules/django_admin/models/__init__.py +20 -0
  118. django_cfg/modules/django_admin/models/action_models.py +33 -0
  119. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  120. django_cfg/modules/django_admin/models/base.py +26 -0
  121. django_cfg/modules/django_admin/models/display_models.py +31 -0
  122. django_cfg/modules/django_admin/utils/badges.py +159 -0
  123. django_cfg/modules/django_admin/utils/displays.py +247 -0
  124. django_cfg/modules/django_app_agent/__init__.py +87 -0
  125. django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
  126. django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
  127. django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
  128. django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
  129. django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
  130. django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
  131. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
  132. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
  133. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
  134. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
  135. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
  136. django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
  137. django_cfg/modules/django_app_agent/core/__init__.py +33 -0
  138. django_cfg/modules/django_app_agent/core/config.py +300 -0
  139. django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
  140. django_cfg/modules/django_app_agent/models/__init__.py +71 -0
  141. django_cfg/modules/django_app_agent/models/base.py +283 -0
  142. django_cfg/modules/django_app_agent/models/context.py +496 -0
  143. django_cfg/modules/django_app_agent/models/enums.py +481 -0
  144. django_cfg/modules/django_app_agent/models/requests.py +500 -0
  145. django_cfg/modules/django_app_agent/models/responses.py +585 -0
  146. django_cfg/modules/django_app_agent/pytest.ini +6 -0
  147. django_cfg/modules/django_app_agent/services/__init__.py +42 -0
  148. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
  149. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
  150. django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
  151. django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
  152. django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
  153. django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
  154. django_cfg/modules/django_app_agent/services/base.py +437 -0
  155. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
  156. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
  157. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
  158. django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
  159. django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
  160. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
  161. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
  162. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
  163. django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
  164. django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
  165. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
  166. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
  167. django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
  168. django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
  169. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
  170. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
  171. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
  172. django_cfg/modules/django_app_agent/services/report_service.py +332 -0
  173. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
  174. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
  175. django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
  176. django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
  177. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
  178. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
  179. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
  180. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
  181. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
  182. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
  183. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
  184. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
  185. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
  186. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
  187. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
  188. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
  189. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
  190. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
  191. django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
  192. django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
  193. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
  194. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
  195. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
  196. django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
  197. django_cfg/modules/django_app_agent/ui/cli.py +419 -0
  198. django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
  199. django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
  200. django_cfg/modules/django_app_agent/utils/logging.py +360 -0
  201. django_cfg/modules/django_app_agent/utils/validation.py +417 -0
  202. django_cfg/modules/django_currency/__init__.py +2 -2
  203. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  204. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  205. django_cfg/modules/django_currency/core/converter.py +12 -12
  206. django_cfg/modules/django_currency/database/__init__.py +2 -2
  207. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  208. django_cfg/modules/django_llm/llm/client.py +10 -2
  209. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  210. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  211. django_cfg/modules/django_unfold/dashboard.py +14 -13
  212. django_cfg/modules/django_unfold/models/config.py +1 -1
  213. django_cfg/registry/core.py +3 -0
  214. django_cfg/registry/third_party.py +2 -2
  215. django_cfg/template_archive/django_sample.zip +0 -0
  216. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
  217. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/RECORD +224 -118
  218. django_cfg/apps/accounts/admin/activity.py +0 -96
  219. django_cfg/apps/accounts/admin/group.py +0 -17
  220. django_cfg/apps/accounts/admin/otp.py +0 -59
  221. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  222. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  223. django_cfg/apps/accounts/admin/user.py +0 -300
  224. django_cfg/apps/agents/core/agent.py +0 -281
  225. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  226. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  227. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  228. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  229. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  230. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  231. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  232. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  233. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  234. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  235. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  236. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  237. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  238. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  239. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  240. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  241. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  242. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  243. django_cfg/apps/tasks/admin.py +0 -320
  244. django_cfg/middleware/static_nocache.py +0 -55
  245. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  246. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  247. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  248. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  249. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  250. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
  251. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
  252. {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)