fruitpicker01 commited on
Commit
b5849a6
1 Parent(s): e3f7d5f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +936 -128
app.py CHANGED
@@ -10,12 +10,50 @@ import plotly.graph_objects as go
10
  import random
11
  import pymorphy2
12
  import string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  morph = pymorphy2.MorphAnalyzer()
15
 
16
  # Авторизация в GigaChat Pro
17
  gc_key = os.getenv('GC_KEY')
18
- chat_pro = GigaChat(credentials=gc_key, model='GigaChat', max_tokens=68, temperature=1.5, verify_ssl_certs=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  # Загрузка данных из Excel-файла
21
  try:
@@ -60,6 +98,78 @@ def create_gauge(value):
60
  fig.update_layout(paper_bgcolor="#f8f9fa", font={'color': "#2d3436", 'family': "Arial"}, width=250, height=150)
61
  return fig
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  # Функция для генерации случайных значений спидометров
64
  def generate_random_gauges():
65
  return create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95))
@@ -90,14 +200,77 @@ def generate_message_gigachat_pro(prompt):
90
  except Exception as e:
91
  return f"Ошибка при обращении к GigaChat-Pro: {e}"
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  # Функция для замены сокращений с 'k' или 'К' на тысячи
94
  def replace_k_with_thousands(message):
95
  # Замена и для 'k' и для 'К', с учётом регистра
96
  message = re.sub(r'(\d+)[kкКK]', r'\1 000', message, flags=re.IGNORECASE)
97
  return message
98
 
99
- # Функция для корректировки использования тире и дефисов
100
  def correct_dash_usage(text):
 
101
  # Step 1: Replace any dash with long dash if surrounded by spaces
102
  text = re.sub(r'\s[-–—]\s', ' — ', text)
103
 
@@ -107,35 +280,176 @@ def correct_dash_usage(text):
107
  # Step 3: Replace any dash with hyphen if surrounded by letters or a combination of letters and digits
108
  text = re.sub(r'(?<=[a-zA-Zа-яА-Я0-9])[-–—](?=[a-zA-Zа-яА-Я0-9])', '-', text)
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  return text
111
 
 
112
  # Функция для добавления ошибок в промпт для перегенерации
113
  def append_errors_to_prompt(prompt, checks):
114
- errors = []
115
-
116
- if not checks["forbidden_words"]:
117
- errors.append("Не использовать запрещённые слова.")
118
- if not checks["client_addressing"]:
119
- errors.append("Не обращаться к клиенту напрямую.")
120
- if not checks["promises"]:
121
- errors.append("Не давать обещания и гарантии.")
122
- if not checks["double_verbs"]:
123
- errors.append("Не используй два глагола подряд (например, хочешь оформить).")
124
- if not checks["participles"]:
125
- errors.append("Не использовать причастия.")
126
- if not checks["adverbial_participles"]:
127
- errors.append("Не использовать деепричастия.")
128
-
129
- # Добавляем ошибки в конец промпта
130
- if errors:
131
- error_instructions = "Следующие ошибки необходимо избежать:\n" + "\n".join(errors)
132
- prompt += f"\n\n{error_instructions}"
133
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  return prompt
 
135
 
136
  def notify_failed_length(message_length):
137
- if message_length < 190:
138
- gr.Warning(f"Сообщение слишком короткое: {message_length} знаков. Минимум 190.")
139
  return False
140
  elif message_length > 250:
141
  gr.Warning(f"Сообщение слишком длинное: {message_length} знаков. Максимум 250.")
@@ -144,66 +458,106 @@ def notify_failed_length(message_length):
144
 
145
  # Функция для уведомления о непройденных проверках
146
  def notify_failed_checks(checks):
147
- # Словарь для перевода англоязычных названий правил в русские
148
  translation = {
149
  "forbidden_words": "Запрещенные слова",
150
  "client_addressing": "Обращение к клиенту",
151
  "promises": "Обещания и гарантии",
152
  "double_verbs": "Два глагола подряд",
153
  "participles": "Причастия",
154
- "adverbial_participles": "Деепричастия"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
157
- # Находим непройденные проверки
158
- failed_checks = [translation[rule] for rule, passed in checks.items() if not passed]
159
-
160
- # Если есть непройденные проверки, выводим предупреждение с русскими названиями правил
161
- if failed_checks:
162
- gr.Warning(f"Сообщение не прошло следующие проверки: {', '.join(failed_checks)}")
 
 
 
163
 
164
  # Модифицированная функция перегенерации сообщений с уведомлениями о номере попытки
165
- def generate_message_gigachat_pro_with_retry(prompt):
166
- last_message = None # Храним последнее сообщение
167
-
168
- for attempt in range(20):
169
- # Уведомление о текущей попытке
170
  gr.Info(f"Итерация {attempt + 1}: генерируется сообщение...")
171
-
172
- # Генерация сообщения
173
  message = generate_message_gigachat_pro(prompt)
174
  message = replace_k_with_thousands(message)
175
  message = correct_dash_usage(message)
176
  message_length = len(message)
177
-
178
- # Проверка длины сообщения. Если не проходит, сразу перегенерируем
179
  if not notify_failed_length(message_length):
180
- last_message = message # Обновляем последнее сообщение
181
- time.sleep(1) # Пауза перед следующей попыткой
182
  continue
183
-
184
- # Выполняем замены и проверки
185
- checks = perform_checks(message)
186
-
187
- # Обновляем последнее сообщение
188
  last_message = message
189
-
190
- # Если сообщение прошло все проверки
 
 
 
 
191
  if all(checks.values()):
192
  return message
193
-
194
- # Если есть ошибки, уведомляем о непройденных проверках
195
- notify_failed_checks(checks)
196
-
197
- # Если есть ошибки, обновляем промпт с инструкцией об ошибках
198
  prompt = append_errors_to_prompt(prompt, checks)
199
-
200
- time.sleep(1) # Пауза перед следующей попыткой
201
-
202
- # Возвращаем последнее сообщение после 10 попыток
203
  gr.Info("Не удалось сгенерировать сообщение, соответствующее требованиям, за 20 итераций. Возвращаем последнее сгенерированное сообщение.")
204
  return last_message
205
 
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  # Функция для создания задания для копирайтера
208
  def generate_standard_prompt(description, advantages, key_message, *selected_values):
209
  prompt = (
@@ -211,7 +565,7 @@ def generate_standard_prompt(description, advantages, key_message, *selected_val
211
  f"Описание предложения: {description}\n"
212
  f"Преимущества: {advantages}\n"
213
  "В тексте смс запрещено использование:\n"
214
- "- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, доступный, банкротство, долги, займ, срочно, сейчас, лучший, главный, номер 1, гарантия, успех, лидер;\n"
215
  "- Обращение к клиенту;\n"
216
  "- Приветствие клиента;\n"
217
  "- Обещания и гарантии;\n"
@@ -238,7 +592,7 @@ def generate_standard_prompt(description, advantages, key_message, *selected_val
238
  "- Узкоспециализированные термины;\n"
239
  "- Фразы, способные создать двойственное ощущение, обидеть;\n"
240
  "- Речевые клише, рекламные штампы, канцеляризмы;\n"
241
- "Убедись, что в готовом тексте до 250, но не менее 190 знаков с пробелами.\n"
242
  )
243
  if key_message.strip():
244
  prompt += f"Убедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
@@ -248,7 +602,7 @@ def generate_standard_prompt(description, advantages, key_message, *selected_val
248
 
249
  # Функция для создания задания для редактора с добавлением prefix и suffix
250
  def generate_personalization_prompt(key_message, *selected_values, prefix, suffix):
251
- prompt = "Адаптируй, не превышая длину сообщения в 250 знаков с пробелами (но и не менее 190 знаков с пробелами), текст с учетом следующих особенностей:\n"
252
  gender, generation, psychotype = selected_values[0], selected_values[1], selected_values[2]
253
  combined_instruction = ""
254
  additional_instructions = ""
@@ -291,7 +645,8 @@ def generate_personalization_prompt(key_message, *selected_values, prefix, suffi
291
 
292
  # Добавляем префикс и суффикс для задания редактора
293
  prompt = f"{prefix}\n{prompt}\n{suffix}"
294
-
 
295
  # Добавляем ключевое сообщение
296
  prompt += f"\nУбедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
297
 
@@ -314,11 +669,8 @@ def clean_prompt_for_display(prompt, prefixes, suffixes):
314
 
315
  # Функция для постепенной генерации всех сообщений через yield
316
  def generate_all_messages(desc, benefits, key_message, gender, generation, psychotype, business_stage, industry, opf):
317
- # Генерация задания для копирайтера
318
  standard_prompt = generate_standard_prompt(desc, benefits, key_message)
319
  yield standard_prompt, None, None, None, None, None, None, None
320
-
321
- # Варианты предложений для начала и конца
322
  prefixes = [
323
  "Начни сообщение с призыва к действию с продуктом.",
324
  "Начни сообщение с указания на пользу продукта. Используй глагол в побудительном наклонении.",
@@ -329,31 +681,21 @@ def generate_all_messages(desc, benefits, key_message, gender, generation, psych
329
  "Убедись, что готовый текст начинается с указания на пользу продукта и использования глагола в побудительном наклонении.",
330
  "Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента."
331
  ]
332
-
333
  non_personalized_messages = []
334
  personalized_messages = []
335
-
336
  flag = 1
337
-
338
- # Генерация и постепенная подача каждого сообщения
339
  for i in range(3):
340
-
341
- # Генерация задания для редактора
342
  personalization_prompt = generate_personalization_prompt(
343
  key_message, gender, generation, psychotype, business_stage, industry, opf,
344
  prefix=prefixes[i], suffix=suffixes[i]
345
  )
346
-
347
- # Удаляем префиксы, суффиксы и пустые строки перед выводом на экран
348
  display_personalization_prompt = clean_prompt_for_display(personalization_prompt, prefixes, suffixes)
349
-
350
  while flag == 1:
351
  yield standard_prompt, display_personalization_prompt, None, None, None, None, None, None
352
  flag += 1
353
-
354
- # Генерация неперсонализированного сообщения
355
  prompt = add_prefix_suffix(standard_prompt, prefixes[i], suffixes[i])
356
- non_personalized_message = generate_message_gigachat_pro_with_retry(prompt)
357
  non_personalized_length = len(non_personalized_message)
358
  non_personalized_display = f"{non_personalized_message}\n------\nКоличество знаков: {non_personalized_length}"
359
  non_personalized_messages.append(non_personalized_display)
@@ -371,7 +713,7 @@ def generate_all_messages(desc, benefits, key_message, gender, generation, psych
371
 
372
  # Генерация персонализированного сообщения
373
  full_personalized_prompt = f"{personalization_prompt}\n\nТекст для адаптации: {non_personalized_message}"
374
- personalized_message = generate_message_gigachat_pro_with_retry(full_personalized_prompt)
375
  personalized_length = len(personalized_message)
376
  personalized_display = f"{personalized_message}\n------\nКоличество знаков: {personalized_length}"
377
  personalized_messages.append(personalized_display)
@@ -386,9 +728,11 @@ def generate_all_messages(desc, benefits, key_message, gender, generation, psych
386
  non_personalized_messages[2] if len(non_personalized_messages) > 2 else None,
387
  personalized_messages[2] if len(personalized_messages) > 2 else None
388
  )
389
-
390
  time.sleep(1)
391
 
 
 
392
 
393
  # ФУНКЦИИ ПРОВЕРОК (НАЧАЛО)
394
 
@@ -401,9 +745,9 @@ def check_forbidden_words(message):
401
  forbidden_patterns = [
402
  r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b',
403
  r'вкусный', r'дешёвый', r'продукт',
404
- r'спам', r'доступный', r'банкротство', r'долг[и]?', r'займ',
405
- r'срочный', r'сейчас', r'главный',
406
- r'гарантия', r'успех', r'лидер'
407
  ]
408
 
409
  # Удаляем знаки препинания для корректного анализа
@@ -451,7 +795,7 @@ def check_no_greeting(message):
451
  def check_no_promises(message):
452
  morph = pymorphy2.MorphAnalyzer()
453
  promise_patterns = [
454
- "обещать", "гарантировать", "обязаться"
455
  ]
456
 
457
  words = message.split()
@@ -473,7 +817,11 @@ def check_no_double_verbs(message):
473
  for i in range(len(morphs) - 1):
474
  # Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы)
475
  if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}):
476
- return False
 
 
 
 
477
  return True
478
 
479
  # 6. Причастия и причастные обороты
@@ -481,10 +829,12 @@ def check_no_double_verbs(message):
481
  def check_no_participles(message):
482
  morph = pymorphy2.MorphAnalyzer()
483
  words = message.split()
484
- morphs = [morph.parse(word)[0] for word in words]
485
 
486
- for morph in morphs:
487
- if 'PRTF' in morph.tag:
 
 
488
  return False
489
  return True
490
 
@@ -591,7 +941,7 @@ def check_no_introductory_phrases(message):
591
 
592
  def check_no_amplifiers(message):
593
  amplifiers = [
594
- r'\b(очень|крайне|чрезвычайно|совсем|абсолютно|полностью|чисто)\b'
595
  ]
596
 
597
  for pattern in amplifiers:
@@ -603,7 +953,7 @@ def check_no_amplifiers(message):
603
 
604
  def check_no_time_parasites(message):
605
  time_parasites = [
606
- r'\b(сейчас|немедленно|срочно|в данный момент|теперь)\b'
607
  ]
608
 
609
  for pattern in time_parasites:
@@ -653,8 +1003,7 @@ def check_no_compound_sentences(message):
653
  r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b',
654
  r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b',
655
  r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b',
656
- r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b',
657
- r'\bчто\b'
658
  ]
659
 
660
  # Убедимся, что слово "как" используется не в вопросе
@@ -684,30 +1033,469 @@ def check_no_dates_written_out(message):
684
 
685
  return True
686
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
687
  # ФУНКЦИИ ПРОВЕРОК (КОНЕЦ)
688
 
689
- def perform_checks(message):
690
- checks = {
691
- "forbidden_words": check_forbidden_words(message),
692
- "client_addressing": check_no_greeting(message),
693
- "promises": check_no_promises(message),
694
- "double_verbs": check_no_double_verbs(message),
695
- "participles": check_no_participles(message),
696
- "adverbial_participles": check_no_adverbial_participles(message)
697
- # "superlative_adjectives": check_no_superlative_adjectives(message),
698
- # "passive_voice": check_no_passive_voice(message),
699
- # "written_out_ordinals": check_no_written_out_ordinals(message),
700
- # "subordinate_clauses_chain": check_no_subordinate_clauses_chain(message),
701
- # "repeating_conjunctions": check_no_repeating_conjunctions(message),
702
- # "introductory_phrases": check_no_introductory_phrases(message),
703
- # "amplifiers": check_no_amplifiers(message),
704
- # "time_parasites": check_no_time_parasites(message),
705
- # "multiple_nouns": check_no_multiple_nouns(message),
706
- # "derived_prepositions": check_no_derived_prepositions(message),
707
- # "compound_sentences": check_no_compound_sentences(message),
708
- # "dates_written_out": check_no_dates_written_out(message)
709
- }
710
- return checks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
 
712
 
713
  def format_checks(checks):
@@ -717,21 +1505,41 @@ def format_checks(checks):
717
  "promises": "Обещания и гарантии",
718
  "double_verbs": "Два глагола подряд",
719
  "participles": "Причастия",
720
- "adverbial_participles": "Деепричастия"
721
- # "superlative_adjectives": "Превосходная степень",
722
- # "passive_voice": "Страдательный залог",
723
- # "written_out_ordinals": "Порядковые числительные",
724
- # "subordinate_clauses_chain": "Цепочки с придаточными предложениями",
725
- # "repeating_conjunctions": "Разделительные повторяющиеся союзы",
726
- # "introductory_phrases": "Вводные конструкции",
727
- # "amplifiers": "Усилители",
728
- # "time_parasites": "Паразиты времени",
729
- # "multiple_nouns": "Несколько существительных подряд",
730
- # "derived_prepositions": "Производные предлоги",
731
- # "compound_sentences": "Сложноподчиненные предложения",
732
- # "dates_written_out": "Даты прописью"
 
 
 
 
 
 
 
 
 
 
 
733
  }
734
- return " \n".join([f"{translation[rule]}: {'✔️' if result else '❌'}" for rule, result in checks.items()])
 
 
 
 
 
 
 
 
 
735
 
736
 
737
  # Функция для обработки нажатия кнопки "Проверить"
 
10
  import random
11
  import pymorphy2
12
  import string
13
+ import json
14
+ from mistralai import Mistral
15
+ from collections import defaultdict
16
+ import requests
17
+ import base64
18
+ import io
19
+
20
+ #MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY')
21
+ token = os.getenv('GITHUB_TOKEN')
22
+
23
+ # Клиент для генерации сообщений
24
+ #client_mistral_generate = Mistral(api_key=MISTRAL_API_KEY)
25
+
26
+ # Клиент для выполнения проверок
27
+ #client_mistral_check = Mistral(api_key=MISTRAL_API_KEY)
28
 
29
  morph = pymorphy2.MorphAnalyzer()
30
 
31
  # Авторизация в GigaChat Pro
32
  gc_key = os.getenv('GC_KEY')
33
+ #chat_pro = GigaChat(credentials=gc_key, model='GigaChat', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
34
+ chat_pro = GigaChat(
35
+ credentials=gc_key,
36
+ model='GigaChat-Pro-preview',
37
+ base_url='https://gigachat-preview.devices.sberbank.ru/api/v1/',
38
+ max_tokens=68,
39
+ temperature=1.15,
40
+ verify_ssl_certs=False
41
+ )
42
+
43
+ chat_pro_check = GigaChat(
44
+ credentials=gc_key,
45
+ model='GigaChat-Pro-preview',
46
+ base_url='https://gigachat-preview.devices.sberbank.ru/api/v1/',
47
+ max_tokens=3000,
48
+ temperature=0.8,
49
+ verify_ssl_certs=False
50
+ )
51
+
52
+ approach_stats = {
53
+ "Начни сообщение с призыва к действию с продуктом.": {"failed_checks": defaultdict(int), "total_attempts": 0},
54
+ "Начни сообщение с указания на пользу продукта. Используй глагол в побудительном наклонении.": {"failed_checks": defaultdict(int), "total_attempts": 0},
55
+ "Начни сообщение с вопроса, который указывает на пользу продукта для клиента.": {"failed_checks": defaultdict(int), "total_attempts": 0}
56
+ }
57
 
58
  # Загрузка данных из Excel-файла
59
  try:
 
98
  fig.update_layout(paper_bgcolor="#f8f9fa", font={'color': "#2d3436", 'family': "Arial"}, width=250, height=150)
99
  return fig
100
 
101
+ def save_statistics_to_github(approach_stats):
102
+ repo = "fruitpicker01/Storage_dev"
103
+ timestamp = int(time.time())
104
+ json_path = f"check_{timestamp}.json"
105
+ csv_path = "checks.csv"
106
+ url_json = f"https://api.github.com/repos/{repo}/contents/{json_path}"
107
+ url_csv = f"https://api.github.com/repos/{repo}/contents/{csv_path}"
108
+ headers = {
109
+ "Authorization": f"token {token}",
110
+ "Content-Type": "application/json"
111
+ }
112
+
113
+ # Подготовка данных для JSON
114
+ json_data = {
115
+ "timestamp": timestamp,
116
+ "approach_stats": approach_stats
117
+ }
118
+ json_content = json.dumps(json_data, ensure_ascii=False, indent=4)
119
+ json_content_encoded = base64.b64encode(json_content.encode('utf-8')).decode('utf-8')
120
+ data_json = {
121
+ "message": f"Добавлен новый файл {json_path}",
122
+ "content": json_content_encoded
123
+ }
124
+ # Сохранение JSON-файла
125
+ response = requests.put(url_json, headers=headers, data=json.dumps(data_json))
126
+ if response.status_code in [200, 201]:
127
+ print("JSON-файл успешно сохранен на GitHub")
128
+ else:
129
+ print(f"Ошибка при сохранении JSON-файла: {response.status_code} {response.text}")
130
+
131
+ # Подготовка данных для CSV
132
+ import pandas as pd
133
+ rows = []
134
+ for approach, stats in approach_stats.items():
135
+ for check_name, count in stats["failed_checks"].items():
136
+ rows.append({
137
+ "Timestamp": timestamp,
138
+ "Approach": approach,
139
+ "Check": check_name,
140
+ "Failed_Count": count,
141
+ "Total_Attempts": stats["total_attempts"]
142
+ })
143
+ df = pd.DataFrame(rows)
144
+
145
+ # Проверяем, существует ли уже файл CSV
146
+ response = requests.get(url_csv, headers=headers)
147
+ if response.status_code == 200:
148
+ # Файл существует, загружаем и добавляем данные
149
+ content = response.json()
150
+ csv_content = base64.b64decode(content['content']).decode('utf-8')
151
+ existing_df = pd.read_csv(io.StringIO(csv_content))
152
+ df = pd.concat([existing_df, df], ignore_index=True)
153
+ sha = content['sha']
154
+ else:
155
+ # Файл не существует
156
+ sha = None
157
+
158
+ csv_content = df.to_csv(index=False)
159
+ csv_content_encoded = base64.b64encode(csv_content.encode('utf-8')).decode('utf-8')
160
+ data_csv = {
161
+ "message": "Обновление файла checks.csv",
162
+ "content": csv_content_encoded
163
+ }
164
+ if sha:
165
+ data_csv["sha"] = sha
166
+ # Сохранение CSV-файла
167
+ response = requests.put(url_csv, headers=headers, data=json.dumps(data_csv))
168
+ if response.status_code in [200, 201]:
169
+ print("CSV-файл успешно сохранен на GitHub")
170
+ else:
171
+ print(f"Ошибка при сохранении CSV-файла: {response.status_code} {response.text}")
172
+
173
  # Функция для генерации случайных значений спидометров
174
  def generate_random_gauges():
175
  return create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95))
 
200
  except Exception as e:
201
  return f"Ошибка при обращении к GigaChat-Pro: {e}"
202
 
203
+ #def generate_message_mistral_generate(prompt, max_retries=5):
204
+ # retries = 0
205
+ # while retries < max_retries:
206
+ # try:
207
+ # chat_response = client_mistral_generate.chat.complete(
208
+ # model="mistral-large-latest",
209
+ # messages=[
210
+ # {
211
+ # "role": "user",
212
+ # "content": prompt,
213
+ # "max_tokens": 68,
214
+ # "temperature": 0.8
215
+ # },
216
+ # ]
217
+ # )
218
+ # cleaned_message = clean_message(chat_response.choices[0].message.content.strip())
219
+ # return cleaned_message
220
+ # except Exception as e:
221
+ # if "Status 429" in str(e):
222
+ # wait_time = 3 # Можно установить фиксированную задержку
223
+ # print(f"Превышен лимит запросов. Ожидание {wait_time} секунд перед повторной попыткой...")
224
+ # time.sleep(wait_time)
225
+ # retries += 1
226
+ # else:
227
+ # print(f"Ошибка при обращении к Mistral: {e}")
228
+ # return None
229
+
230
+ #def generate_message_mistral_check(prompt, max_retries=5):
231
+ # retries = 0
232
+ # while retries < max_retries:
233
+ # try:
234
+ # chat_response = client_mistral_check.chat.complete(
235
+ # model="mistral-large-latest",
236
+ # messages=[
237
+ # {
238
+ # "role": "user",
239
+ # "content": prompt,
240
+ # "max_tokens": 3000,
241
+ # "temperature": 0.2
242
+ # },
243
+ # ]
244
+ # )
245
+ # cleaned_message = clean_message(chat_response.choices[0].message.content.strip())
246
+ # return cleaned_message
247
+ # except Exception as e:
248
+ # if "Status 429" in str(e):
249
+ # wait_time = 3 # Можно установить фиксированную задержку
250
+ # print(f"Превышен лимит запросов. Ожидание {wait_time} секунд перед повторной попыткой...")
251
+ # time.sleep(wait_time)
252
+ # retries += 1
253
+ # else:
254
+ # print(f"Ошибка при обращении к Mistral: {e}")
255
+ # return None
256
+
257
+ def generate_check_gigachat_pro(prompt):
258
+ try:
259
+ messages = [SystemMessage(content=prompt)]
260
+ res2 = chat_pro_check(messages)
261
+ cleaned_message = clean_message(res2.content.strip())
262
+ return cleaned_message
263
+ except Exception as e:
264
+ return f"Ошибка при обращении к GigaChat-Pro: {e}"
265
+
266
  # Функция для замены сокращений с 'k' или 'К' на тысячи
267
  def replace_k_with_thousands(message):
268
  # Замена и для 'k' и для 'К', с учётом регистра
269
  message = re.sub(r'(\d+)[kкКK]', r'\1 000', message, flags=re.IGNORECASE)
270
  return message
271
 
 
272
  def correct_dash_usage(text):
273
+ morph = pymorphy2.MorphAnalyzer()
274
  # Step 1: Replace any dash with long dash if surrounded by spaces
275
  text = re.sub(r'\s[-–—]\s', ' — ', text)
276
 
 
280
  # Step 3: Replace any dash with hyphen if surrounded by letters or a combination of letters and digits
281
  text = re.sub(r'(?<=[a-zA-Zа-яА-Я0-9])[-–—](?=[a-zA-Zа-яА-Я0-9])', '-', text)
282
 
283
+ # Step 4: Replace quotation marks "..." with «...»
284
+ text = re.sub(r'"([^\"]+)"', r'«\1»', text)
285
+
286
+ # Step 5: Remove single quotes
287
+ if text.count('"') == 1:
288
+ text = text.replace('"', '')
289
+
290
+ # Step 6: Remove outer quotes if the entire text is enclosed in quotes (straight or elided)
291
+ if (text.startswith('"') and text.endswith('"')) or (text.startswith('«') and text.endswith('»')):
292
+ text = text[1:-1].strip()
293
+
294
+ # Step 7: Replace 100k with 100 000
295
+ text = re.sub(r'(\d+)[kкКK]', r'\1 000', text, flags=re.IGNORECASE)
296
+
297
+ # Step 8: Remove first sentence if it contains greetings and is less than 5 words
298
+ greeting_patterns = [
299
+ r"привет\b", r"здравствуй", r"добрый\s(день|вечер|утро)",
300
+ r"дорогой\b", r"уважаемый\b", r"дорогая\b", r"уважаемая\b",
301
+ r"господин\b", r"госпожа\b", r"друг\b", r"коллега\b",
302
+ r"товарищ\b", r"приятель\b", r"подруга\b"
303
+ ]
304
+
305
+ def is_greeting_sentence(sentence):
306
+ words = sentence.split()
307
+ if len(words) < 5: # Check if sentence is less than 5 words
308
+ for word in words:
309
+ parsed = morph.parse(word.lower())[0] # Parse the word to get its base form
310
+ for pattern in greeting_patterns:
311
+ if re.search(pattern, parsed.normal_form):
312
+ return True
313
+ return False
314
+
315
+ # Split text into sentences
316
+ sentences = re.split(r'(?<=[.!?])\s+', text)
317
+
318
+ # Check the first sentence for greetings and remove it if necessary
319
+ if sentences and is_greeting_sentence(sentences[0]):
320
+ sentences = sentences[1:]
321
+
322
+ # Join the sentences back
323
+ text = ' '.join(sentences)
324
+
325
+ def restore_yo(text):
326
+ morph = pymorphy2.MorphAnalyzer()
327
+ words = text.split()
328
+ restored_words = []
329
+
330
+ for word in words:
331
+ # Пропускать обработку, если слово полностью в верхнем регистре (аббревиатуры)
332
+ if word.isupper():
333
+ restored_words.append(word)
334
+ continue
335
+
336
+ # Пропускать обработку, если слово "все" (независимо от регистра)
337
+ if word.lower() == "все":
338
+ restored_words.append(word)
339
+ continue
340
+
341
+ # Обработка остальных слов
342
+ parsed = morph.parse(word)[0]
343
+ restored_word = parsed.word
344
+
345
+ # Сохраняем оригинальный регистр первой буквы
346
+ if word and word[0].isupper():
347
+ restored_word = restored_word.capitalize()
348
+
349
+ restored_words.append(restored_word)
350
+
351
+ return ' '.join(restored_words)
352
+
353
+ text = restore_yo(text)
354
+
355
+ # Step 9: Replace common abbreviations and acronyms (Ип -> ИП, Ооо -> ООО, Рф -> РФ)
356
+ text = re.sub(r'\bИп\b', 'ИП', text, flags=re.IGNORECASE)
357
+ text = re.sub(r'\bОоо\b', 'ООО', text, flags=re.IGNORECASE)
358
+ text = re.sub(r'\bРф\b', 'РФ', text, flags=re.IGNORECASE)
359
+
360
+ # Step 10: Replace specific words (пользуйтесь -> пользуйтесь, ею -> ей)
361
+ text = re.sub(r'\bпользовуйтесь\b', 'пользуйтесь', text, flags=re.IGNORECASE)
362
+ text = re.sub(r'\bею\b', 'ей', text, flags=re.IGNORECASE)
363
+ text = re.sub(r'\bповышьте\b', 'повысьте', text, flags=re.IGNORECASE)
364
+
365
+ text = re.sub(r'\bСбербизнес\b', 'СберБизнес', text, flags=re.IGNORECASE)
366
+ text = re.sub(r'\bСбербанк\b', 'СберБанк', text, flags=re.IGNORECASE)
367
+ text = re.sub(r'\bвашего ООО\b', 'вашей компании', text, flags=re.IGNORECASE)
368
+
369
+ # Step 11: Replace all forms of "рублей", "рубля", "руб." with "р"
370
+ # Используем два отдельных регулярных выражения для точности
371
+ # 1. Заменяем "руб." на "р", учитывая, что "руб." может быть перед символом "/" или другим несловесным символом
372
+ text = re.sub(r'\bруб\.(?=\W|$)', 'р', text, flags=re.IGNORECASE)
373
+ # 2. Заменяем "рубля" и "рублей" на "р"
374
+ text = re.sub(r'\bруб(?:ля|лей)\b', 'р', text, flags=re.IGNORECASE)
375
+
376
+ # Step 12: Replace thousands and millions with appropriate abbreviations
377
+ text = re.sub(r'(\d+)\s+тысяч(?:а|и)?(?:\s+рублей)?', r'\1 000 р', text, flags=re.IGNORECASE)
378
+ text = re.sub(r'(\d+)\s*тыс\.\s*руб\.', r'\1 000 р', text, flags=re.IGNORECASE)
379
+ text = re.sub(r'(\d+)\s*тыс\.\s*р\.', r'\1 000 р', text, flags=re.IGNORECASE)
380
+
381
+ # Replace millions with "млн"
382
+ text = re.sub(r'(\d+)\s+миллиона\b|\bмиллионов\b', r'\1 млн', text, flags=re.IGNORECASE)
383
+ text = re.sub(r'(\d+)\s*млн\s*руб\.', r'\1 млн р', text, flags=re.IGNORECASE)
384
+
385
+ # Ensure space formatting around currency abbreviations
386
+ text = re.sub(r'(\d+)\s*р\b', r'\1 р', text)
387
+
388
+ # Step 13: Remove sentences containing "никаких посещений" or "никаких визитов"
389
+ def remove_specific_sentences(text):
390
+ sentences = re.split(r'(?<=[.!?])\s+', text) # Разбиваем текст на предложения
391
+ filtered_sentences = [
392
+ sentence for sentence in sentences
393
+ if not re.search(r'\bникаких\s+(посещений|визитов)\b', sentence, flags=re.IGNORECASE)
394
+ ]
395
+ return ' '.join(filtered_sentences)
396
+
397
+ # Шаг 14: Замена чисел вида "5 000 000 р" на "5 млн р"
398
+ text = re.sub(r'\b(\d+)\s+000\s+000\s*р\b', r'\1 млн р', text, flags=re.IGNORECASE)
399
+
400
+ text = remove_specific_sentences(text)
401
+
402
  return text
403
 
404
+
405
  # Функция для добавления ошибок в промпт для перегенерации
406
  def append_errors_to_prompt(prompt, checks):
407
+ # Словарь с сообщениями об ошибках для каждого правила
408
+ error_messages = {
409
+ "forbidden_words": "Не использовать запрещённые слова: номер один, №1, № 1, номер, вкусный, дешёвый, продукт, спам, банкротство, долг, займ, срочный, главный, гарантия, успех, лидер.",
410
+ "client_addressing": "Не обращаться к клиенту напрямую.",
411
+ "promises": "Не давать обещания и гарантии.",
412
+ "double_verbs": "Не использовать два глагола подряд (например, 'хочешь оформить').",
413
+ "participles": "Не использовать причастия.",
414
+ "adverbial_participles": "Не использовать деепричастия.",
415
+ "superlative_adjectives": "Не использовать превосходную степень прилагательных.",
416
+ "passive_voice": "Избегать страдательного залога.",
417
+ "written_out_ordinals": "Не использовать порядковые числительные от 10 прописью.",
418
+ "subordinate_clauses_chain": "Избегать цепочек с придаточными предложениями.",
419
+ "repeating_conjunctions": "Не использовать разделительные повторяющиеся союзы.",
420
+ "introductory_phrases": "Не использовать вводные конструкции.",
421
+ "amplifiers": "Не использовать усилители.",
422
+ "time_parasites": "Не использовать 'паразиты времени'.",
423
+ "multiple_nouns": "Избегать нескольких существительных подряд.",
424
+ "derived_prepositions": "Не использовать производные предлоги.",
425
+ "compound_sentences": "Избегать сложноподчиненных предложений.",
426
+ "dates_written_out": "Не писать даты прописью.",
427
+ "no_word_repetitions": "Избегать повторов слов.",
428
+ "disconnected_sentences": "Избегать сложных предложений без логической связи.",
429
+ "synonymous_members": "Не использовать близкие по смыслу однородные члены предложения.",
430
+ "clickbait_phrases": "Не использовать кликбейтные фразы.",
431
+ "abstract_claims": "Избегать абстрактных заявлений без доказательств.",
432
+ "specialized_terms": "Не использовать узкоспециализированные термины.",
433
+ "offensive_phrases": "Избегать двусмысленных или оскорбительных фраз.",
434
+ "cliches_and_bureaucratese": "Не использовать речевые клише, рекламные штампы, канцеляризмы.",
435
+ "no_contradictions": "Избегать противоречий с описанием предложения.",
436
+ "contains_key_message": "Обязательно включить ключевое сообщение."
437
+ }
438
+
439
+ # Находим первую не пройденную проверку
440
+ for check_name, passed in checks.items():
441
+ if passed is False:
442
+ error_message = error_messages.get(check_name, f"Ошибка в проверке {check_name}.")
443
+ error_instruction = "Следующую ошибку необходимо избежать:\n" + error_message
444
+ prompt += f"\n\n{error_instruction}"
445
+ break # Останавливаемся на первой ошибке
446
+
447
  return prompt
448
+
449
 
450
  def notify_failed_length(message_length):
451
+ if message_length < 120:
452
+ gr.Warning(f"Сообщение слишком короткое: {message_length} знаков. Минимум 120.")
453
  return False
454
  elif message_length > 250:
455
  gr.Warning(f"Сообщение слишком длинное: {message_length} знаков. Максимум 250.")
 
458
 
459
  # Функция для уведомления о непройденных проверках
460
  def notify_failed_checks(checks):
 
461
  translation = {
462
  "forbidden_words": "Запрещенные слова",
463
  "client_addressing": "Обращение к клиенту",
464
  "promises": "Обещания и гарантии",
465
  "double_verbs": "Два глагола подряд",
466
  "participles": "Причастия",
467
+ "adverbial_participles": "Деепричастия",
468
+ "superlative_adjectives": "Превосходная степень",
469
+ "passive_voice": "Страдательный залог",
470
+ "written_out_ordinals": "Порядковые числительные",
471
+ "subordinate_clauses_chain": "Цепочки с придаточными предложениями",
472
+ "repeating_conjunctions": "Разделительные повторяющиеся союзы",
473
+ "introductory_phrases": "Вводные конструкции",
474
+ "amplifiers": "Усилители",
475
+ "time_parasites": "Паразиты времени",
476
+ "multiple_nouns": "Несколько существительных подряд",
477
+ "derived_prepositions": "Производные предлоги",
478
+ "compound_sentences": "Сложноподчиненные предложения",
479
+ "dates_written_out": "Даты прописью",
480
+ "no_word_repetitions": "Повторы слов",
481
+ "disconnected_sentences": "Сложные предложения без логической связи",
482
+ "synonymous_members": "Близкие по смыслу однородные члены предложения",
483
+ "clickbait_phrases": "Кликбейтные фразы",
484
+ "abstract_claims": "Абстрактные заявления без доказательств",
485
+ "specialized_terms": "Узкоспециализированные термины",
486
+ "offensive_phrases": "Двусмысленные или оскорбительные фразы",
487
+ "cliches_and_bureaucratese": "Речевые клише, рекламные штампы, канцеляризмы",
488
+ "no_contradictions": "Противоречия с описанием предложения",
489
+ "contains_key_message": "Отсутствие ключевого сообщения"
490
  }
491
 
492
+ # Находим первую не пройденную проверку
493
+ for check_name, passed in checks.items():
494
+ if passed is False:
495
+ failed_check = translation.get(check_name, check_name)
496
+ gr.Warning(f"Сообщение не прошло следующую проверку: {failed_check}")
497
+ break # Останавливаемся на первой ошибке
498
+ else:
499
+ # Если все проверки пройдены, выводим уведомление
500
+ gr.Warning("ВСЕ ПРОВЕРКИ ПРОЙДЕНЫ")
501
 
502
  # Модифицированная функция перегенерации сообщений с уведомлениями о номере попытки
503
+ def generate_message_gigachat_pro_with_retry(prompt, current_prefix, description, key_message):
504
+ global approach_stats
505
+ last_message = None
506
+ for attempt in range(30):
 
507
  gr.Info(f"Итерация {attempt + 1}: генерируется сообщение...")
 
 
508
  message = generate_message_gigachat_pro(prompt)
509
  message = replace_k_with_thousands(message)
510
  message = correct_dash_usage(message)
511
  message_length = len(message)
 
 
512
  if not notify_failed_length(message_length):
513
+ last_message = message
514
+ time.sleep(1)
515
  continue
516
+ checks = perform_checks(message, description, key_message)
 
 
 
 
517
  last_message = message
518
+ approach_stats[current_prefix]["total_attempts"] += 1
519
+ for check_name, passed in checks.items():
520
+ if passed is False:
521
+ approach_stats[current_prefix]["failed_checks"][check_name] += 1
522
+ break
523
+ notify_failed_checks(checks) # Вызываем функцию независимо от результата проверок
524
  if all(checks.values()):
525
  return message
 
 
 
 
 
526
  prompt = append_errors_to_prompt(prompt, checks)
527
+ time.sleep(1)
 
 
 
528
  gr.Info("Не удалось сгенерировать сообщение, соответствующее требованиям, за 20 итераций. Возвращаем последнее сгенерированное сообщение.")
529
  return last_message
530
 
531
 
532
+ #def generate_message_mistral_with_retry(prompt, current_prefix, description, key_message):
533
+ # global approach_stats
534
+ # last_message = None
535
+ # for attempt in range(20):
536
+ # gr.Info(f"Итерация {attempt + 1}: генерируется сообщение...")
537
+ # message = generate_message_mistral_generate(prompt)
538
+ # message = replace_k_with_thousands(message)
539
+ # message = correct_dash_usage(message)
540
+ # message_length = len(message)
541
+ # if not notify_failed_length(message_length):
542
+ # last_message = message
543
+ # time.sleep(1)
544
+ # continue
545
+ # checks = perform_checks(message, description, key_message)
546
+ # last_message = message
547
+ # approach_stats[current_prefix]["total_attempts"] += 1
548
+ # for check_name, passed in checks.items():
549
+ # if passed is False:
550
+ # approach_stats[current_prefix]["failed_checks"][check_name] += 1
551
+ # break
552
+ # notify_failed_checks(checks) # Вызываем функцию независимо от результата проверок
553
+ # if all(checks.values()):
554
+ # return message
555
+ # prompt = append_errors_to_prompt(prompt, checks)
556
+ # time.sleep(1)
557
+ # gr.Info("Не удалось сгенерировать сообщение, соответствующее требованиям, за 20 итераций. Возвращаем последнее сгенерированное сообщение.")
558
+ # return last_message
559
+
560
+
561
  # Функция для создания задания для копирайтера
562
  def generate_standard_prompt(description, advantages, key_message, *selected_values):
563
  prompt = (
 
565
  f"Описание предложения: {description}\n"
566
  f"Преимущества: {advantages}\n"
567
  "В тексте смс запрещено использование:\n"
568
+ "- Запрещенные слова: № один, н��мер один, № 1, вкусный, дешёвый, продукт, спам, доступный, банкротство, долги, займ, срочно, сейчас, лучший, главный, номер 1, гарантия, успех, лидер, никакой;\n"
569
  "- Обращение к клиенту;\n"
570
  "- Приветствие клиента;\n"
571
  "- Обещания и гарантии;\n"
 
592
  "- Узкоспециализированные термины;\n"
593
  "- Фразы, способные создать двойственное ощущение, обидеть;\n"
594
  "- Речевые клише, рекламные штампы, канцеляризмы;\n"
595
+ "Убедись, что в готовом тексте до 250, но не менее 120 знаков с пробелами.\n"
596
  )
597
  if key_message.strip():
598
  prompt += f"Убедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
 
602
 
603
  # Функция для создания задания для редактора с добавлением prefix и suffix
604
  def generate_personalization_prompt(key_message, *selected_values, prefix, suffix):
605
+ prompt = "Адаптируй, не превышая длину сообщения в 250 знаков с пробелами (но и не менее 120 знаков с пробелами), текст с учетом следующих особенностей:\n"
606
  gender, generation, psychotype = selected_values[0], selected_values[1], selected_values[2]
607
  combined_instruction = ""
608
  additional_instructions = ""
 
645
 
646
  # Добавляем префикс и суффикс для задания редактора
647
  prompt = f"{prefix}\n{prompt}\n{suffix}"
648
+ prompt += "Убедись, что в готовом тексте не изменено название предлагаемого продукта.\n"
649
+
650
  # Добавляем ключевое сообщение
651
  prompt += f"\nУбедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
652
 
 
669
 
670
  # Функция для постепенной генерации всех сообщений через yield
671
  def generate_all_messages(desc, benefits, key_message, gender, generation, psychotype, business_stage, industry, opf):
 
672
  standard_prompt = generate_standard_prompt(desc, benefits, key_message)
673
  yield standard_prompt, None, None, None, None, None, None, None
 
 
674
  prefixes = [
675
  "Начни сообщение с призыва к действию с продуктом.",
676
  "Начни сообщение с указания на пользу продукта. Используй глагол в побудительном наклонении.",
 
681
  "Убедись, что готовый текст начинается с указания на пользу продукта и использования глагола в побудительном наклонении.",
682
  "Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента."
683
  ]
 
684
  non_personalized_messages = []
685
  personalized_messages = []
 
686
  flag = 1
 
 
687
  for i in range(3):
688
+ current_prefix = prefixes[i]
 
689
  personalization_prompt = generate_personalization_prompt(
690
  key_message, gender, generation, psychotype, business_stage, industry, opf,
691
  prefix=prefixes[i], suffix=suffixes[i]
692
  )
 
 
693
  display_personalization_prompt = clean_prompt_for_display(personalization_prompt, prefixes, suffixes)
 
694
  while flag == 1:
695
  yield standard_prompt, display_personalization_prompt, None, None, None, None, None, None
696
  flag += 1
 
 
697
  prompt = add_prefix_suffix(standard_prompt, prefixes[i], suffixes[i])
698
+ non_personalized_message = generate_message_gigachat_pro_with_retry(prompt, current_prefix, desc, key_message)
699
  non_personalized_length = len(non_personalized_message)
700
  non_personalized_display = f"{non_personalized_message}\n------\nКоличество знаков: {non_personalized_length}"
701
  non_personalized_messages.append(non_personalized_display)
 
713
 
714
  # Генерация персонализированного сообщения
715
  full_personalized_prompt = f"{personalization_prompt}\n\nТекст для адаптации: {non_personalized_message}"
716
+ personalized_message = generate_message_gigachat_pro_with_retry(full_personalized_prompt, current_prefix, desc, key_message)
717
  personalized_length = len(personalized_message)
718
  personalized_display = f"{personalized_message}\n------\nКоличество знаков: {personalized_length}"
719
  personalized_messages.append(personalized_display)
 
728
  non_personalized_messages[2] if len(non_personalized_messages) > 2 else None,
729
  personalized_messages[2] if len(personalized_messages) > 2 else None
730
  )
731
+
732
  time.sleep(1)
733
 
734
+ save_statistics_to_github(approach_stats)
735
+
736
 
737
  # ФУНКЦИИ ПРОВЕРОК (НАЧАЛО)
738
 
 
745
  forbidden_patterns = [
746
  r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b',
747
  r'вкусный', r'дешёвый', r'продукт',
748
+ r'спам', r'банкротство', r'долг[и]?', r'займ',
749
+ r'срочный', r'главный',
750
+ r'гарантия', r'успех', r'лидер', 'никакой'
751
  ]
752
 
753
  # Удаляем знаки препинания для корректного анализа
 
795
  def check_no_promises(message):
796
  morph = pymorphy2.MorphAnalyzer()
797
  promise_patterns = [
798
+ "обещать", "обещание", "гарантировать", "обязаться", "обязать", "обязательство", "обязательный"
799
  ]
800
 
801
  words = message.split()
 
817
  for i in range(len(morphs) - 1):
818
  # Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы)
819
  if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}):
820
+ # Проверяем, является ли первый глагол "хотеть" или "начинать"
821
+ if morphs[i].normal_form in ['хотеть', 'начинать', 'начать']:
822
+ return True
823
+ else:
824
+ return False
825
  return True
826
 
827
  # 6. Причастия и причастные обороты
 
829
  def check_no_participles(message):
830
  morph = pymorphy2.MorphAnalyzer()
831
  words = message.split()
832
+ exceptions = {"повышенный", "увеличенный", "пониженный", "сниженный"}
833
 
834
+ for word in words:
835
+ parsed_word = morph.parse(word)[0]
836
+ lemma = parsed_word.normal_form
837
+ if 'PRTF' in parsed_word.tag and lemma not in exceptions:
838
  return False
839
  return True
840
 
 
941
 
942
  def check_no_amplifiers(message):
943
  amplifiers = [
944
+ r'\b(очень|крайне|чрезвычайно|совсем|полностью|чисто)\b'
945
  ]
946
 
947
  for pattern in amplifiers:
 
953
 
954
  def check_no_time_parasites(message):
955
  time_parasites = [
956
+ r'\b(немедленно|срочно|в данный момент)\b'
957
  ]
958
 
959
  for pattern in time_parasites:
 
1003
  r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b',
1004
  r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b',
1005
  r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b',
1006
+ r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b'
 
1007
  ]
1008
 
1009
  # Убедимся, что слово "как" используется не в вопросе
 
1033
 
1034
  return True
1035
 
1036
+ # Доп правило. Повторы слов
1037
+
1038
+ def check_no_word_repetitions(message):
1039
+ morph = pymorphy2.MorphAnalyzer()
1040
+
1041
+ # Список союзов и предлогов, которые мы будем игнорировать
1042
+ ignore_words = set([
1043
+ 'и', 'а', 'но', 'или', 'да', 'ни', 'как', 'так',
1044
+ 'в', 'на', 'под', 'над', 'за', 'к', 'до', 'по', 'из', 'у', 'о', 'про', 'для',
1045
+ 'не', 'вот', 'это', 'тот', 'тем', 'при', 'чем',
1046
+ 'же', 'ли', 'бы', 'то',
1047
+ ])
1048
+
1049
+ # Разбиваем текст на слова, удаляя знаки препинания
1050
+ words = re.findall(r'\b\w+\b', message.lower())
1051
+
1052
+ # Словарь для хранения нормализованных форм слов
1053
+ normalized_words = {}
1054
+
1055
+ for word in words:
1056
+ if word not in ignore_words:
1057
+ # Получаем нормальную форму слова
1058
+ normal_form = morph.parse(word)[0].normal_form
1059
+
1060
+ # Если слово уже встречалось, возвращаем False
1061
+ if normal_form in normalized_words:
1062
+ return False
1063
+
1064
+ # Добавляем слово в словарь
1065
+ normalized_words[normal_form] = True
1066
+
1067
+ # Если мы дошли до этой точки, повторов не было
1068
+ return True
1069
+
1070
+ # Проверки на LLM
1071
+
1072
+ import re
1073
+ import json
1074
+
1075
+ def parse_json_response(response):
1076
+ try:
1077
+ # Попытка найти JSON-подобную структуру в ответе
1078
+ match = re.search(r'\{.*', response)
1079
+ if match:
1080
+ json_str = match.group(0)
1081
+ # Проверяем и добавляем недостающие кавычки и скобки
1082
+ if json_str.count('"') % 2 != 0:
1083
+ json_str += '"'
1084
+ if json_str.count('{') > json_str.count('}'):
1085
+ json_str += '}'
1086
+ result = json.loads(json_str)
1087
+ return result
1088
+
1089
+ # Если JSON не найден, пытаемся найти ключ-значение вручную
1090
+ else:
1091
+ decision_match = re.search(r'decision:\s*(true|false)', response)
1092
+ explanation_match = re.search(r'explanation:\s*"(.+?)"', response)
1093
+
1094
+ result = {}
1095
+ if decision_match:
1096
+ decision_value = decision_match.group(1)
1097
+ result['decision'] = True if decision_value == 'true' else False
1098
+
1099
+ if explanation_match:
1100
+ result['explanation'] = explanation_match.group(1)
1101
+
1102
+ if result:
1103
+ return result
1104
+ else:
1105
+ print("JSON не найден, и ключи 'decision' и 'explanation' не извлечены")
1106
+ return None
1107
+ except Exception as e:
1108
+ print(f"Ошибка при разборе JSON: {e}")
1109
+ return None
1110
+
1111
+
1112
+ def cut_message(message):
1113
+ # Удаляем любой дополнительный текст, например, "------\nКоличество знаков: ..."
1114
+ # Разделяем сообщение по '------' и берем первую часть
1115
+ if '------' in message:
1116
+ message = message.split('------')[0].strip()
1117
+ return message
1118
+
1119
+ # 22. Проверка сложных предложений без логической связи
1120
+ def check_disconnected_sentences(message):
1121
+ message_clean = cut_message(message)
1122
+ print()
1123
+ print()
1124
+ print("СООБЩЕНИЕ:", message_clean)
1125
+ print()
1126
+ print("Проверка 22: Проверка сложных предложений без логической связи")
1127
+ print()
1128
+ prompt = f'''Проверь следующий текст на наличие сложных предложений, где отсутствует логическая связь между частями:
1129
+ "{message_clean}"
1130
+ Определи, есть ли в тексте предложения с несколькими частями, которые кажутся несвязанными, не поддерживают общую мысль или делают текст трудным для понимания.
1131
+ Обрати внимание, что в контексте коротких рекламных сообщений допустимы краткие предложения, перечисления и фразы, которые вместе передают связную информацию о продукте или услуге. Не считай такие сообщения несвязанными, если их части логически связаны с предложением продукта или условиями его получения.
1132
+ Пример ответа:
1133
+ {{"decision": false, "explanation": "Текст понятен, и все предложения логически связаны между собой."}}
1134
+ Если в тексте **есть** сложные предложения без логической связи между частями, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1135
+ если таких предложений **нет**, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1136
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь **только** в формате JSON с закрывающими кавычками и скобками.**'''
1137
+
1138
+ response = generate_check_gigachat_pro(prompt)
1139
+ time.sleep(3) # Задержка в 3 секунды между запросами
1140
+ print("GigaChat Pro response:", response) # Выводим полный ответ модели
1141
+ result = parse_json_response(response)
1142
+ if result is not None:
1143
+ decision = result.get("decision", False)
1144
+ explanation = result.get("explanation", "")
1145
+ print("Explanation:", explanation)
1146
+ return not decision # Инвертируем логику
1147
+ else:
1148
+ return None
1149
+
1150
+ # 23. Проверка на близкие по смыслу однородные члены
1151
+ def check_synonymous_members(message):
1152
+ print()
1153
+ print("Проверка 23: Проверка на близкие по смыслу однородные члены")
1154
+ print()
1155
+ message_clean = cut_message(message)
1156
+ prompt = f'''Проверь следующий текст на наличие однородных членов предложения, которые имеют одинаковый или практически одинаковый смысл и повторяют одну и ту же идею:
1157
+ "{message_clean}"
1158
+ Обрати внимание, что слова или выражения могут описывать разные аспекты продукта или услуги, и это не считается избыточным, если они не полностью дублируют значение друг друга. Например, такие слова как "премиальная" и "бизнес" могут описывать разные качества и не должны считаться синонимами.
1159
+ Пример ответа:
1160
+ {{"decision": true, "explanation": "В предложении используются синонимы 'быстрый' и 'скорый', которые повторяют одну и ту же идею."}}
1161
+ Если такие слова или выражения есть, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1162
+ если таких слов или выражений нет, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1163
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1164
+
1165
+ response = generate_check_gigachat_pro(prompt)
1166
+ time.sleep(3)
1167
+ print("GigaChat Pro response:", response)
1168
+ result = parse_json_response(response)
1169
+ if result is not None:
1170
+ decision = result.get("decision", False)
1171
+ explanation = result.get("explanation", "")
1172
+ print("Explanation:", explanation)
1173
+ return not decision # Инвертируем логику
1174
+ else:
1175
+ return None
1176
+
1177
+
1178
+ # 24. Проверка на шокиру��щие, экстравагантные или кликбейтные фразы
1179
+ def check_clickbait_phrases(message):
1180
+ message_clean = cut_message(message)
1181
+ print()
1182
+ print("Проверка 24: Проверка на шокирующие, экстравагантные или кликбейтные фразы")
1183
+ print()
1184
+ prompt = f'''Проверь следующий текст на наличие шокирующих, экстравагантных или кликбейтных фраз:
1185
+ "{message_clean}"
1186
+ Инструкции:
1187
+ 1. Игнорируй фразы, которые основаны на фактической информации, даже если они выглядят сенсационно, такие как "лимит до миллиона" или "льготный период до 365 дней". Если эти данные подтверждаются и не являются преувеличением, их не следует считать кликбейтом.
1188
+ 2. Ищи фразы, которые явно преувеличивают или вводят в заблуждение, обещая нечто чрезмерно идеализированное или сенсационное, что не может быть доказано или подтверждено. Примеры кликбейтных фраз: "Шокирующая правда", "Вы не поверите, что произошло", "Это изменит вашу жизнь за один день".
1189
+ 3. Стандартные рекламные призывы к действию, такие как "купите сейчас" или "узнайте больше", не считаются кликбейтом, если они не преувеличивают преимущества или не используют явную манипуляцию эмоциями.
1190
+ Пример ответа:
1191
+ {{"decision": false, "explanation": "Текст нейтрален и не содержит кликбейтных фраз."}}
1192
+
1193
+ Если текст содержит кликбейтные фразы, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1194
+ если таких фраз нет, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1195
+
1196
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1197
+
1198
+ response = generate_check_gigachat_pro(prompt)
1199
+ time.sleep(3)
1200
+ print("GigaChat Pro response:", response)
1201
+ result = parse_json_response(response)
1202
+ if result is not None:
1203
+ decision = result.get("decision", False)
1204
+ explanation = result.get("explanation", "")
1205
+ print("Explanation:", explanation)
1206
+ return not decision # Инвертируем логику
1207
+ else:
1208
+ return None
1209
+
1210
+
1211
+ # 25. Проверка на абстрактные заявления без поддержки фактами
1212
+ def check_abstract_claims(message):
1213
+ print()
1214
+ print("Проверка 25: Проверка на абстрактные заявления без поддержки фактами")
1215
+ print()
1216
+ message_clean = cut_message(message)
1217
+ prompt = f'''Проверь следующий текст на наличие чрезмерно абстрактных или неподкрепленных фактическими данными утверждений, которые могут усложнить понимание преимуществ продукта или услуги:
1218
+ "{message_clean}"
1219
+
1220
+ Инструкции:
1221
+ 1. Исключи фразы, которые содержат конкретные числовые данные, обещания о времени выполнения или другие факты, которые могут быть проверены (например, "от 1 минуты", "24/7", "в течение 24 часов").
1222
+ 2. Не считай абстрактными фразами выражения, которые описывают конкретные выгодные условия, если они сопровождаются фактами или цифрами (например, "выгодные условия при покупке от 100 000 рублей" или "индивидуальные условия с процентной ставкой 3%").
1223
+ 3. Помечай абстрактными фразами любые утверждения, которые звучат эмоционально, но не сопровождаются конкретикой, такие как:
1224
+ - "выгодное финансирование"
1225
+ - "развивайте свой бизнес быстрее"
1226
+ - "повышение эффективнос��и"
1227
+ - "эффективное управление"
1228
+ - "надёжное решение"
1229
+ - "оптимизируйте управление финансами"
1230
+ - "выгодные условия для бизнеса"
1231
+ - "лёгкие условия и кэшбэк"
1232
+ - "мобильно, удобно, комфортно".
1233
+ 4. Ищи общие фразы, которые не дают представления о конкретной пользе, такие как "лучшее решение", "высокое качество", "отличный сервис", если они не сопровождаются пояснением о том, почему это так.
1234
+ 5. Учитывай, что в рекламных сообщениях допустимы эмоциональные и обобщённые фразы, если они достаточно конкретны для понимания аудитории, однако они должны сопровождаться фактами или подробными примерами.
1235
+
1236
+ Пример ответа:
1237
+ {{"decision": false, "explanation": "Текст не содержит абстрактные утверждения без конкретики."}}
1238
+
1239
+ Если в тексте присутствуют абстрактные или неподкрепленные заявления, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1240
+ если таких утверждений нет, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1241
+
1242
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1243
+
1244
+ response = generate_check_gigachat_pro(prompt)
1245
+ time.sleep(3)
1246
+ print("GigaChat Pro response:", response)
1247
+ result = parse_json_response(response)
1248
+ if result is not None:
1249
+ decision = result.get("decision", False)
1250
+ explanation = result.get("explanation", "")
1251
+ print("Explanation:", explanation)
1252
+ return not decision # Инвертируем логическое значение
1253
+ else:
1254
+ return None
1255
+
1256
+
1257
+ # 26. Проверка на узкоспециализированные термины
1258
+ def check_specialized_terms(message):
1259
+ print()
1260
+ print("Проверка 26: Проверка на узкоспециализированные термины")
1261
+ print()
1262
+ message_clean = cut_message(message)
1263
+ prompt = f'''Проверь следующий текст на наличие узкоспециализированных терминов или жаргона, которые могут быть непонятны широкой аудитории:
1264
+ "{message_clean}"
1265
+
1266
+ Инструкции:
1267
+ 1. Игнорируй общеупотребительные термины, известные широкой аудитории, такие как "ИП", "ООО", "РФ", а также термины, связанные с обычными финансовыми продуктами (например, "кредитная карта", "интернет-банк", "Mastercard").
1268
+ 2. Ищи термины, характерные для узких профессиональных областей, таких как медицина, ИТ, право, инженерия и другие специализированные сферы.
1269
+ 3. Пример специализированных терминов: "интероперабельность", "кибернетика", "гипертензия", "аутентификация" и т.п.
1270
+
1271
+ Определи, содержит ли текст термины, которые известны только специалистам в определенной области и могут вызвать затруднения у обычных читателей.
1272
+
1273
+ Пример ответа:
1274
+ {{"decision": false, "explanation": "В тексте отсутствуют узкоспециализированные термины."}}
1275
+
1276
+ Если в тексте есть такие узкоспециализированные термины, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1277
+ если таких терминов нет, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1278
+
1279
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1280
+
1281
+ response = generate_check_gigachat_pro(prompt)
1282
+ time.sleep(3)
1283
+ print("GigaChat Pro response:", response)
1284
+ result = parse_json_response(response)
1285
+ if result is not None:
1286
+ decision = result.get("decision", False)
1287
+ explanation = result.get("explanation", "")
1288
+ print("Explanation:", explanation)
1289
+ return not decision # Инвертируем логическое значение
1290
+ else:
1291
+ return None
1292
+
1293
+ # 27. Проверка на двусмысленные или обидные фразы
1294
+ def check_offensive_phrases(message):
1295
+ print()
1296
+ print("Проверка 27: Проверка на двусмысленные или обидные фразы")
1297
+ print()
1298
+ message_clean = cut_message(message)
1299
+ prompt = f'''Проверь следующий текст на наличие фраз, которые могут быть истолкованы двусмысленно или вызвать негативные эмоции у читателя:
1300
+ "{message_clean}"
1301
+ Определи, есть ли в тексте выражения, которые могут быть восприняты как оскорбительные, обидные или неуместные.
1302
+ Обрати внимание, что фразы, используемые в обычном деловом контексте и не содержащие явных оскорблений, дискриминации или непристойностей, не считаются проблемными.
1303
+ Например, фразы, объясняющие преимущества продукта, такие как "без отчётов и комиссий", являются допустимыми.
1304
+ Пример ответа:
1305
+ {{"decision": false, "explanation": "Текст не содержит обидных или двусмысленных фраз."}}
1306
+ Если такие фразы есть, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}};
1307
+ если таких фраз нет, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}}.
1308
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1309
+
1310
+ response = generate_check_gigachat_pro(prompt)
1311
+ time.sleep(3)
1312
+ print("GigaChat Pro response:", response)
1313
+ result = parse_json_response(response)
1314
+ if result is not None:
1315
+ decision = result.get("decision", False)
1316
+ explanation = result.get("explanation", "")
1317
+ print("Explanation:", explanation)
1318
+ return not decision # Инвертируем логическое значение
1319
+ else:
1320
+ return None
1321
+
1322
+ # 28. Проверка на речевые клише, рекламные штампы и канцеляризмы
1323
+ def check_cliches_and_bureaucratese(message):
1324
+ print()
1325
+ print("Проверка 28: Проверка на речевые клише, рекламные штампы и канцеляризмы")
1326
+ print()
1327
+ message_clean = cut_message(message)
1328
+ prompt = f'''Проверь следующий текст на наличие речевых клише, излишне употребляемых фраз, рекламных штампов и канцеляризмов, которые делают текст менее выразительным и оригинальным:
1329
+ "{message_clean}"
1330
+ Обрати внимание **только** на избитые фразы, которые чрезмерно используются в рекламных текстах и не несут дополнительной ценности.
1331
+ **Не считай клише или канцеляризмами следующие типы выражений:**
1332
+ - Стандартные призывы к действию (например, "Получите", "Оформите", "Закажите сейчас"), но **не** их комбинации с общими, неопределёнными фразами, как например, "за считанные минуты", "быстро, удобно".
1333
+ - Информацию о ценах, скидках, акциях или условиях покупки (например, "при покупках от 100 000 рублей в месяц").
1334
+ - Описания способов оформления или получения услуг (например, "оформление возможно онлайн или в офисе").
1335
+ - Стандартные отраслевые термины и фразы, необходимые для понимания сообщения (например, "премиальная бизнес-карта", "Mastercard Preffered"), но **не** их использование в комбинации с общими словами, как например, "идеальное решение для вашего бизнеса".
1336
+ **Считай клише или канцеляризмами следующие типы выражений:**
1337
+ - Избитые фразы, такие как:
1338
+ - "Обеспечьте стабильность и развитие вашего бизнеса"
1339
+ - "Заботьтесь о будущем семьи, сохраняя ресурсы."
1340
+ - "Получите необходимые средства для развития бизнеса и обеспечения финансовой стабильности!"
1341
+ - "Ваш бизнес ждёт выгодное финансирование! Развивайте свой бизнес быстрее!"
1342
+ - "Без лишней волокиты"
1343
+ - "Быстро, удобно, без лишних хлопот!"
1344
+ - "За считанные минуты"
1345
+ - "Это идеальное предложение для вашего бизнеса!"
1346
+ - "Удобное и надёжное решение для роста вашего капитала".
1347
+ Пример ответа:
1348
+ {{"decision": false, "explanation": "Текст не содержит клише или канцеляризмов."}}
1349
+ Если в тексте **нет** таких выражений, **верни только** JSON {{"decision": false, "explanation": "<пояснение>"}};
1350
+ если в тексте **есть** такие выражения, **верни только** JSON {{"decision": true, "explanation": "<пояснение>"}}.
1351
+ **Не добавляй никакого дополнительного текста. Перед ответом убедись, что отвечаешь только в формате JSON с закрывающими кавычками и скобками.**'''
1352
+
1353
+ response = generate_check_gigachat_pro(prompt)
1354
+ time.sleep(3)
1355
+ print("GigaChat Pro response:", response)
1356
+ result = parse_json_response(response)
1357
+ if result is not None:
1358
+ decision = result.get("decision", False)
1359
+ explanation = result.get("explanation", "")
1360
+ print("Explanation:", explanation)
1361
+ return not decision
1362
+ else:
1363
+ return None
1364
+
1365
+ # 29. Проверка на соответствие описанию предложения
1366
+ def check_no_contradictions(message, description):
1367
+ print()
1368
+ print("Проверка 29: Проверка на отсутствие противоречий с описанием предложения")
1369
+ print()
1370
+ message_clean = cut_message(message)
1371
+ prompt = f'''Проверь, не противоречит ли следующее сообщение описанию предложения.
1372
+ Описание предложения:
1373
+ "{description}"
1374
+ Сообщение:
1375
+ "{message}"
1376
+ Если сообщение не содержит фактов, которые отсутствуют в описании предложения, **верни только** JSON {{"decision": false, "explanation": "Противоречий не обнаружено."}}.
1377
+ Если сообщение содержит факты, которые отсутствуют в описании предложения, **верни только** JSON {{"decision": true, "explanation": "<описание противоречий>"}}.
1378
+ **Не добавляй никакого дополнительного текста. Отвечай только в формате JSON с закрывающими кавычками и скобками.**'''
1379
+
1380
+ response = generate_check_gigachat_pro(prompt)
1381
+ time.sleep(3)
1382
+ print("GigaChat Pro response:", response)
1383
+ result = parse_json_response(response)
1384
+ if result is not None:
1385
+ decision = result.get("decision", False)
1386
+ explanation = result.get("explanation", "")
1387
+ print("Explanation:", explanation)
1388
+ return not decision # Возвращаем True, если противоречий нет
1389
+ else:
1390
+ return None
1391
+
1392
+ # 30. Проверка на наличие ключевого сообщения
1393
+ def check_contains_key_message(message, key_message):
1394
+ print()
1395
+ print("Проверка 30: Проверка на наличие ключевого сообщения")
1396
+ print()
1397
+ message_clean = cut_message(message)
1398
+ prompt = f'''Проверь, содержит ли следующее сообщение ключевое сообщение.
1399
+ Сообщение:
1400
+ "{message}"
1401
+ Ключевой текст:
1402
+ "{key_message}"
1403
+ Если сообщение **содержит всю** информацию из ключевого текста, **верни только** JSON {{"decision": false, "explanation": "Ключевое текст присутствует."}}.
1404
+ Если сообщение **не содержит всю** информацию из ключевого текста, **верни только** JSON {{"decision": true, "explanation": "Ключевое текст отсутствует."}}.
1405
+ **Не добавляй никакого дополнит��льного текста. Отвечай только в формате JSON с закрывающими кавычками и скобками.**'''
1406
+
1407
+ response = generate_check_gigachat_pro(prompt)
1408
+ time.sleep(3)
1409
+ print("GigaChat Pro response:", response)
1410
+ result = parse_json_response(response)
1411
+ if result is not None:
1412
+ decision = result.get("decision", False)
1413
+ explanation = result.get("explanation", "")
1414
+ print("Explanation:", explanation)
1415
+ return not decision # Возвращаем True, если ключевое сообщение присутствует
1416
+ else:
1417
+ return None
1418
+
1419
  # ФУНКЦИИ ПРОВЕРОК (КОНЕЦ)
1420
 
1421
+
1422
+ def safe_check(func, *args):
1423
+ try:
1424
+ return func(*args)
1425
+ except Exception as e:
1426
+ # Optionally, you can log the exception here if needed
1427
+ return None # Indicate that the check could not be performed
1428
+
1429
+ def perform_checks(message, description, key_message):
1430
+ checks = {}
1431
+
1432
+ # 2. Morphological checks using pymorphy2
1433
+ morphological_checks = [
1434
+ ("forbidden_words", check_forbidden_words),
1435
+ ("client_addressing", check_no_greeting),
1436
+ ("promises", check_no_promises),
1437
+ ("double_verbs", check_no_double_verbs),
1438
+ ("participles", check_no_participles),
1439
+ ("adverbial_participles", check_no_adverbial_participles),
1440
+ ("superlative_adjectives", check_no_superlative_adjectives),
1441
+ ("passive_voice", check_no_passive_voice),
1442
+ ("written_out_ordinals", check_no_written_out_ordinals),
1443
+ ("subordinate_clauses_chain", check_no_subordinate_clauses_chain),
1444
+ ("repeating_conjunctions", check_no_repeating_conjunctions),
1445
+ ("introductory_phrases", check_no_introductory_phrases),
1446
+ ("amplifiers", check_no_amplifiers),
1447
+ ("time_parasites", check_no_time_parasites),
1448
+ ("multiple_nouns", check_no_multiple_nouns),
1449
+ ("derived_prepositions", check_no_derived_prepositions),
1450
+ ("compound_sentences", check_no_compound_sentences),
1451
+ ("dates_written_out", check_no_dates_written_out),
1452
+ ("no_word_repetitions", check_no_word_repetitions),
1453
+ ]
1454
+
1455
+ # 3. LLM checks: check_clickbait_phrases, check_abstract_claims, check_cliches_and_bureaucratese
1456
+ llm_checks_group1 = [
1457
+ ("clickbait_phrases", check_clickbait_phrases),
1458
+ ("abstract_claims", check_abstract_claims),
1459
+ ("cliches_and_bureaucratese", check_cliches_and_bureaucratese),
1460
+ ]
1461
+
1462
+ # 4. Remaining LLM checks
1463
+ llm_checks_group2 = [
1464
+ ("disconnected_sentences", check_disconnected_sentences),
1465
+ ("synonymous_members", check_synonymous_members),
1466
+ ("specialized_terms", check_specialized_terms),
1467
+ ("offensive_phrases", check_offensive_phrases),
1468
+ ("no_contradictions", check_no_contradictions),
1469
+ ("contains_key_message", check_contains_key_message),
1470
+ ]
1471
+
1472
+ # Perform morphological checks
1473
+ for check_name, check_func in morphological_checks:
1474
+ result = safe_check(check_func, message)
1475
+ checks[check_name] = result
1476
+ if result is False:
1477
+ return checks # Stop on first failure
1478
+
1479
+ # Perform LLM checks group 1
1480
+ for check_name, check_func in llm_checks_group1:
1481
+ result = safe_check(check_func, message)
1482
+ checks[check_name] = result
1483
+ if result is False:
1484
+ return checks # Stop on first failure
1485
+
1486
+ # Perform remaining LLM checks
1487
+ for check_name, check_func in llm_checks_group2:
1488
+ if check_name == "no_contradictions":
1489
+ result = safe_check(check_func, message, description)
1490
+ elif check_name == "contains_key_message":
1491
+ result = safe_check(check_func, message, key_message)
1492
+ else:
1493
+ result = safe_check(check_func, message)
1494
+ checks[check_name] = result
1495
+ if result is False:
1496
+ return checks # Stop on first failure
1497
+
1498
+ return checks # All checks passed
1499
 
1500
 
1501
  def format_checks(checks):
 
1505
  "promises": "Обещания и гарантии",
1506
  "double_verbs": "Два глагола подряд",
1507
  "participles": "Причастия",
1508
+ "adverbial_participles": "Деепричастия",
1509
+ "superlative_adjectives": "Превосходная степень",
1510
+ "passive_voice": "Страдательный залог",
1511
+ "written_out_ordinals": "Порядковые числительные",
1512
+ "subordinate_clauses_chain": "Цепочки с придаточными предложениями",
1513
+ "repeating_conjunctions": "Разделительные повторяющиеся союзы",
1514
+ "introductory_phrases": "Вводные конструкции",
1515
+ "amplifiers": "Усилители",
1516
+ "time_parasites": "Паразиты времени",
1517
+ "multiple_nouns": "Несколько существительных подряд",
1518
+ "derived_prepositions": "Производные предлоги",
1519
+ "compound_sentences": "Сложноподчиненные предложения",
1520
+ "dates_written_out": "Даты прописью",
1521
+ "no_word_repetitions": "Повторы слов",
1522
+ # Проверки на LLM
1523
+ "disconnected_sentences": "Сложные предложения без логической связи",
1524
+ "synonymous_members": "Близкие по смыслу однородные члены предложения",
1525
+ "clickbait_phrases": "Кликбейтные фразы",
1526
+ "abstract_claims": "Абстрактные заявления без доказательств",
1527
+ "specialized_terms": "Узкоспециализированные термины",
1528
+ "offensive_phrases": "Двусмысленные или оскорбительные фразы",
1529
+ "cliches_and_bureaucratese": "Речевые клише, рекламные штампы, канцеляризмы",
1530
+ "no_contradictions": "Отсутствие противоречий с описанием предложения",
1531
+ "contains_key_message": "Наличие ключевого сообщения"
1532
  }
1533
+ formatted_results = []
1534
+ for rule, result in checks.items():
1535
+ if result is True:
1536
+ symbol = '✔️'
1537
+ elif result is False:
1538
+ symbol = '❌'
1539
+ else:
1540
+ symbol = '❓' # Indicates that the check could not be performed
1541
+ formatted_results.append(f"{translation[rule]}: {symbol}")
1542
+ return " \n".join(formatted_results)
1543
 
1544
 
1545
  # Функция для обработки нажатия кнопки "Проверить"