django-lucy-assist 1.2.3__py3-none-any.whl → 1.2.4__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 (26) hide show
  1. {django_lucy_assist-1.2.3.dist-info → django_lucy_assist-1.2.4.dist-info}/METADATA +1 -1
  2. django_lucy_assist-1.2.4.dist-info/RECORD +45 -0
  3. lucy_assist/__init__.py +1 -1
  4. lucy_assist/admin.py +6 -39
  5. lucy_assist/conf.py +4 -0
  6. lucy_assist/constantes.py +79 -29
  7. lucy_assist/migrations/0001_initial.py +3 -1
  8. lucy_assist/models/configuration.py +0 -116
  9. lucy_assist/services/context_service.py +234 -0
  10. lucy_assist/services/crud_service.py +97 -13
  11. lucy_assist/services/gitlab_service.py +79 -6
  12. lucy_assist/services/mistral_service.py +31 -11
  13. lucy_assist/services/tool_executor_service.py +91 -0
  14. lucy_assist/services/tools_definition.py +65 -0
  15. lucy_assist/services/view_discovery_service.py +47 -13
  16. lucy_assist/static/lucy_assist/css/lucy-assist.css +48 -1
  17. lucy_assist/static/lucy_assist/js/lucy-assist.js +11 -0
  18. lucy_assist/templates/lucy_assist/chatbot_sidebar.html +11 -1
  19. django_lucy_assist-1.2.3.dist-info/RECORD +0 -50
  20. lucy_assist/migrations/0002_configurationlucyassist_prompt_complementaire.py +0 -18
  21. lucy_assist/migrations/0003_configurationlucyassist_crud_views_mapping.py +0 -18
  22. lucy_assist/migrations/0004_configurationlucyassist_system_prompt.py +0 -22
  23. lucy_assist/migrations/0005_configurationlucyassist_project_context.py +0 -22
  24. lucy_assist/migrations/0006_remove_configurationlucyassist_prompt_complementaire.py +0 -17
  25. {django_lucy_assist-1.2.3.dist-info → django_lucy_assist-1.2.4.dist-info}/WHEEL +0 -0
  26. {django_lucy_assist-1.2.3.dist-info → django_lucy_assist-1.2.4.dist-info}/top_level.txt +0 -0
@@ -54,6 +54,9 @@ class ToolExecutorService:
54
54
  'get_form_fields': self._handle_get_form_fields,
55
55
  'navigate_to_page': self._handle_navigate_to_page,
56
56
  'analyze_bug': self._handle_analyze_bug,
57
+ 'get_page_help': self._handle_get_page_help,
58
+ 'search_code_gitlab': self._handle_search_code_gitlab,
59
+ 'get_file_content_gitlab': self._handle_get_file_content_gitlab,
57
60
  }
58
61
 
59
62
  handler = handlers.get(tool_name)
@@ -371,6 +374,94 @@ class ToolExecutorService:
371
374
  }
372
375
 
373
376
 
377
+ def _handle_get_page_help(self, params: Dict) -> Dict:
378
+ """
379
+ Recupere l'aide contextuelle pour la page actuelle.
380
+ """
381
+ url_path = params.get('url_path', '')
382
+
383
+ if not url_path:
384
+ return {'error': 'url_path est requis'}
385
+
386
+ help_info = self.context_service.get_page_help(url_path)
387
+
388
+ return {
389
+ 'success': True,
390
+ **help_info
391
+ }
392
+
393
+ def _handle_search_code_gitlab(self, params: Dict) -> Dict:
394
+ """
395
+ Recherche dans le code source du projet via GitLab.
396
+ """
397
+ query = params.get('query', '')
398
+ file_type = params.get('file_type', 'all')
399
+
400
+ if not query:
401
+ return {'error': 'query est requis'}
402
+
403
+ # Adapter la recherche selon le type de fichier
404
+ search_query = query
405
+ if file_type != 'all':
406
+ # Ajouter un filtre de chemin pour cibler le type de fichier
407
+ search_query = f"{query} path:{file_type}"
408
+
409
+ results = self.gitlab_service.search_code(search_query, per_page=10)
410
+
411
+ if not results:
412
+ return {
413
+ 'success': True,
414
+ 'count': 0,
415
+ 'message': f'Aucun resultat trouve pour "{query}"',
416
+ 'results': []
417
+ }
418
+
419
+ # Formater les resultats
420
+ formatted_results = []
421
+ for result in results[:10]:
422
+ formatted_results.append({
423
+ 'file': result.get('filename', ''),
424
+ 'content_preview': result.get('data', '')[:500],
425
+ 'ref': result.get('ref', '')
426
+ })
427
+
428
+ return {
429
+ 'success': True,
430
+ 'count': len(formatted_results),
431
+ 'query': query,
432
+ 'results': formatted_results
433
+ }
434
+
435
+ def _handle_get_file_content_gitlab(self, params: Dict) -> Dict:
436
+ """
437
+ Recupere le contenu complet d'un fichier depuis GitLab.
438
+ """
439
+ file_path = params.get('file_path', '')
440
+
441
+ if not file_path:
442
+ return {'error': 'file_path est requis'}
443
+
444
+ content = self.gitlab_service.get_file_content(file_path)
445
+
446
+ if content is None:
447
+ return {
448
+ 'success': False,
449
+ 'error': f'Fichier non trouve: {file_path}'
450
+ }
451
+
452
+ # Limiter la taille du contenu retourne
453
+ max_content_size = 10000
454
+ truncated = len(content) > max_content_size
455
+
456
+ return {
457
+ 'success': True,
458
+ 'file_path': file_path,
459
+ 'content': content[:max_content_size],
460
+ 'truncated': truncated,
461
+ 'total_size': len(content)
462
+ }
463
+
464
+
374
465
  def create_tool_executor(user):
375
466
  """
376
467
  Factory function pour créer un callable d'exécution de tools.
@@ -274,6 +274,71 @@ LUCY_ASSIST_TOOLS = [
274
274
  "required": ["user_description"]
275
275
  }
276
276
  }
277
+ },
278
+ {
279
+ "type": "function",
280
+ "function": {
281
+ "name": "get_page_help",
282
+ "description": """Recupere l'aide contextuelle pour la page actuelle.
283
+ Utilise ce tool pour obtenir des informations sur ce que l'utilisateur peut faire sur la page.
284
+ Retourne les actions suggerees, liens utiles et conseils.""",
285
+ "parameters": {
286
+ "type": "object",
287
+ "properties": {
288
+ "url_path": {
289
+ "type": "string",
290
+ "description": "URL de la page actuelle (disponible dans le contexte)"
291
+ }
292
+ },
293
+ "required": ["url_path"]
294
+ }
295
+ }
296
+ },
297
+ {
298
+ "type": "function",
299
+ "function": {
300
+ "name": "search_code_gitlab",
301
+ "description": """USAGE INTERNE - Recherche dans le code source pour comprendre le fonctionnement.
302
+ Utilise ce tool pour comprendre comment fonctionne une fonctionnalite.
303
+ IMPORTANT: Les resultats sont pour TON usage interne uniquement.
304
+ Ne JAMAIS montrer les chemins de fichiers ou le code a l'utilisateur.
305
+ Utilise ces informations pour repondre en termes simples avec des liens vers les pages.""",
306
+ "parameters": {
307
+ "type": "object",
308
+ "properties": {
309
+ "query": {
310
+ "type": "string",
311
+ "description": "Terme de recherche (nom de classe, fonction, variable, texte)"
312
+ },
313
+ "file_type": {
314
+ "type": "string",
315
+ "enum": ["models", "views", "urls", "forms", "admin", "all"],
316
+ "description": "Type de fichier a rechercher (defaut: all)"
317
+ }
318
+ },
319
+ "required": ["query"]
320
+ }
321
+ }
322
+ },
323
+ {
324
+ "type": "function",
325
+ "function": {
326
+ "name": "get_file_content_gitlab",
327
+ "description": """USAGE INTERNE - Recupere le contenu d'un fichier pour comprendre le fonctionnement.
328
+ IMPORTANT: Les resultats sont pour TON usage interne uniquement.
329
+ Ne JAMAIS montrer le code source ou les chemins de fichiers a l'utilisateur.
330
+ Utilise ces informations pour repondre en termes simples avec des liens vers les pages.""",
331
+ "parameters": {
332
+ "type": "object",
333
+ "properties": {
334
+ "file_path": {
335
+ "type": "string",
336
+ "description": "Chemin du fichier dans le repository"
337
+ }
338
+ },
339
+ "required": ["file_path"]
340
+ }
341
+ }
277
342
  }
278
343
  ]
279
344
 
@@ -16,8 +16,16 @@ from lucy_assist.conf import lucy_assist_settings
16
16
  class ViewDiscoveryService:
17
17
  """
18
18
  Service pour découvrir automatiquement les vues CRUD d'un projet Django.
19
+
20
+ La découverte est mise en cache en mémoire pour éviter de scanner
21
+ les URLs à chaque requête.
19
22
  """
20
23
 
24
+ # Cache en mémoire pour les vues découvertes (partagé entre instances)
25
+ _views_cache = None
26
+ _cache_timestamp = None
27
+ CACHE_TTL = 300 # 5 minutes
28
+
21
29
  # Patterns de nommage courants pour les vues CRUD
22
30
  # L'ordre est important : les patterns plus spécifiques doivent être en premier
23
31
  CRUD_PATTERNS = {
@@ -65,6 +73,35 @@ class ViewDiscoveryService:
65
73
  def __init__(self):
66
74
  self.apps_prefix = lucy_assist_settings.PROJECT_APPS_PREFIX or ''
67
75
 
76
+ @classmethod
77
+ def get_cached_views(cls) -> Dict:
78
+ """
79
+ Retourne les vues CRUD depuis le cache mémoire.
80
+ Redécouvre automatiquement si le cache est expiré.
81
+ """
82
+ import time
83
+
84
+ now = time.time()
85
+
86
+ # Vérifier si le cache est valide
87
+ if (cls._views_cache is not None and
88
+ cls._cache_timestamp is not None and
89
+ now - cls._cache_timestamp < cls.CACHE_TTL):
90
+ return cls._views_cache
91
+
92
+ # Redécouvrir les vues
93
+ service = cls()
94
+ cls._views_cache = service.discover_crud_views()
95
+ cls._cache_timestamp = now
96
+
97
+ return cls._views_cache
98
+
99
+ @classmethod
100
+ def invalidate_cache(cls):
101
+ """Force la redécouverte des vues au prochain appel."""
102
+ cls._views_cache = None
103
+ cls._cache_timestamp = None
104
+
68
105
  def discover_crud_views(self) -> Dict:
69
106
  """
70
107
  Découvre toutes les vues CRUD du projet.
@@ -293,6 +330,9 @@ class ViewDiscoveryService:
293
330
  """
294
331
  Récupère les informations d'une vue pour un modèle et une action.
295
332
 
333
+ Utilise le cache mémoire pour éviter de scanner les URLs à chaque requête.
334
+ Le cache est automatiquement rafraîchi après CACHE_TTL secondes.
335
+
296
336
  Args:
297
337
  model_name: Nom du modèle
298
338
  action: Action CRUD ('list', 'create', 'detail', 'update', 'delete')
@@ -300,11 +340,8 @@ class ViewDiscoveryService:
300
340
  Returns:
301
341
  Dict avec 'url_name', 'url', 'method', 'requires_pk' ou None
302
342
  """
303
- from lucy_assist.models import ConfigurationLucyAssist
304
- config = ConfigurationLucyAssist.get_config()
305
-
306
- if not config.crud_views_mapping:
307
- config.refresh_crud_views_mapping()
343
+ # Utiliser le cache mémoire (découverte dynamique)
344
+ crud_views_mapping = self.get_cached_views()
308
345
 
309
346
  model_lower = model_name.lower()
310
347
 
@@ -317,10 +354,12 @@ class ViewDiscoveryService:
317
354
  ]
318
355
 
319
356
  for variant in variations:
320
- model_views = config.crud_views_mapping.get(variant, {})
357
+ model_views = crud_views_mapping.get(variant, {})
321
358
  if model_views and action in model_views:
359
+ LogUtils.info(f"[ViewDiscovery] Vue trouvée: {variant}.{action} -> {model_views[action].get('url_name')}")
322
360
  return model_views.get(action)
323
361
 
362
+ LogUtils.info(f"[ViewDiscovery] Aucune vue trouvée pour {model_name}.{action}")
324
363
  return None
325
364
 
326
365
  def get_all_discovered_models(self) -> List[str]:
@@ -330,10 +369,5 @@ class ViewDiscoveryService:
330
369
  Returns:
331
370
  Liste des noms de modèles
332
371
  """
333
- from lucy_assist.models import ConfigurationLucyAssist
334
- config = ConfigurationLucyAssist.get_config()
335
-
336
- if not config.crud_views_mapping:
337
- config.refresh_crud_views_mapping()
338
-
339
- return list(config.crud_views_mapping.keys())
372
+ crud_views_mapping = self.get_cached_views()
373
+ return list(crud_views_mapping.keys())
@@ -113,9 +113,17 @@
113
113
  transform: translateX(100%);
114
114
  }
115
115
 
116
+ /* Sidebar expanded (80% width) */
117
+ .lucy-sidebar.expanded {
118
+ width: 90vw;
119
+ max-width: 90vw;
120
+ }
121
+
116
122
  @media (max-width: 640px) {
117
- .lucy-sidebar {
123
+ .lucy-sidebar,
124
+ .lucy-sidebar.expanded {
118
125
  width: 100%;
126
+ max-width: 100vw;
119
127
  }
120
128
  }
121
129
 
@@ -304,6 +312,7 @@
304
312
  .lucy-messages {
305
313
  flex: 1;
306
314
  overflow-y: auto;
315
+ overflow-x: hidden;
307
316
  padding: 1rem;
308
317
  display: flex;
309
318
  flex-direction: column;
@@ -389,6 +398,7 @@
389
398
  display: flex;
390
399
  gap: 0.5rem;
391
400
  max-width: 85%;
401
+ min-width: 0;
392
402
  }
393
403
 
394
404
  .lucy-message.user {
@@ -422,6 +432,9 @@
422
432
  .lucy-message-content {
423
433
  display: flex;
424
434
  flex-direction: column;
435
+ min-width: 0;
436
+ max-width: 100%;
437
+ overflow: hidden;
425
438
  }
426
439
 
427
440
  .lucy-message-bubble {
@@ -430,6 +443,9 @@
430
443
  font-size: 0.875rem;
431
444
  line-height: 1.5;
432
445
  word-wrap: break-word;
446
+ overflow-wrap: break-word;
447
+ max-width: 100%;
448
+ overflow-x: auto;
433
449
  }
434
450
 
435
451
  .lucy-message.bot .lucy-message-bubble {
@@ -897,6 +913,9 @@
897
913
  border-radius: 0.375rem;
898
914
  overflow-x: auto;
899
915
  margin: 0.5rem 0;
916
+ max-width: 100%;
917
+ white-space: pre-wrap;
918
+ word-break: break-word;
900
919
  }
901
920
 
902
921
  .lucy-message-bubble code {
@@ -909,6 +928,34 @@
909
928
  text-decoration: underline;
910
929
  }
911
930
 
931
+ /* Tables in messages */
932
+ .lucy-message-bubble table {
933
+ border-collapse: collapse;
934
+ font-size: 0.75rem;
935
+ margin: 0.5rem 0;
936
+ width: max-content;
937
+ max-width: 100%;
938
+ }
939
+
940
+ .lucy-message-bubble th,
941
+ .lucy-message-bubble td {
942
+ border: 1px solid var(--lucy-border);
943
+ padding: 0.25rem 0.5rem;
944
+ text-align: left;
945
+ white-space: nowrap;
946
+ }
947
+
948
+ .lucy-message-bubble th {
949
+ background: var(--lucy-bg-darker);
950
+ font-weight: 600;
951
+ }
952
+
953
+ /* Markdown content wrapper for overflow */
954
+ .lucy-message-bubble .markdown-content {
955
+ overflow-x: auto;
956
+ max-width: 100%;
957
+ }
958
+
912
959
  /* ========================================
913
960
  DOCUMENTATION - COLLAPSE/ACCORDION
914
961
  ======================================== */
@@ -9,6 +9,7 @@ function lucyAssist() {
9
9
  return {
10
10
  // État de l'interface
11
11
  isOpen: false,
12
+ isExpanded: false,
12
13
  isLoading: false,
13
14
  showHistory: false,
14
15
  showDoc: false,
@@ -86,6 +87,7 @@ function lucyAssist() {
86
87
  saveState() {
87
88
  const state = {
88
89
  isOpen: this.isOpen,
90
+ isExpanded: this.isExpanded,
89
91
  currentConversationId: this.currentConversationId,
90
92
  showHistory: this.showHistory,
91
93
  showDoc: this.showDoc
@@ -102,6 +104,7 @@ function lucyAssist() {
102
104
  if (savedState) {
103
105
  const state = JSON.parse(savedState);
104
106
  this.isOpen = state.isOpen || false;
107
+ this.isExpanded = state.isExpanded || false;
105
108
  this.currentConversationId = state.currentConversationId || null;
106
109
  this.showHistory = state.showHistory || false;
107
110
  this.showDoc = state.showDoc || false;
@@ -148,6 +151,14 @@ function lucyAssist() {
148
151
  this.showDoc = false;
149
152
  },
150
153
 
154
+ /**
155
+ * Toggle du mode agrandi (80% de la fenetre)
156
+ */
157
+ toggleExpanded() {
158
+ this.isExpanded = !this.isExpanded;
159
+ this.saveState();
160
+ },
161
+
151
162
  /**
152
163
  * Vérifie si c'est le premier lancement
153
164
  */
@@ -34,7 +34,7 @@
34
34
  x-transition:leave-start="transform translate-x-0"
35
35
  x-transition:leave-end="transform translate-x-full"
36
36
  class="lucy-sidebar"
37
- :class="{ 'hidden': !isOpen }"
37
+ :class="{ 'hidden': !isOpen, 'expanded': isExpanded }"
38
38
  style="display: none;"
39
39
  x-cloak
40
40
  >
@@ -42,6 +42,16 @@
42
42
  <div class="lucy-header">
43
43
  <span class="lucy-header-title">Lucy Assist</span>
44
44
  <div class="lucy-header-actions">
45
+ {# Bouton Agrandir/Reduire #}
46
+ <button
47
+ @click="toggleExpanded()"
48
+ class="lucy-header-btn"
49
+ :class="{ 'active': isExpanded }"
50
+ :title="isExpanded ? 'Reduire la fenetre' : 'Agrandir la fenetre'"
51
+ >
52
+ <i class="fa-solid" :class="isExpanded ? 'fa-compress' : 'fa-expand'"></i>
53
+ </button>
54
+
45
55
  {# Bouton Historique #}
46
56
  <button
47
57
  @click="showHistory = !showHistory; showDoc = false"
@@ -1,50 +0,0 @@
1
- lucy_assist/__init__.py,sha256=9NTQKOljcruDMZjj1WQhcSRRjLbrx61jyaTuhXpk9ds,325
2
- lucy_assist/admin.py,sha256=CFVBPmuFRIJzxc2pZ9s3LK1kdxMhSbLVA022VgbH89Y,4734
3
- lucy_assist/apps.py,sha256=zHZtlBXs5ML4CKtGg7xDyptSWzLfB1ks2VvbXF50hdo,264
4
- lucy_assist/conf.py,sha256=RgtZSrUwHZjjbEGZqQvifvC4GNdICmhty2XetfvAbls,3992
5
- lucy_assist/constantes.py,sha256=9L2VGBK0HorJoNDGdwQlhEfT75W-xNPAhtS0-qgawBs,3947
6
- lucy_assist/context_processors.py,sha256=tnzil4CEJwtExuQGLyRzIEuwpQfnwJ-eMgkkR6zNgSg,2200
7
- lucy_assist/signals.py,sha256=i3Uj9v-0zyAIROFl86fLlwaqRqQizL9_CpWmVjJbk8g,863
8
- lucy_assist/urls.py,sha256=Qr8jJjEyC_EFGAeiZnjhgTc-9P4Y-TqKDaYicWRp_GQ,1451
9
- lucy_assist/migrations/0001_initial.py,sha256=quQUw6is5clu3Q4B3P_0mUZVE33lSvdimH_OTCY3ycE,4977
10
- lucy_assist/migrations/0002_configurationlucyassist_prompt_complementaire.py,sha256=yWE4-RPHQtPAqYHlAhr4EsXgk35kI8zRQArlAP_JwDc,418
11
- lucy_assist/migrations/0003_configurationlucyassist_crud_views_mapping.py,sha256=1vnu1VwVBouskhQBgLz-Lp71p4a9Cb9PjrT-RLVGY7s,429
12
- lucy_assist/migrations/0004_configurationlucyassist_system_prompt.py,sha256=0a78xO15oiLcCSlO8BicMac_QE8IfiNSt9WlGptVNNo,568
13
- lucy_assist/migrations/0005_configurationlucyassist_project_context.py,sha256=6eZCssiWylS_9pg9wDExbUZWEDwk2zaVu_f3pqMzuz8,564
14
- lucy_assist/migrations/0006_remove_configurationlucyassist_prompt_complementaire.py,sha256=AwTzbmZWfWJ7Q_kcbSspSOiVJgHzGLLeMupeRSSVuI4,359
15
- lucy_assist/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- lucy_assist/models/__init__.py,sha256=JQMr50P94sBrKwwcNArRE_qnk7dLnknMKCabeRLskJc,415
17
- lucy_assist/models/base.py,sha256=Ql2AY7bzvcxZhxsPdCpbVEKvtWD-NBkHTLYZX4TjT3s,1532
18
- lucy_assist/models/configuration.py,sha256=GHmgkVZk3m01vlDwT-YEn4UG4za8e3Qr7xK00vsd_Qc,17095
19
- lucy_assist/models/conversation.py,sha256=psx2AQtQ5SFP-AJD7wbGabpXXLIGYngdVZfeoTlgKtQ,1849
20
- lucy_assist/models/message.py,sha256=kf-ffMtLYNFhXYUrB3QSL97KKDJUOMrKaPjKeOcJa_o,1492
21
- lucy_assist/models/project_context_cache.py,sha256=Bnb0VU7pv7QEvjOI6JSLEPvL4BxskCQ0ojWGxO7YDSM,6530
22
- lucy_assist/services/__init__.py,sha256=2Txqcn_M33amvlI1KZLJk9RXvu0s0I2-GfYKX_RAe3w,807
23
- lucy_assist/services/bug_notification_service.py,sha256=OyowCvAs-QDlsGQ_WTFoc4lRe9detD7r6ZyYK0JD2Sc,7217
24
- lucy_assist/services/context_service.py,sha256=Vx2tR6W1jmqr06pGn924uzWTF2SV7RAO_JIScxYbCy0,17087
25
- lucy_assist/services/crud_service.py,sha256=W50K02ZkaScyzO-yRaBd9Cjva9PGH7OjNTipSruErcA,41495
26
- lucy_assist/services/gitlab_service.py,sha256=uH83fwRSCwiRItznENpYQG4aPckjafYIV9z6OChUrZg,8056
27
- lucy_assist/services/mistral_service.py,sha256=mmoI2ixBFTeKFOId-2goe-NGpvjd_cMW9PMuV2C-P2k,18624
28
- lucy_assist/services/project_context_service.py,sha256=6QNVL-K2D-8whIPfyAJhi_xAifqTXxR09461YNBwg4o,14826
29
- lucy_assist/services/tool_executor_service.py,sha256=nTeJbj2JUDMk_bmLVgGxtWqFbSgywq-tNRBK-_3Yayw,15155
30
- lucy_assist/services/tools_definition.py,sha256=qIiIoB5_QMqmkD03OOEk_3A5Nc0g0avAjDCj3Uq3_r8,11735
31
- lucy_assist/services/view_discovery_service.py,sha256=J9LkHXUOzlGS3cyft2_jA1X27TWOd3xViN4M7GOROVw,11872
32
- lucy_assist/static/lucy_assist/css/lucy-assist.css,sha256=7bJfV31cIgOFJQ8RQ0vIqgel6dM8dh5W2wshv6MHjxs,23325
33
- lucy_assist/static/lucy_assist/image/icon-lucy.png,sha256=FOYlwXAt40Gr9jsWFmhgPivYOBFWKeYW0lxJI5Up-GM,6710
34
- lucy_assist/static/lucy_assist/js/lucy-assist.js,sha256=dmXtSPQ38LisoRWZd3R1Ms6OvVaEk3OrYKcVM0OMb_Q,28207
35
- lucy_assist/templates/lucy_assist/chatbot_sidebar.html,sha256=HtxR8G0c21vWmaXN4ALJXT7VhdUlOhtheeu8kk7Emjg,18925
36
- lucy_assist/templates/lucy_assist/partials/documentation_content.html,sha256=twbe3TvuPfy1Et2LMElK0JJNq2awb3SnIouA8v8NeWs,4143
37
- lucy_assist/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- lucy_assist/tests/test_lucy_assist.py,sha256=KBvuED10_gOJWdaRS2zMigM3W5Kp00KhMEwaR8tvhUc,6949
39
- lucy_assist/tests/factories/__init__.py,sha256=cDkgr4aPFKwbPo6JLY2s22pHrGWPI_vqG4IafWAhSmE,376
40
- lucy_assist/tests/factories/lucy_assist_factories.py,sha256=Mz1EN7xtMpIDJPNMledDbjR6X6dsBNv7JWczjD9-_MQ,3674
41
- lucy_assist/utils/__init__.py,sha256=FnL0QF7pyhjHCOywVAkZq3dl4IEgT39prJk1FtXMBDc,129
42
- lucy_assist/utils/log_utils.py,sha256=gdjaKg5PNUYlDVCQNFXQJG3vsLKay_aWX6AJxoHtiG4,1720
43
- lucy_assist/utils/message_utils.py,sha256=YzcLHnl1ig4d5_utHCJwgxS7tKmd49Q-tuo78e6w2Ww,4494
44
- lucy_assist/utils/token_utils.py,sha256=aBzyKVqpU67rAetO_Ee3QIfPtbNyjyWSe6qPfzIRJF8,2608
45
- lucy_assist/views/__init__.py,sha256=uUPYpuHlBC8j7zKS_DDoWjwpCpRnOIXETY-S2-Ss0cY,288
46
- lucy_assist/views/api_views.py,sha256=sJwKNC9-mi1zMbgyKZTVvT3pz4hMmw4jR0rrS7iJR-g,23619
47
- django_lucy_assist-1.2.3.dist-info/METADATA,sha256=JDd1H3wg2RpwLmeVdA-Ednz73-6-St1r3oSHWu3ztdQ,5899
48
- django_lucy_assist-1.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
49
- django_lucy_assist-1.2.3.dist-info/top_level.txt,sha256=T-UCiwpn5yF3Oem3234TUpSVnEgbkrM2rGz9Tz5N-QA,12
50
- django_lucy_assist-1.2.3.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- # Generated by Django 6.0.1 on 2026-01-27 09:51
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('lucy_assist', '0001_initial'),
10
- ]
11
-
12
- operations = [
13
- migrations.AddField(
14
- model_name='configurationlucyassist',
15
- name='prompt_complementaire',
16
- field=models.TextField(blank=True, default=''),
17
- ),
18
- ]
@@ -1,18 +0,0 @@
1
- # Generated by Django
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('lucy_assist', '0002_configurationlucyassist_prompt_complementaire'),
10
- ]
11
-
12
- operations = [
13
- migrations.AddField(
14
- model_name='configurationlucyassist',
15
- name='crud_views_mapping',
16
- field=models.JSONField(blank=True, default=dict),
17
- ),
18
- ]
@@ -1,22 +0,0 @@
1
- # Generated by Django
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('lucy_assist', '0003_configurationlucyassist_crud_views_mapping'),
10
- ]
11
-
12
- operations = [
13
- migrations.AddField(
14
- model_name='configurationlucyassist',
15
- name='system_prompt',
16
- field=models.TextField(
17
- blank=True,
18
- default='',
19
- help_text="Prompt système pour l'assistant IA. Initialisé automatiquement si vide."
20
- ),
21
- ),
22
- ]
@@ -1,22 +0,0 @@
1
- # Generated by Django
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('lucy_assist', '0004_configurationlucyassist_system_prompt'),
10
- ]
11
-
12
- operations = [
13
- migrations.AddField(
14
- model_name='configurationlucyassist',
15
- name='project_context',
16
- field=models.TextField(
17
- blank=True,
18
- default='',
19
- help_text="Contexte du projet analyse depuis GitLab. Rafraichir via l'action admin."
20
- ),
21
- ),
22
- ]
@@ -1,17 +0,0 @@
1
- # Generated by Django
2
-
3
- from django.db import migrations
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('lucy_assist', '0005_configurationlucyassist_project_context'),
10
- ]
11
-
12
- operations = [
13
- migrations.RemoveField(
14
- model_name='configurationlucyassist',
15
- name='prompt_complementaire',
16
- ),
17
- ]