feat: added integration with yandexgpt

This commit is contained in:
ITQ
2025-02-18 14:16:00 +03:00
parent 3e637d0641
commit ff4c15650c
6 changed files with 146 additions and 0 deletions
@@ -0,0 +1,64 @@
# ruff: noqa: E501, W291
import logging
from django.conf import settings
from yandex_cloud_ml_sdk import YCloudML
from yandex_cloud_ml_sdk.exceptions import YCloudMLError
logger = logging.getLogger(__name__)
AD_PROMPT_TEMPLATE = """
Сгенерируй креативный рекламный текст для рекламодателя с именем: "{advertiser_name}",
название рекламной кампании: "{ad_title}".
Требования:
1. Текст должен быть максимально привлекательным и продающим
2. Использовать современные маркетинговые приемы
3. Включить призыв к действию
4. Соблюдать структуру: заголовок - основной текст - заключение
5. Длина: 3-5 коротких предложений
6. Ответ должен содержать только текст рекламы без дополнительных комментариев
7. Весь текст должен быть на одной строчке
Пример хорошего текста:
"Запустите свой бизнес в космос с {{advertiser_name}}! Кампания "{{ad_title}}" предлагает
уникальные решения для цифрового продвижения. Присоединяйтесь к лидерам рынка - получите
персональную консультацию сегодня!"
""".strip()
class YandexAIAdTextGenerator:
def __init__(self) -> None:
self.sdk = YCloudML(
folder_id=settings.YANDEX_CLOUD_FOLDER_ID,
auth=settings.YANDEX_CLOUD_API_KEY,
)
def generate_ad_text(
self, advertiser_name: str, ad_title: str
) -> str | None:
try:
prompt = AD_PROMPT_TEMPLATE.format(
advertiser_name=advertiser_name, ad_title=ad_title
)
promise = (
self.sdk.models.completions(
"yandexgpt-lite", model_version="latest"
)
.configure(max_tokens=400, temperature=0.9)
.run_deferred([{"role": "system", "text": prompt}])
)
result = promise.wait()
logger.debug("Generated ad text: %s", result)
return self._clean_response(result.alternatives[0].text)
except YCloudMLError:
return None
def _clean_response(self, text: str) -> str:
cleaned = text.strip()
cleaned = cleaned.replace('"', "")
return " ".join(cleaned.splitlines())
@@ -0,0 +1,25 @@
from django.conf import settings
from health_check.backends import BaseHealthCheckBackend
from yandex_cloud_ml_sdk import YCloudML
from yandex_cloud_ml_sdk.exceptions import YCloudMLError
class YandexAIHealthCheck(BaseHealthCheckBackend):
critical_service = False
def check_status(self) -> None:
try:
sdk = YCloudML(
folder_id=settings.YANDEX_CLOUD_FOLDER_ID,
auth=settings.YANDEX_CLOUD_API_KEY,
)
result = sdk.models.completions(
"yandexgpt-lite", model_version="latest"
).tokenize("ping")
if not result:
self.add_error("YandexAI API is unaccessible")
except YCloudMLError:
self.add_error("YandexAI API is unaccessible")
def identifier(self) -> str:
return self.__class__.__name__
@@ -0,0 +1,57 @@
# ruff: noqa: E501, W291
import logging
from django.conf import settings
from yandex_cloud_ml_sdk import YCloudML
from yandex_cloud_ml_sdk.exceptions import YCloudMLError
logger = logging.getLogger(__name__)
DEFAULT_INVALID_SIGNAL = (
"В интернете есть много сайтов с информацией на эту тему. "
"[Посмотрите, что нашлось в поиске](https://ya.ru)"
).lower()
MODERATION_PROMPT = """
Ты — строгий AI-модератор контента. Анализируй текст ПО ВСЕМ указанным критериям.
Если ЛЮБОЙ из критериев нарушен — верни true. Только если ВСЕ критерии соблюдены — верни false.
Критерии нарушений (true):
1. Нецензурная лексика: мат, эвфемизмы, оскорбительные выражения
2. Угрозы: прямые/косвенные угрозы жизни, шантаж, буллинг
3. Дискриминация: расизм, сексизм, ксенофобия, гомофобия
""".strip()
class YandexAIModerator:
def __init__(self) -> None:
self.sdk = YCloudML(
folder_id=settings.YANDEX_CLOUD_FOLDER_ID,
auth=settings.YANDEX_CLOUD_API_KEY,
)
def get_moderation_verdict(self, text: str) -> bool:
try:
promise = (
self.sdk.models.completions(
"yandexgpt-lite", model_version="latest"
)
.configure(max_tokens=200, temperature=0.1)
.run_deferred(
[
{"role": "system", "text": MODERATION_PROMPT},
{"role": "user", "text": text},
]
)
)
result = promise.wait()
logger.debug("Moderation API response: %s", result)
return self._normalize_response(result.alternatives[0].text)
except YCloudMLError:
return False
def _normalize_response(self, text: str) -> bool:
clean_verdict = text.strip().lower().split("\n")[0]
return clean_verdict in ("true", DEFAULT_INVALID_SIGNAL)