Spaces:
Sleeping
Sleeping
File size: 47,384 Bytes
4973465 f154467 641416a c250f7e 641416a 3885885 542a444 ba58727 4973465 ba58727 edcf6fe 641416a 119e341 c250f7e 235357d da5f556 738feef da5f556 388bd90 aa349c2 388bd90 aa349c2 388bd90 aa349c2 da5f556 aa349c2 da5f556 7aee395 2329b47 7aee395 6839970 19d03d6 9f22308 2329b47 7aee395 6839970 7aee395 edcf6fe 7aee395 6839970 7aee395 9f22308 19d03d6 9f22308 7aee395 edcf6fe 307fbe8 d8d03be 307fbe8 d8d03be c2fba02 7aee395 5d9bc33 edcf6fe 5d9bc33 edcf6fe d3200da 08918b8 edcf6fe d3200da 7aee395 08918b8 d3200da dc5500f 925728c 9f22308 d3200da 5d9bc33 d3200da 5d9bc33 d3200da 307fbe8 d8d03be d3200da 307fbe8 d3200da ac0dd59 d3200da dc5500f 9f4be58 08918b8 d3200da 08918b8 307fbe8 d3200da 08918b8 cc02279 029a020 33a02ce 6b1f030 33a02ce 6b1f030 33a02ce d369a94 33a02ce d369a94 33a02ce d369a94 33a02ce d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 db923e7 d369a94 33a02ce edcf6fe 6839970 75730ec dfaf6c1 11d46da 5c41f19 593d3df 6839970 593d3df 6839970 2ca7cf0 119e341 593d3df 6839970 593d3df 6839970 119e341 593d3df edcf6fe 593d3df 6839970 593d3df 6839970 593d3df 6839970 7c8c711 af57cba 7aee395 af57cba 7aee395 af57cba 593d3df 2ca7cf0 dc5500f 75730ec 6839970 2ca7cf0 dc5500f 6839970 2ca7cf0 dc5500f 6839970 2ca7cf0 33a02ce 6839970 ae090c3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 |
import re
import gradio as gr
import os
import pandas as pd
import time
from langchain.schema import SystemMessage
from langchain_community.chat_models.gigachat import GigaChat
from openpyxl import load_workbook
import plotly.graph_objects as go
import random
import pymorphy2
import string
morph = pymorphy2.MorphAnalyzer()
# Авторизация в GigaChat Pro
gc_key = os.getenv('GC_KEY')
chat_pro = GigaChat(credentials=gc_key, model='GigaChat-Pro', max_tokens=68, temperature=1, verify_ssl_certs=False)
# Загрузка данных из Excel-файла
try:
data = pd.read_excel('Признаки.xlsx', sheet_name=None)
except Exception as e:
print(f"Ошибка при загрузке Excel-файла: {e}")
data = {}
# Создание списка признаков и их значений
features = {}
for sheet_name, df in data.items():
try:
if sheet_name == "Пол Поколение Психотип":
features[sheet_name] = df.set_index(['Пол', 'Поколение', 'Психотип'])['Инструкция'].to_dict()
else:
features[sheet_name] = df.set_index(df.columns[0]).to_dict()[df.columns[1]]
except Exception as e:
print(f"Ошибка при обработке данных листа {sheet_name}: {e}")
features[sheet_name] = {}
# Функция для создания спидометра
def create_gauge(value):
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=value,
gauge={
'axis': {'range': [0, 100]},
'bar': {'color': "black"}, # Цвет стрелки
'steps': [
{'range': [0, 40], 'color': "#55efc4"}, # Мягкий зеленый
{'range': [40, 70], 'color': "#ffeaa7"}, # Желтый
{'range': [70, 100], 'color': "#ff7675"} # Мягкий красный
],
'threshold': {
'line': {'color': "black", 'width': 4},
'thickness': 0.75,
'value': value
}
},
number={'font': {'size': 48}} # Размер шрифта числа
))
fig.update_layout(paper_bgcolor="#f8f9fa", font={'color': "#2d3436", 'family': "Arial"}, width=250, height=150)
return fig
# Функция для генерации случайных значений спидометров
def generate_random_gauges():
return create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95)), create_gauge(random.randint(80, 95))
# Функция для смены вкладки
def change_tab(id):
return gr.Tabs(selected=id)
# Вспомогательная функция для добавления префиксов и суффиксов
def add_prefix_suffix(prompt, prefix, suffix):
return f"{prefix}\n{prompt}\n{suffix}"
# Функция для обрезки сообщения до последнего знака препинания
def clean_message(message):
if not message.endswith(('.', '!', '?')):
last_period = max(message.rfind('.'), message.rfind('!'), message.rfind('?'))
if last_period != -1:
message = message[:last_period + 1]
return message
# Функция для генерации сообщения с GigaChat Pro
def generate_message_gigachat_pro(prompt):
try:
messages = [SystemMessage(content=prompt)]
res = chat_pro(messages)
cleaned_message = clean_message(res.content.strip())
return cleaned_message
except Exception as e:
return f"Ошибка при обращении к GigaChat-Pro: {e}"
# Функция для замены сокращений с 'k' или 'К' на тысячи
def replace_k_with_thousands(message):
# Замена и для 'k' и для 'К', с учётом регистра
message = re.sub(r'(\d+)[kкКK]', r'\1 000', message, flags=re.IGNORECASE)
return message
# Функция для повторной генерации сообщения, пока оно не станет короче 250 знаков и не меньше 190 знаков
# Добавляем проверку в функцию перегенерации
def generate_message_gigachat_pro_with_retry(prompt):
for _ in range(10):
message = generate_message_gigachat_pro(prompt)
message_length = len(message)
# Выполняем замены и проверки
message = replace_k_with_thousands(message)
checks = perform_checks(message)
if 190 <= message_length <= 250 and all(checks.values()):
return message
return message
# Функция для создания задания для копирайтера
def generate_standard_prompt(description, advantages, key_message, *selected_values):
prompt = (
f"Сгенерируй смс-сообщение для клиента.\n"
f"Описание предложения: {description}\n"
f"Преимущества: {advantages}\n"
"В тексте смс запрещено использование:\n"
"- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, доступный, банкротство, долги, займ, срочно, сейчас, лучший, главный, номер 1, гарантия, успех, лидер;\n"
"- Обращение к клиенту;\n"
"- Приветствие клиента;\n"
"- Обещания и гарантии;\n"
"- Использовать составные конструкции из двух глаголов;\n"
"- Причастия и причастные обороты;\n"
"- Деепричастия и деепричастные обороты;\n"
"- Превосходная степень прилагательных;\n"
"- Страдательный залог;\n"
"- Порядковые числительные от 10 прописью;\n"
"- Цепочки с придаточными предложениями;\n"
"- Разделительные повторяющиеся союзы;\n"
"- Вводные конструкции;\n"
"- Усилители;\n"
"- Паразиты времени;\n"
"- Несколько существительных подряд, в том числе отглагольных;\n"
"- Производные предлоги;\n"
"- Сложные предложения, в которых нет связи между частями;\n"
"- Сложноподчинённые предложения;\n"
"- Даты прописью;\n"
"- Близкие по смыслу однородные члены предложения;\n"
"- Шокирующие, экстравагантные, кликбейтные фразы;\n"
"- Абстрактные заявления без поддержки фактами и отсутствие доказательства пользы для клиента;\n"
"- Гарантирующие фразы;\n"
"- Узкоспециализированные термины;\n"
"- Фразы, способные создать двойственное ощущение, обидеть;\n"
"- Речевые клише, рекламные штампы, канцеляризмы;\n"
"Убедись, что в готовом тексте до 250 знаков с пробелами, но не менее 190 знаков с пробелами.\n"
)
if key_message.strip():
prompt += f"Убедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
return prompt
# Функция для создания задания для редактора с добавлением prefix и suffix
def generate_personalization_prompt(key_message, *selected_values, prefix, suffix):
prompt = "Адаптируй, не превышая длину сообщения в 250 знаков с пробелами (но и не менее 190 знаков с пробелами), текст с учетом следующих особенностей:\n"
gender, generation, psychotype = selected_values[0], selected_values[1], selected_values[2]
combined_instruction = ""
additional_instructions = ""
# Проверяем, выбраны ли все три параметра: Пол, Поколение, Психотип
if gender and generation and psychotype:
# Получаем данные с листа "Пол Поколение Психотип"
sheet = features.get("Пол Поколение Психотип", {})
# Ищем ключ, соответствующий комбинации "Пол", "Поколение", "Психотип"
key = (gender, generation, psychotype)
if key in sheet:
combined_instruction = sheet[key]
# Если не найдена комбинированная инструкция, добавляем индивидуальные инструкции
if not combined_instruction:
for i, feature in enumerate(["Пол", "Поколение", "Психотип"]):
if selected_values[i]:
try:
instruction = features[feature][selected_values[i]]
additional_instructions += f"{instruction}\n"
except KeyError:
return f"Ошибка: выбранное значение {selected_values[i]} не найдено в данных."
# Добавляем инструкции для остальных параметров (например, Отрасль)
for i, feature in enumerate(features.keys()):
if feature not in ["Пол", "Поколение", "Психотип", "Пол Поколение Психотип"]:
if i < len(selected_values) and selected_values[i]:
try:
instruction = features[feature][selected_values[i]]
additional_instructions += f"{instruction}\n"
except KeyError:
return f"Ошибка: выбранное значение {selected_values[i]} не найдено в данных."
# Формируем итоговый промпт
if combined_instruction:
prompt += combined_instruction # Добавляем комбинированную инструкцию, если она есть
if additional_instructions:
prompt += additional_instructions # Добавляем остальные инструкции
# Добавляем префикс и суффикс для задания редактора
prompt = f"{prefix}\n{prompt}\n{suffix}"
# Добавляем ключевое сообщение
prompt += f"\nУбедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}"
return prompt.strip()
# Функция для удаления префиксов, суффиксов и пустых строк перед выводом на экран
def clean_prompt_for_display(prompt, prefixes, suffixes):
# Удаляем префиксы и суффиксы
for prefix in prefixes:
prompt = prompt.replace(prefix, "")
for suffix in suffixes:
prompt = prompt.replace(suffix, "")
# Удаляем пустые строки
lines = prompt.split('\n')
non_empty_lines = [line for line in lines if line.strip() != '']
cleaned_prompt = '\n'.join(non_empty_lines)
return cleaned_prompt.strip()
# Функция для постепенной генерации всех сообщений через yield
def generate_all_messages(desc, benefits, key_message, gender, generation, psychotype, business_stage, industry, opf):
# Генерация задания для копирайтера
standard_prompt = generate_standard_prompt(desc, benefits, key_message)
yield standard_prompt, None, None, None, None, None, None, None
# Небольшая пауза для демонстрации постепенной генерации
time.sleep(1)
# Варианты предложений для начала и конца
prefixes = [
"Начни сообщение с призыва к действию с продуктом.",
"Начни сообщение с указания на пользу продукта. Используй глагол в побудительном наклонении.",
"Начни сообщение с вопроса, который указывает на пользу продукта для клиента."
]
suffixes = [
"Убедись, что готовый текст начинается с призыва к действию с продуктом.",
"Убедись, что готовый текст начинается с указания на пользу продукта и использования глагола в побудительном наклонении.",
"Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента."
]
non_personalized_messages = []
personalized_messages = []
# Генерация и постепенная подача каждого сообщения
for i in range(3):
# Генерация неперсонализированного сообщения
prompt = add_prefix_suffix(standard_prompt, prefixes[i], suffixes[i])
non_personalized_message = generate_message_gigachat_pro_with_retry(prompt)
non_personalized_length = len(non_personalized_message)
non_personalized_display = f"{non_personalized_message}\n------\nКоличество знаков: {non_personalized_length}"
non_personalized_messages.append(non_personalized_display)
# Генерация задания для редактора
personalization_prompt = generate_personalization_prompt(
key_message, gender, generation, psychotype, business_stage, industry, opf,
prefix=prefixes[i], suffix=suffixes[i]
)
# Удаляем префиксы, суффиксы и пустые строки перед выводом на экран
display_personalization_prompt = clean_prompt_for_display(personalization_prompt, prefixes, suffixes)
# Выводим неперсонализированное сообщение и задание для редактора
yield (
standard_prompt, display_personalization_prompt, # Задание для редактора без префиксов, суффиксов и пустых строк
non_personalized_messages[0] if i >= 0 else None,
personalized_messages[0] if len(personalized_messages) > 0 else None,
non_personalized_messages[1] if i >= 1 else None,
personalized_messages[1] if len(personalized_messages) > 1 else None,
non_personalized_messages[2] if i >= 2 else None,
personalized_messages[2] if len(personalized_messages) > 2 else None
)
# Генерация персонализированного сообщения
full_personalized_prompt = f"{personalization_prompt}\n\nТекст для адаптации: {non_personalized_message}"
personalized_message = generate_message_gigachat_pro_with_retry(full_personalized_prompt)
personalized_length = len(personalized_message)
personalized_display = f"{personalized_message}\n------\nКоличество знаков: {personalized_length}"
personalized_messages.append(personalized_display)
# Выводим персонализированное сообщение
yield (
standard_prompt, display_personalization_prompt, # Задание для редактора без префиксов, суффиксов и пустых строк
non_personalized_messages[0] if len(non_personalized_messages) > 0 else None,
personalized_messages[0] if len(personalized_messages) > 0 else None,
non_personalized_messages[1] if len(non_personalized_messages) > 1 else None,
personalized_messages[1] if len(personalized_messages) > 1 else None,
non_personalized_messages[2] if len(non_personalized_messages) > 2 else None,
personalized_messages[2] if len(personalized_messages) > 2 else None
)
time.sleep(1)
# ФУНКЦИИ ПРОВЕРОК (НАЧАЛО)
# 1. Запрещенные слова
def check_forbidden_words(message):
morph = pymorphy2.MorphAnalyzer()
# Перечень запрещённых слов и фраз
forbidden_patterns = [
r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b',
r'вкусный', r'дешёвый', r'продукт',
r'спам', r'доступный', r'банкротство', r'долг[и]?', r'займ',
r'срочный', r'сейчас', r'главный',
r'гарантия', r'успех', r'лидер'
]
# Удаляем знаки препинания для корректного анализа
message_without_punctuation = message.translate(str.maketrans('', '', string.punctuation))
# Проверка на наличие подстроки "лучш" (без учета регистра)
if re.search(r'лучш', message_without_punctuation, re.IGNORECASE):
return False
# Лемматизация слов сообщения
words = message_without_punctuation.split()
lemmas = [morph.parse(word)[0].normal_form for word in words]
normalized_message = ' '.join(lemmas)
# Проверка на запрещённые фразы и леммы
for pattern in forbidden_patterns:
if re.search(pattern, normalized_message, re.IGNORECASE):
return False
return True
# 2 и #3. Обращение к клиенту и приветствие клиента
def check_no_greeting(message):
morph = pymorphy2.MorphAnalyzer()
# Список типичных обращений и приветствий
greeting_patterns = [
r"привет\b", r"здравствуй", r"добрый\s(день|вечер|утро)",
r"дорогой\b", r"уважаемый\b", r"дорогая\b", r"уважаемая\b",
r"господин\b", r"госпожа\b", r"друг\b", r"коллега\b",
r"товарищ\b", r"приятель\b", r"друг\b", r"подруга\b"
]
# Компилируем все шаблоны в один регулярное выражение
greeting_regex = re.compile('|'.join(greeting_patterns), re.IGNORECASE)
# Проверяем, начинается ли сообщение с шаблона приветствия или обращения
if greeting_regex.search(message.strip()):
return False
return True
# 4. Обещания и гарантии
def check_no_promises(message):
morph = pymorphy2.MorphAnalyzer()
promise_patterns = [
"обещать", "гарантировать", "обязаться"
]
words = message.split()
lemmas = [morph.parse(word)[0].normal_form for word in words]
for pattern in promise_patterns:
if pattern in lemmas:
return False
return True
# 5. Составные конструкции из двух глаголов
def check_no_double_verbs(message):
morph = pymorphy2.MorphAnalyzer()
# Разделяем текст по пробелам и знакам препинания
words = re.split(r'\s+|[.!?]', message)
morphs = [morph.parse(word)[0] for word in words]
for i in range(len(morphs) - 1):
# Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы)
if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}):
return False
return True
# 6. Причастия и причастные обороты
def check_no_participles(message):
morph = pymorphy2.MorphAnalyzer()
words = message.split()
morphs = [morph.parse(word)[0] for word in words]
for morph in morphs:
if 'PRTF' in morph.tag:
return False
return True
# 7. Деепричастия и деепричастные обороты
def check_no_adverbial_participles(message):
morph = pymorphy2.MorphAnalyzer()
words = message.split()
morphs = [morph.parse(word)[0] for word in words]
for morph in morphs:
if 'GRND' in morph.tag:
return False
return True
# 8. Превосходная степень прилагательных
def check_no_superlative_adjectives(message):
morph = pymorphy2.MorphAnalyzer()
words = message.split()
morphs = [morph.parse(word)[0] for word in words]
for morph in morphs:
if 'COMP' in morph.tag or 'Supr' in morph.tag:
return False
return True
# 9. Страдательный залог
def check_no_passive_voice(message):
morph = pymorphy2.MorphAnalyzer()
words = message.split()
morphs = [morph.parse(word)[0] for word in words]
for morph in morphs:
if 'PRTF' in morph.tag and ('passive' in morph.tag or 'в' in morph.tag):
return False
return True
# 10. Порядковые числительные от 10 прописью
def check_no_written_out_ordinals(message):
morph = pymorphy2.MorphAnalyzer()
ordinal_words = [
"десятый", "одиннадцатый", "двенадцатый", "тринадцатый", "четырнадцатый", "пятнадцатый",
"шестнадцатый", "семнадцатый", "восемнадцатый", "девятнадцатый", "двадцатый"
]
words = message.split()
lemmas = [morph.parse(word)[0].normal_form for word in words]
for word in ordinal_words:
if word in lemmas:
return False
return True
# 11. Цепочки с придаточными предложениями
def check_no_subordinate_clauses_chain(message):
# Регулярное выражение, которое ищет последовательности придаточных предложений
subordinate_clause_patterns = [
r'\b(который|которая|которое|которые)\b',
r'\b(если|потому что|так как|что|когда)\b',
r'\b(хотя|несмотря на то что)\b'
]
count = 0
for pattern in subordinate_clause_patterns:
if re.search(pattern, message):
count += 1
# Если в предложении найдено более одного придаточного предложения подряд, возвращаем False
return count < 2
# 12. Разделительные повторяющиеся союзы
def check_no_repeating_conjunctions(message):
# Регулярное выражение для поиска разделительных повторяющихся союзов с запятой перед вторым союзом
repeating_conjunctions_patterns = r'\b(и|ни|то|не то|или|либо)\b\s*(.*?)\s*,\s*\b\1\b'
# Разделяем сообщение на предложения по точке, вопросительному и восклицательному знакам
sentences = re.split(r'[.!?]\s*', message)
# Проверяем каждое предложение отдельно
for sentence in sentences:
if re.search(repeating_conjunctions_patterns, sentence, re.IGNORECASE):
return False
return True
# 13. Вводные конструкции
def check_no_introductory_phrases(message):
introductory_phrases = [
r'\b(во-первых|во-вторых|с одной стороны|по сути|по правде говоря)\b',
r'\b(может быть|кстати|конечно|естественно|безусловно|возможно)\b'
]
for pattern in introductory_phrases:
if re.search(pattern, message, re.IGNORECASE):
return False
return True
# 14. Усилители
def check_no_amplifiers(message):
amplifiers = [
r'\b(очень|крайне|чрезвычайно|совсем|абсолютно|полностью|чисто)\b'
]
for pattern in amplifiers:
if re.search(pattern, message, re.IGNORECASE):
return False
return True
# 15. Паразиты времени
def check_no_time_parasites(message):
time_parasites = [
r'\b(сейчас|немедленно|срочно|в данный момент|теперь)\b'
]
for pattern in time_parasites:
if re.search(pattern, message, re.IGNORECASE):
return False
return True
# 16. Несколько существительных подряд
def check_no_multiple_nouns(message):
noun_count = 0
words = re.split(r'\s+|[.!?]', message) # Разбиваем по пробелам и знакам препинания
morph = pymorphy2.MorphAnalyzer()
for word in words:
parsed_word = morph.parse(word)[0]
# Если слово — существительное
if 'NOUN' in parsed_word.tag:
noun_count += 1
# Если встречен конец предложения (точка, вопросительный знак, восклицательный знак)
elif re.match(r'[.!?]', word):
noun_count = 0
else:
noun_count = 0
if noun_count > 2:
return False
return True
# 17. Производные предлоги
def check_no_derived_prepositions(message):
derived_prepositions = [
r'\b(в течение|в ходе|вследствие|в связи с|по мере|при помощи|согласно|вопреки|на основании|на случай|в продолжение|по причине|вблизи|вдалеке|вокруг|внутри|вдоль|посередине|вне|снаружи|благодаря|невзирая на|исходя из)\b'
]
for pattern in derived_prepositions:
if re.search(pattern, message, re.IGNORECASE):
return False
return True
# 19. Сложноподчиненные предложения
def check_no_compound_sentences(message):
subordinating_conjunctions = [
r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b',
r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b',
r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b',
r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b',
r'\bчто\b'
]
# Убедимся, что слово "как" используется не в вопросе
for pattern in subordinating_conjunctions:
if re.search(pattern, message) and not re.search(r'\?', message):
return False
return True
# 20. Даты прописью
def check_no_dates_written_out(message):
# Ищем упоминания месяцев или слов, связанных с датами
months = [
"января", "февраля", "марта", "апреля", "мая", "июня",
"июля", "августа", "сентября", "октября", "ноября", "декабря"
]
# Слова для проверки чисел прописью
date_written_out_patterns = [
r'\b(первого|второго|третьего|четвертого|пятого|шестого|седьмого|восьмого|девятого|десятого|одиннадцатого|двенадцатого|тринадцатого|четырнадцатого|пятнадцатого|шестнадцатого|семнадцатого|восемнадцатого|девятнадцатого|двадцатого|двадцать первого|двадцать второго|двадцать третьего|двадцать четвертого|двадцать пятого|двадцать шестого|двадцать седьмого|двадцать восьмого|двадцать девятого|тридцатого|тридцать первого)\b'
]
for month in months:
for pattern in date_written_out_patterns:
if re.search(f'{pattern}\\s{month}', message, re.IGNORECASE):
return False
return True
# ФУНКЦИИ ПРОВЕРОК (КОНЕЦ)
def perform_checks(message):
checks = {
"forbidden_words": check_forbidden_words(message),
"client_addressing": check_no_greeting(message),
"promises": check_no_promises(message),
"double_verbs": check_no_double_verbs(message),
"participles": check_no_participles(message),
"adverbial_participles": check_no_adverbial_participles(message)
# "superlative_adjectives": check_no_superlative_adjectives(message),
# "passive_voice": check_no_passive_voice(message),
# "written_out_ordinals": check_no_written_out_ordinals(message),
# "subordinate_clauses_chain": check_no_subordinate_clauses_chain(message),
# "repeating_conjunctions": check_no_repeating_conjunctions(message),
# "introductory_phrases": check_no_introductory_phrases(message),
# "amplifiers": check_no_amplifiers(message),
# "time_parasites": check_no_time_parasites(message),
# "multiple_nouns": check_no_multiple_nouns(message),
# "derived_prepositions": check_no_derived_prepositions(message),
# "compound_sentences": check_no_compound_sentences(message),
# "dates_written_out": check_no_dates_written_out(message)
}
return checks
def format_checks(checks):
translation = {
"forbidden_words": "Запрещенные слова",
"client_addressing": "Обращение к клиенту",
"promises": "Обещания и гарантии",
"double_verbs": "Два глагола подряд",
"participles": "Причастия",
"adverbial_participles": "Деепричастия"
# "superlative_adjectives": "Превосходная степень",
# "passive_voice": "Страдательный залог",
# "written_out_ordinals": "Порядковые числительные",
# "subordinate_clauses_chain": "Цепочки с придаточными предложениями",
# "repeating_conjunctions": "Разделительные повторяющиеся союзы",
# "introductory_phrases": "Вводные конструкции",
# "amplifiers": "Усилители",
# "time_parasites": "Паразиты времени",
# "multiple_nouns": "Несколько существительных подряд",
# "derived_prepositions": "Производные предлоги",
# "compound_sentences": "Сложноподчиненные предложения",
# "dates_written_out": "Даты прописью"
}
return " \n".join([f"{translation[rule]}: {'✔️' if result else '❌'}" for rule, result in checks.items()])
# Функция для обработки нажатия кнопки "Проверить"
def perform_all_checks_and_show_results(personalized_message_1, personalized_message_2, personalized_message_3):
# Моментально показываем все персонализированные сообщения
yield (
personalized_message_1, None, # Первое сообщение без проверки
personalized_message_2, None, # Второе сообщение без проверки
personalized_message_3, None, # Третье сообщение без проверки
None, None, None # Пустые графики для спидометров
)
# Выполняем и показываем проверки с задержкой 1 секунда
checks_1 = perform_checks(personalized_message_1)
formatted_checks_1 = format_checks(checks_1)
time.sleep(1) # Задержка 1 секунда перед выводом первого результата проверки
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, None, # Второе сообщение без проверки
personalized_message_3, None, # Третье сообщение без проверки
None, None, None # Пустые графики для спидометров
)
checks_2 = perform_checks(personalized_message_2)
formatted_checks_2 = format_checks(checks_2)
time.sleep(1) # Задержка 1 секунда перед выводом второго результата проверки
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, formatted_checks_2, # Проверка для второго сообщения
personalized_message_3, None, # Третье сообщение без проверки
None, None, None # Пустые графики для спидометров
)
checks_3 = perform_checks(personalized_message_3)
formatted_checks_3 = format_checks(checks_3)
time.sleep(1) # Задержка 1 секунда перед выводом третьего результата проверки
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, formatted_checks_2, # Проверка для второго сообщения
personalized_message_3, formatted_checks_3, # Проверка для третьего сообщения
None, None, None # Пустые графики для спидометров
)
# Генерация и показ графиков спидометров с задержкой 2 секунды
time.sleep(2)
gauges = generate_random_gauges()
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, formatted_checks_2, # Проверка для второго сообщения
personalized_message_3, formatted_checks_3, # Проверка для третьего сообщения
gauges[0], None, None # Первый график спидометра
)
time.sleep(2)
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, formatted_checks_2, # Проверка для второго сообщения
personalized_message_3, formatted_checks_3, # Проверка для третьего сообщения
gauges[0], gauges[1], None # Первый и второй графики спидометра
)
time.sleep(2)
yield (
personalized_message_1, formatted_checks_1, # Проверка для первого сообщения
personalized_message_2, formatted_checks_2, # Проверка для второго сообщения
personalized_message_3, formatted_checks_3, # Проверка для третьего сообщения
gauges[0], gauges[1], gauges[2] # Все три графика спидометра
)
# Интерфейс Gradio
with gr.Blocks() as demo:
# Твой интерфейс
with gr.Tabs() as tabs:
# Вкладка 1: Исходные данные
with gr.TabItem("Исходные данные", id=0):
with gr.Row():
with gr.Column():
desc = gr.Textbox(
label="Описание предложения (предзаполненный пример можно поменять на свой)",
lines=7,
value=(
"Необходимо предложить клиенту оформить дебетовую премиальную бизнес-карту Mastercard Preffered. "
"Обслуживание карты стоит 700 рублей в месяц, но клиент может пользоваться ей бесплатно. "
"Что необходимо сделать, чтобы воспользоваться предложением:\n"
"1. Оформить премиальную бизнес-карту в офисе банка или онлайн в интернет-банке СберБизнес.\n"
"2. Забрать карту.\n"
"3. В течение календарного месяца совершить по ней покупки на сумму от 100 000 рублей.\n"
"4. В течение следующего месяца пользоваться ей бесплатно."
)
)
benefits = gr.Textbox(
label="Преимущества (предзаполненный пример можно поменять на свой)",
lines=5,
value=(
"Предложение по бесплатному обслуживанию — бессрочное.\n"
"Оплата покупок без отчётов и платёжных поручений.\n"
"Платёжные документы без комиссии.\n"
"Лимиты на расходы сотрудников.\n"
"Мгновенные переводы на карты любых банков."
)
)
key_message = gr.Textbox(
label="Ключевое сообщение (предзаполненный пример можно поменять на свой)",
lines=3,
value="Бесплатное обслуживание при покупках от 100 000 рублей в месяц."
)
with gr.Column():
gender = gr.Dropdown(label="Пол", choices=[None] + list(features.get('Пол', {}).keys()))
generation = gr.Dropdown(label="Поколение", choices=[None] + list(features.get('Поколение', {}).keys()))
psychotype = gr.Dropdown(label="Психотип", choices=[None] + list(features.get('Психотип', {}).keys()))
business_stage = gr.Dropdown(label="Стадия бизнеса", choices=[None] + list(features.get('Стадия бизнеса', {}).keys()))
industry = gr.Dropdown(label="Отрасль", choices=[None] + list(features.get('Отрасль', {}).keys()))
opf = gr.Dropdown(label="ОПФ", choices=[None] + list(features.get('ОПФ', {}).keys()))
btn_to_prompts = gr.Button("Создать")
# Вкладка 2: Промпты
with gr.TabItem("Ассистент", id=1):
with gr.Row():
with gr.Column():
non_personalized_prompt = gr.Textbox(
label="Задание для копирайтера",
lines=25,
interactive=False)
with gr.Column():
personalized_prompt = gr.Textbox(label="Задание для редактора", lines=25) # Увеличенная высота
# Вкладка 3: Сообщения
with gr.TabItem("Сообщения", id=2):
with gr.Row():
gr.Markdown("### Копирайтер")
gr.Markdown("### Редактор")
with gr.Row():
non_personalized_1 = gr.Textbox(label="Стандартное сообщение 1", lines=4, interactive=False)
personalized_1 = gr.Textbox(label="Персонализированное сообщение 1", lines=4, interactive=False)
with gr.Row():
non_personalized_2 = gr.Textbox(label="Стандартное сообщение 2", lines=4, interactive=False)
personalized_2 = gr.Textbox(label="Персонализированное сообщение 2", lines=4, interactive=False)
with gr.Row():
non_personalized_3 = gr.Textbox(label="Стандартное сообщение 3", lines=4, interactive=False)
personalized_3 = gr.Textbox(label="Персонализированное сообщение 3", lines=4, interactive=False)
# Четвертый ряд
with gr.Row():
btn_check = gr.Button("Проверить", elem_id="check3")
btn_check.click(fn=change_tab, inputs=[gr.Number(value=3, visible=False)], outputs=tabs)
# Сначала переключаем вкладку, потом запускаем генерацию сообщений
btn_to_prompts.click(
fn=change_tab,
inputs=[gr.Number(value=1, visible=False)], # Переключение на вкладку "Ассистент" (id=1)
outputs=tabs # Обновляем вкладку
).then(
fn=generate_all_messages,
inputs=[desc, benefits, key_message, gender, generation, psychotype, business_stage, industry, opf], # Входные текстовые поля
outputs=[
non_personalized_prompt, personalized_prompt, # Поля для задания копирайтера и редактора (на вкладке "Ассистент")
non_personalized_1, personalized_1, # Сообщения на вкладке "Сообщения"
non_personalized_2, personalized_2,
non_personalized_3, personalized_3
]
)
# Вкладка 4: Проверка
with gr.TabItem("Проверка", id=3):
with gr.Row():
gr.Markdown("### Редактор")
gr.Markdown("### Корректор")
gr.Markdown("### Аналитик")
with gr.Row():
personalized_message_1 = gr.Textbox(label="Персонализированное сообщение 1", lines=5, interactive=False)
check_message_1 = gr.Textbox(label="Проверка сообщения 1", lines=5, interactive=False)
with gr.Column():
gr.HTML("<div style='display:flex; justify-content:center; width:100%;'>")
success_forecast_1 = gr.Plot(label="Прогноз успешности сообщения 1")
gr.HTML("</div>")
with gr.Row():
personalized_message_2 = gr.Textbox(label="Персонализированное сообщение 2", lines=5)
check_message_2 = gr.Textbox(label="Проверка сообщения 2", lines=5, interactive=False)
with gr.Column():
gr.HTML("<div style='display:flex; justify-content:center; width:100%;'>")
success_forecast_2 = gr.Plot(label="Прогноз успешности сообщения 2")
gr.HTML("</div>")
with gr.Row():
personalized_message_3 = gr.Textbox(label="Персонализированное сообщение 3", lines=5, interactive=False)
check_message_3 = gr.Textbox(label="Проверка сообщения 3", lines=5, interactive=False)
with gr.Column():
gr.HTML("<div style='display:flex; justify-content:center; width:100%;'>")
success_forecast_3 = gr.Plot(label="Прогноз успешности сообщения 3")
gr.HTML("</div>")
# Модифицируем нажатие кнопки "Проверить"
btn_check.click(
fn=change_tab,
inputs=[gr.Number(value=3, visible=False)], # Переключение на вкладку "Проверка"
outputs=tabs # Обновляем вкладку
).then(
fn=perform_all_checks_and_show_results,
inputs=[personalized_1, personalized_2, personalized_3], # Входные персонализированные сообщения
outputs=[
personalized_message_1, check_message_1, # Результаты проверок для первого сообщения
personalized_message_2, check_message_2, # Результаты проверок для второго сообщения
personalized_message_3, check_message_3 # Результаты проверок для третьего сообщения
]
).then(
fn=generate_random_gauges,
inputs=[], # Нет входных данных для спидометров
outputs=[success_forecast_1, success_forecast_2, success_forecast_3] # Вывод значений спидометров
)
demo.launch() |