haikal/haikalbot/services/analysis_service.py
Marwan Alwali 250e0aa7bb update
2025-05-26 15:17:10 +03:00

320 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.db.models import Avg, Sum, Max, Min, ForeignKey, OneToOneField
import inspect
from django.db import models
from django.utils.translation import gettext_lazy as _
def _localized_keys(language):
"""
Get localized key names based on language.
:param language: Language code ('en' or 'ar')
:type language: str
:return: Dictionary of localized keys
:rtype: dict
"""
if language == 'ar':
return {
'type': 'نوع', 'model': 'النموذج', 'count': 'العدد', 'filters': 'الفلاتر_المطبقة',
'error': 'خطأ', 'chart_type': 'نوع_الرسم_البياني', 'labels': 'التسميات', 'data': 'البيانات',
'visualization_data': 'بيانات_الرسم_البياني', 'field': 'الحقل', 'value': 'القيمة',
'statistic_type': 'نوع_الإحصاء', 'results': 'النتائج', 'title': 'العنوان'
}
else:
return {
'type': 'type', 'model': 'model', 'count': 'count', 'filters': 'filters_applied',
'error': 'error', 'chart_type': 'chart_type', 'labels': 'labels', 'data': 'data',
'visualization_data': 'visualization_data', 'field': 'field', 'value': 'value',
'statistic_type': 'statistic_type', 'results': 'results', 'title': 'title'
}
def generate_count_insight(models, query_params, dealer_id=None, language='en'):
"""
Generate count insights for the specified models.
:param models: List of models to analyze
:type models: list
:param query_params: Query parameters for filtering
:type query_params: dict
:param dealer_id: Dealer ID for filtering
:type dealer_id: int
:param language: Language code ('en' or 'ar')
:type language: str
:return: Count insights
:rtype: dict
"""
keys = _localized_keys(language)
results = []
for model in models:
try:
queryset = model.objects.all()
if dealer_id:
if hasattr(model, 'dealer_id'):
queryset = queryset.filter(dealer_id=dealer_id)
elif hasattr(model, 'dealer'):
queryset = queryset.filter(dealer=dealer_id)
filters = {}
for key, value in query_params.items():
if key not in ['field', 'operation'] and hasattr(model, key):
try:
field = model._meta.get_field(key)
if isinstance(field, models.IntegerField):
value = int(value)
elif isinstance(field, models.BooleanField):
value = value.lower() in ('true', '1', 'yes')
except Exception:
pass
filters[key] = value
if filters:
queryset = queryset.filter(**filters)
results.append({
keys['model']: model.__name__,
keys['count']: queryset.count(),
keys['filters']: filters
})
except Exception as e:
results.append({
keys['model']: model.__name__,
keys['error']: str(e)
})
return {
keys['type']: keys['type'] + '_analysis',
keys['results']: results,
keys['visualization_data']: {
keys['chart_type']: 'bar',
keys['labels']: [r[keys['model']] for r in results if keys['count'] in r],
keys['data']: [r[keys['count']] for r in results if keys['count'] in r]
}
}
def generate_statistics_insight(models, query_params, dealer_id=None, language='en'):
"""
Generate statistical insights for the specified models.
:param models: List of models to analyze
:type models: list
:param query_params: Query parameters for filtering
:type query_params: dict
:param dealer_id: Dealer ID for filtering
:type dealer_id: int
:param language: Language code ('en' or 'ar')
:type language: str
:return: Statistical insights
:rtype: dict
"""
keys = _localized_keys(language)
results = []
field = query_params.get('field')
operation = query_params.get('operation', 'average')
for model in models:
try:
if not field or not hasattr(model, field):
continue
queryset = model.objects.all()
if dealer_id:
if hasattr(model, 'dealer_id'):
queryset = queryset.filter(dealer_id=dealer_id)
elif hasattr(model, 'dealer'):
queryset = queryset.filter(dealer=dealer_id)
filters = {}
for k, v in query_params.items():
if k not in ['field', 'operation'] and hasattr(model, k):
filters[k] = v
if filters:
queryset = queryset.filter(**filters)
stat_map = {
'average': Avg,
'sum': Sum,
'max': Max,
'min': Min
}
if operation in stat_map:
agg = queryset.aggregate(val=stat_map[operation](field))['val']
value = agg
else:
value = queryset.count()
results.append({
keys['model']: model.__name__,
keys['field']: field,
keys['statistic_type']: operation,
keys['value']: value,
keys['filters']: filters
})
except Exception as e:
results.append({keys['model']: model.__name__, keys['error']: str(e)})
return {
keys['type']: keys['type'] + '_analysis',
keys['results']: results,
keys['visualization_data']: {
keys['chart_type']: 'bar',
keys['labels']: [f"{r[keys['model']]}.{r[keys['field']]}" for r in results if keys['value'] in r],
keys['data']: [r[keys['value']] for r in results if keys['value'] in r],
keys['title']: f"{operation} of {field}" if language != 'ar' else f"{field} ({operation})"
}
}
def generate_recommendations(model_classes, analysis_type, language='en'):
"""
Generate recommendations based on model analysis.
:param model_classes: List of models to analyze
:type model_classes: list
:param analysis_type: Type of analysis
:type analysis_type: str
:param language: Language code ('en' or 'ar')
:type language: str
:return: List of recommendations
:rtype: list
"""
recs = []
for model in model_classes:
for field in model._meta.fields:
if isinstance(field, ForeignKey) and not field.db_index:
msg = f"أضف db_index=True إلى {model.__name__}.{field.name}" if language == 'ar' else f"Add db_index=True to {model.__name__}.{field.name}"
recs.append(msg)
if isinstance(field, models.CharField) and not field.db_index and field.name in ['name', 'title', 'description', 'text']:
msg = f"فكر في فهرسة الحقل النصي {model.__name__}.{field.name}" if language == 'ar' else f"Consider indexing the text field {model.__name__}.{field.name}"
recs.append(msg)
return recs[:5]
def generate_model_insight(model, dealer_id=None, language='en'):
"""
Generate insights for a specific model.
:param model: Model to analyze
:type model: Model class
:param dealer_id: Dealer ID for filtering
:type dealer_id: int
:param language: Language code ('en' or 'ar')
:type language: str
:return: Model insights
:rtype: dict
"""
keys = _localized_keys(language)
fields_info = [
{
'name': f.name,
'type': f.__class__.__name__,
'null': f.null,
'blank': f.blank,
'unique': f.unique,
'pk': f.primary_key
} for f in model._meta.fields
]
try:
qs = model.objects.all()
if dealer_id:
if hasattr(model, 'dealer_id'):
qs = qs.filter(dealer_id=dealer_id)
elif hasattr(model, 'dealer'):
qs = qs.filter(dealer=dealer_id)
count = qs.count()
except Exception:
count = "error"
return {
keys['type']: keys['type'] + '_analysis',
keys['model']: model.__name__,
'fields': fields_info,
'count': count
}
def generate_relationship_insight(models, query_params=None, dealer_id=None, language='en'):
"""
Generate relationship insights between models.
:param models: List of models to analyze
:type models: list
:param query_params: Query parameters (unused)
:type query_params: dict
:param dealer_id: Dealer ID (unused)
:type dealer_id: int
:param language: Language code ('en' or 'ar')
:type language: str
:return: Relationship insights
:rtype: dict
"""
from_ = "من" if language == 'ar' else "from"
to_ = "إلى" if language == 'ar' else "to"
rel_type = "نوع" if language == 'ar' else "type"
relationships = []
for model in models:
for field in model._meta.fields:
if isinstance(field, (ForeignKey, OneToOneField)):
relationships.append({
from_: model.__name__,
to_: field.related_model.__name__,
rel_type: field.__class__.__name__
})
for field in model._meta.many_to_many:
relationships.append({
from_: model.__name__,
to_: field.related_model.__name__,
rel_type: 'ManyToManyField'
})
return {
'type': 'تحليل_العلاقات' if language == 'ar' else 'relationship_analysis',
'relationships': relationships
}
def generate_performance_insight(models, query_params=None, dealer_id=None, language='en'):
"""
Generate performance insights for models.
:param models: List of models to analyze
:type models: list
:param query_params: Query parameters (unused)
:type query_params: dict
:param dealer_id: Dealer ID (unused)
:type dealer_id: int
:param language: Language code ('en' or 'ar')
:type language: str
:return: Performance insights
:rtype: dict
"""
issues = []
for model in models:
for field in model._meta.fields:
if isinstance(field, ForeignKey) and not field.db_index:
issues.append({
'model': model.__name__,
'field': field.name,
'issue': 'Missing index on ForeignKey'
})
if isinstance(field, models.CharField) and not field.db_index and field.name in ['name', 'title']:
issues.append({
'model': model.__name__,
'field': field.name,
'issue': 'Unindexed CharField used in filtering'
})
return {
'type': 'تحليل_الأداء' if language == 'ar' else 'performance_analysis',
'issues': issues
}