Spaces:
Sleeping
Sleeping
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(60, 90)), create_gauge(random.randint(60, 90)), create_gauge(random.randint(60, 90)) | |
# Функция для смены вкладки | |
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}" | |
# Функция для повторной генерации сообщения, пока оно не станет короче 250 знаков | |
def generate_message_gigachat_pro_with_retry(prompt): | |
for _ in range(10): | |
message = generate_message_gigachat_pro(prompt) | |
if len(message) <= 250: | |
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 знаков с пробелами.\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 знаков с пробелами, текст с учетом следующих особенностей:\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() |