refactor(ai): улучшить архитектуру генератора названий букетов

- Добавить константы для параметров генерации
- Улучшить валидацию входных параметров
- Оптимизировать выбор AI-сервиса
- Реализовать нормализацию регистра названий
- Добавить обработку ошибок при сохранении в базу данных
- Улучшить логику фильтрации нежелательных префиксов
- Рефакторить метод generate_and_store для лучшей читаемости
This commit is contained in:
2026-01-23 15:18:51 +03:00
parent 84cfc5cd47
commit 9ddf54f398

View File

@@ -19,6 +19,12 @@ class BouquetNameGenerator(BaseAIProductService):
"Избегайте общих терминов. Фокусируйтесь на эмоциях, эстетике" "Избегайте общих терминов. Фокусируйтесь на эмоциях, эстетике"
) )
# Константы
MAX_TOKENS_GENERATION = 3000
DEFAULT_COUNT = 500
MAX_GENERATION_COUNT = 1000
SKIP_PREFIXES = {'here', 'names', "i'm", 'sorry', 'i hope', 'hope'}
def generate( def generate(
self, self,
count: int = 500, count: int = 500,
@@ -38,17 +44,17 @@ class BouquetNameGenerator(BaseAIProductService):
Returns: Returns:
Tuple: (success, message, data) где data содержит список названий Tuple: (success, message, data) где data содержит список названий
""" """
# Валидация параметров
if count > self.MAX_GENERATION_COUNT:
count = self.MAX_GENERATION_COUNT
logger.warning(f"Count reduced to {self.MAX_GENERATION_COUNT}")
logger.info(f"Генерация {count} названий для букетов") logger.info(f"Генерация {count} названий для букетов")
# Получаем доступный AI-сервис # Получаем доступный AI-сервис
glm_service = self.get_glm_service() service = self.get_glm_service() or self.get_openrouter_service()
if not glm_service: if not service:
openrouter_service = self.get_openrouter_service() return False, "Нет активных AI-интеграций", None
if not openrouter_service:
return False, "Нет активных AI-интеграций", None
service = openrouter_service
else:
service = glm_service
# Формируем промпт # Формируем промпт
prompt = f"Сгенерируй {count} креативных и привлекательных названий для букетов цветов" prompt = f"Сгенерируй {count} креативных и привлекательных названий для букетов цветов"
@@ -98,9 +104,7 @@ class BouquetNameGenerator(BaseAIProductService):
for line in lines: for line in lines:
line = line.strip() line = line.strip()
# Пропускаем пустые строки и заголовки # Пропускаем пустые строки и заголовки
if not line or line.lower().startswith('here') or line.lower().startswith('names') or \ if not line or any(line.lower().startswith(prefix) for prefix in self.SKIP_PREFIXES):
line.lower().startswith('i\'m') or line.lower().startswith('sorry') or \
line.lower().startswith('i hope') or line.lower().startswith('hope'):
continue continue
# Удаляем номера списка # Удаляем номера списка
@@ -119,7 +123,9 @@ class BouquetNameGenerator(BaseAIProductService):
line = line.replace('**', '').replace('*', '').replace('"', '').replace("'", '').strip() line = line.replace('**', '').replace('*', '').replace('"', '').replace("'", '').strip()
if line: if line:
names.append(line) # Приводим к нужному формату: первое слово с заглавной, остальные строчные
normalized_line = self._normalize_case(line)
names.append(normalized_line)
# Удаляем дубликаты # Удаляем дубликаты
unique_names = [] unique_names = []
@@ -131,6 +137,28 @@ class BouquetNameGenerator(BaseAIProductService):
return unique_names return unique_names
def _normalize_case(self, text: str) -> str:
"""
Приводит текст к формату: первое слово с заглавной буквы, остальные строчные
Например: "романтический БУКЕТ роз" -> "Романтический букет роз"
Но сохраняет имена собственные: "Букет Van Gogh" -> "Букет Van Gogh"
"""
if not text:
return text
# Разбиваем текст на слова
words = text.split()
if not words:
return text
# Первое слово с заглавной буквы, остальные как есть (сохраняем имена собственные)
first_word = words[0].capitalize()
remaining_words = words[1:]
# Собираем обратно в строку
return ' '.join([first_word] + remaining_words)
def generate_and_store( def generate_and_store(
self, self,
count: int = 500, count: int = 500,
@@ -142,23 +170,33 @@ class BouquetNameGenerator(BaseAIProductService):
Генерирует названия и сохраняет в базу данных Генерирует названия и сохраняет в базу данных
""" """
from products.models import BouquetName from products.models import BouquetName
success, msg, data = self.generate(count, characteristics, occasion, language) success, msg, data = self.generate(count, characteristics, occasion, language)
if success and data: if success and data:
# Сохраняем названия в базу # Сохраняем названия в базу
stored_count = 0 stored_count = 0
for name in data['names']: failed_count = 0
BouquetName.objects.get_or_create(
name=name,
language=language,
defaults={
'is_approved': False
}
)
stored_count += 1
return True, f"Сгенерировано и сохранено {stored_count} названий для букетов", data for name in data['names']:
try:
BouquetName.objects.get_or_create(
name=name,
language=language,
defaults={
'is_approved': False
}
)
stored_count += 1
except Exception as e:
logger.error(f"Ошибка сохранения названия '{name}': {e}")
failed_count += 1
success_msg = f"Сгенерировано и сохранено {stored_count} названий для букетов"
if failed_count > 0:
success_msg += f", не удалось сохранить {failed_count} названий"
return True, success_msg, data
return success, msg, data return success, msg, data