Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -17,6 +17,11 @@ import string
|
|
17 |
import io
|
18 |
from datetime import datetime, timedelta
|
19 |
import plotly.express as px
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
morph = pymorphy2.MorphAnalyzer()
|
22 |
|
@@ -30,7 +35,7 @@ TOGETHER_API_KEY = os.getenv('TOGETHER_API_KEY')
|
|
30 |
client = Together(api_key=TOGETHER_API_KEY)
|
31 |
|
32 |
# Авторизация в сервисе GigaChat
|
33 |
-
chat_pro = GigaChat(credentials=gc_key, model='GigaChat-Pro', max_tokens=68, temperature=1, verify_ssl_certs=False)
|
34 |
chat_lite = GigaChat(credentials=gc_key, model='GigaChat', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
|
35 |
chat_plus = GigaChat(credentials=gc_key, model='GigaChat-Plus', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
|
36 |
|
@@ -504,6 +509,25 @@ def correct_dash_usage(text):
|
|
504 |
# Join the sentences back
|
505 |
text = ' '.join(sentences)
|
506 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
507 |
return text
|
508 |
|
509 |
|
@@ -692,20 +716,18 @@ def load_previous_user_request_from_github():
|
|
692 |
return "", "", "", "", "", "", "", "", "", "", None, None, None, None, None, None
|
693 |
|
694 |
|
695 |
-
def get_reference_message(gender, generation, psychotype, business_stage, industry, legal_form):
|
696 |
import io
|
697 |
-
|
|
|
698 |
repo = "fruitpicker01/Storage_dev"
|
699 |
file_path = "messages.csv"
|
700 |
-
|
701 |
url = f"https://api.github.com/repos/{repo}/contents/{file_path}"
|
702 |
headers = {
|
703 |
"Authorization": f"token {token}",
|
704 |
"Content-Type": "application/json"
|
705 |
}
|
706 |
-
|
707 |
response = requests.get(url, headers=headers)
|
708 |
-
|
709 |
if response.status_code == 200:
|
710 |
content = response.json()
|
711 |
file_content = base64.b64decode(content['content'])
|
@@ -714,11 +736,9 @@ def get_reference_message(gender, generation, psychotype, business_stage, indust
|
|
714 |
print(f"Error accessing the file: {response.status_code}")
|
715 |
return None
|
716 |
|
717 |
-
# Нормализуем данные для корректного сравнения
|
718 |
for col in ["Пол", "Поколение", "Психотип", "Стадия бизнеса", "Отрасль", "ОПФ"]:
|
719 |
df[col] = df[col].astype(str).str.strip().str.lower()
|
720 |
|
721 |
-
# Нормализуем входные параметры
|
722 |
params = {
|
723 |
"Пол": str(gender).strip().lower() if gender else None,
|
724 |
"Поколение": str(generation).strip().lower() if generation else None,
|
@@ -728,7 +748,8 @@ def get_reference_message(gender, generation, psychotype, business_stage, indust
|
|
728 |
"ОПФ": str(legal_form).strip().lower() if legal_form else None
|
729 |
}
|
730 |
|
731 |
-
|
|
|
732 |
filter_conditions = []
|
733 |
for col, value in params.items():
|
734 |
if value and value.lower() != 'none':
|
@@ -738,7 +759,6 @@ def get_reference_message(gender, generation, psychotype, business_stage, indust
|
|
738 |
print("Не заданы параметры персонализации.")
|
739 |
return None
|
740 |
|
741 |
-
# Применяем фильтрацию
|
742 |
filter_condition = filter_conditions[0]
|
743 |
for condition in filter_conditions[1:]:
|
744 |
filter_condition &= condition
|
@@ -749,25 +769,50 @@ def get_reference_message(gender, generation, psychotype, business_stage, indust
|
|
749 |
print("Сообщения с заданными параметрами не найдены.")
|
750 |
return None
|
751 |
|
752 |
-
|
753 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
754 |
|
755 |
-
#
|
756 |
-
|
757 |
|
758 |
-
# Получаем
|
759 |
-
|
760 |
-
|
|
|
|
|
|
|
|
|
761 |
else:
|
762 |
-
|
|
|
|
|
|
|
763 |
|
764 |
-
|
765 |
-
|
|
|
|
|
766 |
|
|
|
767 |
return reference_message
|
768 |
|
769 |
|
770 |
def adapt_messages_to_best_example(
|
|
|
771 |
personalized_gigachat_pro,
|
772 |
personalized_gigachat_lite,
|
773 |
personalized_gigachat_plus,
|
@@ -786,7 +831,7 @@ def adapt_messages_to_best_example(
|
|
786 |
legal_form = selected_values[5]
|
787 |
|
788 |
# Получение эталонного сообщения (без изменений)
|
789 |
-
reference_message = get_reference_message(gender, generation, psychotype, business_stage, industry, legal_form)
|
790 |
|
791 |
if not reference_message:
|
792 |
# Если эталонное сообщение не найдено
|
@@ -796,13 +841,14 @@ def adapt_messages_to_best_example(
|
|
796 |
# Шаблон промпта (без изменений)
|
797 |
prompt_template = (
|
798 |
"Сообщение для адаптации:\n\"{personalized_message}\"\n\n"
|
799 |
-
"Эталонное
|
800 |
-
"Перепиши сообщение для адаптации,
|
801 |
-
"
|
802 |
-
"
|
803 |
-
"Убедись, что
|
|
|
804 |
)
|
805 |
-
|
806 |
# Инициализация пустых переменных для сообщений
|
807 |
adapted_gigachat_pro = ""
|
808 |
adapted_gigachat_lite = ""
|
@@ -866,7 +912,7 @@ def adapt_messages_to_best_example(
|
|
866 |
yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, adapted_gigachat_plus_display, adapted_gpt4o_display, adapted_meta_llama_405b_display
|
867 |
|
868 |
|
869 |
-
def update_best_example_prompt(*selected_values):
|
870 |
# Extract personalization parameters
|
871 |
gender = selected_values[0]
|
872 |
generation = selected_values[1]
|
@@ -876,20 +922,24 @@ def update_best_example_prompt(*selected_values):
|
|
876 |
legal_form = selected_values[5]
|
877 |
|
878 |
# Retrieve the reference message
|
879 |
-
reference_message = get_reference_message(gender, generation, psychotype, business_stage, industry, legal_form)
|
880 |
|
881 |
if not reference_message:
|
882 |
# No reference message found
|
883 |
best_prompt = "Эталонное сообщение не найдено для выбранных параметров персонализации."
|
884 |
else:
|
885 |
best_prompt = (
|
886 |
-
|
887 |
-
"Перепиши сообщение для адаптации,
|
888 |
-
"
|
889 |
-
|
|
|
|
|
|
|
890 |
return best_prompt
|
891 |
|
892 |
def adapt_messages_and_perform_checks(
|
|
|
893 |
personalized_gigachat_pro,
|
894 |
personalized_gigachat_lite,
|
895 |
personalized_gigachat_plus,
|
@@ -900,6 +950,7 @@ def adapt_messages_and_perform_checks(
|
|
900 |
*selected_values
|
901 |
):
|
902 |
adaptation_generator = adapt_messages_to_best_example(
|
|
|
903 |
personalized_gigachat_pro,
|
904 |
personalized_gigachat_lite,
|
905 |
personalized_gigachat_plus,
|
@@ -965,7 +1016,7 @@ def generate_standard_prompt(description, advantages, key_message, approach, *se
|
|
965 |
f"Описание предложения: {description}\n"
|
966 |
f"Преимущества: {advantages}\n"
|
967 |
"В тексте смс запрещено использование:\n"
|
968 |
-
"- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам,
|
969 |
"- Обращение к клиенту;\n"
|
970 |
"- Приветствие клиента;\n"
|
971 |
"- Обещания и гарантии;\n"
|
@@ -1684,8 +1735,8 @@ def check_forbidden_words(message):
|
|
1684 |
forbidden_patterns = [
|
1685 |
r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b',
|
1686 |
r'вкусный', r'дешёвый', r'продукт',
|
1687 |
-
r'спам', r'
|
1688 |
-
r'срочный', r'
|
1689 |
r'гарантия', r'успех', r'лидер'
|
1690 |
]
|
1691 |
|
@@ -1734,7 +1785,7 @@ def check_no_greeting(message):
|
|
1734 |
def check_no_promises(message):
|
1735 |
morph = pymorphy2.MorphAnalyzer()
|
1736 |
promise_patterns = [
|
1737 |
-
"обещать", "гарантировать", "обязаться"
|
1738 |
]
|
1739 |
|
1740 |
words = message.split()
|
@@ -1756,7 +1807,11 @@ def check_no_double_verbs(message):
|
|
1756 |
for i in range(len(morphs) - 1):
|
1757 |
# Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы)
|
1758 |
if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}):
|
1759 |
-
|
|
|
|
|
|
|
|
|
1760 |
return True
|
1761 |
|
1762 |
# 6. Причастия и причастные обороты
|
@@ -1874,7 +1929,7 @@ def check_no_introductory_phrases(message):
|
|
1874 |
|
1875 |
def check_no_amplifiers(message):
|
1876 |
amplifiers = [
|
1877 |
-
r'\b(
|
1878 |
]
|
1879 |
|
1880 |
for pattern in amplifiers:
|
@@ -1886,7 +1941,7 @@ def check_no_amplifiers(message):
|
|
1886 |
|
1887 |
def check_no_time_parasites(message):
|
1888 |
time_parasites = [
|
1889 |
-
r'\b(
|
1890 |
]
|
1891 |
|
1892 |
for pattern in time_parasites:
|
@@ -1936,8 +1991,7 @@ def check_no_compound_sentences(message):
|
|
1936 |
r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b',
|
1937 |
r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b',
|
1938 |
r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b',
|
1939 |
-
r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b'
|
1940 |
-
r'\bчто\b'
|
1941 |
]
|
1942 |
|
1943 |
# Убедимся, что слово "как" используется не в вопросе
|
@@ -1967,6 +2021,40 @@ def check_no_dates_written_out(message):
|
|
1967 |
|
1968 |
return True
|
1969 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1970 |
# ФУНКЦИИ ПРОВЕРОК (КОНЕЦ)
|
1971 |
|
1972 |
def safe_check(func, message):
|
@@ -1995,7 +2083,8 @@ def perform_checks(message):
|
|
1995 |
"multiple_nouns": safe_check(check_no_multiple_nouns, message),
|
1996 |
"derived_prepositions": safe_check(check_no_derived_prepositions, message),
|
1997 |
"compound_sentences": safe_check(check_no_compound_sentences, message),
|
1998 |
-
"dates_written_out": safe_check(check_no_dates_written_out, message)
|
|
|
1999 |
}
|
2000 |
return checks
|
2001 |
|
@@ -2019,7 +2108,8 @@ def format_checks(checks):
|
|
2019 |
"multiple_nouns": "Несколько существительных подряд",
|
2020 |
"derived_prepositions": "Производные предлоги",
|
2021 |
"compound_sentences": "Сложноподчиненные предложения",
|
2022 |
-
"dates_written_out": "Даты прописью"
|
|
|
2023 |
}
|
2024 |
formatted_results = []
|
2025 |
for rule, result in checks.items():
|
@@ -2110,7 +2200,7 @@ with gr.Blocks() as demo:
|
|
2110 |
"Лимиты на расходы сотрудников.\n"
|
2111 |
"Мгновенные переводы на карты любых банков.\n "
|
2112 |
"В тексте смс запрещено использование:\n"
|
2113 |
-
"- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам,
|
2114 |
"- Обращение к клиенту;\n"
|
2115 |
"- Приветствие клиента;\n"
|
2116 |
"- Обещания и гарантии;\n"
|
@@ -2232,7 +2322,7 @@ with gr.Blocks() as demo:
|
|
2232 |
with gr.TabItem("Аналитика", id=1):
|
2233 |
|
2234 |
with gr.Row():
|
2235 |
-
download_btn = gr.Button("Выгрузить актуальную базу сообщений (~
|
2236 |
download_link = gr.Markdown(value="", label="Ссылка для скачивания")
|
2237 |
|
2238 |
gr.Markdown("---")
|
@@ -2256,6 +2346,15 @@ with gr.Blocks() as demo:
|
|
2256 |
|
2257 |
gr.Markdown("---")
|
2258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2259 |
# Очистка всех полей кроме prompt_display
|
2260 |
description_input.change(
|
2261 |
fn=clear_outputs, # Сначала вызываем функцию очистки полей
|
@@ -2327,6 +2426,10 @@ with gr.Blocks() as demo:
|
|
2327 |
fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта
|
2328 |
inputs=[description_input, advantages_input, key_message_input, approach_input] + selections,
|
2329 |
outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта
|
|
|
|
|
|
|
|
|
2330 |
)
|
2331 |
|
2332 |
# Очистка всех полей кроме prompt_display
|
@@ -2558,7 +2661,7 @@ with gr.Blocks() as demo:
|
|
2558 |
# Очищаем все персонализированные сообщения и результаты проверок
|
2559 |
selection.change(
|
2560 |
fn=clear_outputs,
|
2561 |
-
inputs=[
|
2562 |
personalized_output_text_gigachat_pro,
|
2563 |
personalized_output_text_gigachat_lite,
|
2564 |
personalized_output_text_gigachat_plus,
|
@@ -2617,7 +2720,7 @@ with gr.Blocks() as demo:
|
|
2617 |
outputs=personalization_prompt # Обновляем поле с персонализированным промптом
|
2618 |
).then(
|
2619 |
fn=update_best_example_prompt,
|
2620 |
-
inputs=selections,
|
2621 |
outputs=best_example_prompt
|
2622 |
)
|
2623 |
|
@@ -2774,6 +2877,7 @@ with gr.Blocks() as demo:
|
|
2774 |
best_example_btn.click(
|
2775 |
fn=adapt_messages_and_perform_checks,
|
2776 |
inputs=[
|
|
|
2777 |
personalized_output_text_gigachat_pro,
|
2778 |
personalized_output_text_gigachat_lite,
|
2779 |
personalized_output_text_gigachat_plus,
|
@@ -2943,70 +3047,70 @@ with gr.Blocks() as demo:
|
|
2943 |
personalize_message_gigachat_pro,
|
2944 |
inputs=[output_text_gigachat_pro, key_message_input, approach_input] + selections,
|
2945 |
outputs=[personalized_output_text_gigachat_pro, validation_display_1]
|
2946 |
-
).then(
|
2947 |
-
fn=generate_personalization_prompt, # Вызов генерации промпта
|
2948 |
-
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
2949 |
-
outputs=personalization_prompt # Вывод в поле с промптом
|
2950 |
).then(
|
2951 |
fn=lambda: (""),
|
2952 |
inputs=[],
|
2953 |
outputs=[adapted_output_text_gigachat_pro]
|
|
|
|
|
|
|
|
|
2954 |
)
|
2955 |
|
2956 |
personalize_gigachat_lite_btn.click(
|
2957 |
personalize_message_gigachat_lite,
|
2958 |
inputs=[output_text_gigachat_lite, key_message_input, approach_input] + selections,
|
2959 |
outputs=[personalized_output_text_gigachat_lite, validation_display_2] # Поле для проверки
|
2960 |
-
).then(
|
2961 |
-
fn=generate_personalization_prompt, # Вызов генерации промпта
|
2962 |
-
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
2963 |
-
outputs=personalization_prompt # Вывод в поле с промптом
|
2964 |
).then(
|
2965 |
fn=lambda: (""),
|
2966 |
inputs=[],
|
2967 |
outputs=[adapted_output_text_gigachat_lite]
|
|
|
|
|
|
|
|
|
2968 |
)
|
2969 |
|
2970 |
personalize_gigachat_plus_btn.click(
|
2971 |
personalize_message_gigachat_plus,
|
2972 |
inputs=[output_text_gigachat_plus, key_message_input, approach_input] + selections,
|
2973 |
outputs=[personalized_output_text_gigachat_plus, validation_display_3] # Добавляем результат проверки
|
2974 |
-
).then(
|
2975 |
-
fn=generate_personalization_prompt, # Вызов генерации промпта
|
2976 |
-
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
2977 |
-
outputs=personalization_prompt # Вывод в поле с промптом
|
2978 |
).then(
|
2979 |
fn=lambda: (""),
|
2980 |
inputs=[],
|
2981 |
outputs=[adapted_output_text_gigachat_plus]
|
|
|
|
|
|
|
|
|
2982 |
)
|
2983 |
|
2984 |
personalize_gpt4o_btn.click(
|
2985 |
personalize_message_gpt4o,
|
2986 |
inputs=[output_text_gpt4o, key_message_input, approach_input] + selections,
|
2987 |
outputs=[personalized_output_text_gpt4o, validation_display_4] # Добавляем результат проверки
|
2988 |
-
).then(
|
2989 |
-
fn=generate_personalization_prompt, # Вызов генерации промпта
|
2990 |
-
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
2991 |
-
outputs=personalization_prompt # Вывод в поле с промптом
|
2992 |
).then(
|
2993 |
fn=lambda: (""),
|
2994 |
inputs=[],
|
2995 |
outputs=[adapted_output_text_gpt4o]
|
|
|
|
|
|
|
|
|
2996 |
)
|
2997 |
|
2998 |
personalize_meta_llama_405b_btn.click(
|
2999 |
personalize_message_meta_llama_405b,
|
3000 |
inputs=[output_text_meta_llama_405b, key_message_input, approach_input] + selections,
|
3001 |
outputs=[personalized_output_text_meta_llama_405b, validation_display_5] # Добавляем результат проверки
|
3002 |
-
).then(
|
3003 |
-
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3004 |
-
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3005 |
-
outputs=personalization_prompt # Вывод в поле с промптом
|
3006 |
).then(
|
3007 |
fn=lambda: (""),
|
3008 |
inputs=[],
|
3009 |
outputs=[adapted_output_text_meta_llama_405b]
|
|
|
|
|
|
|
|
|
3010 |
)
|
3011 |
|
3012 |
|
|
|
17 |
import io
|
18 |
from datetime import datetime, timedelta
|
19 |
import plotly.express as px
|
20 |
+
from sklearn.feature_extraction.text import TfidfVectorizer
|
21 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
22 |
+
from sentence_transformers import SentenceTransformer, util
|
23 |
+
import numpy as np
|
24 |
+
|
25 |
|
26 |
morph = pymorphy2.MorphAnalyzer()
|
27 |
|
|
|
35 |
client = Together(api_key=TOGETHER_API_KEY)
|
36 |
|
37 |
# Авторизация в сервисе GigaChat
|
38 |
+
chat_pro = GigaChat(credentials=gc_key, model='GigaChat-Pro', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
|
39 |
chat_lite = GigaChat(credentials=gc_key, model='GigaChat', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
|
40 |
chat_plus = GigaChat(credentials=gc_key, model='GigaChat-Plus', max_tokens=68, temperature=1.15, verify_ssl_certs=False)
|
41 |
|
|
|
509 |
# Join the sentences back
|
510 |
text = ' '.join(sentences)
|
511 |
|
512 |
+
def restore_yo(text):
|
513 |
+
morph = pymorphy2.MorphAnalyzer()
|
514 |
+
words = text.split()
|
515 |
+
restored_words = []
|
516 |
+
|
517 |
+
for word in words:
|
518 |
+
parsed = morph.parse(word)[0]
|
519 |
+
restored_word = parsed.word
|
520 |
+
|
521 |
+
# Сохраняем оригинальный регистр первой буквы
|
522 |
+
if word and word[0].isupper():
|
523 |
+
restored_word = restored_word.capitalize()
|
524 |
+
|
525 |
+
restored_words.append(restored_word)
|
526 |
+
|
527 |
+
return ' '.join(restored_words)
|
528 |
+
|
529 |
+
text = restore_yo(text)
|
530 |
+
|
531 |
return text
|
532 |
|
533 |
|
|
|
716 |
return "", "", "", "", "", "", "", "", "", "", None, None, None, None, None, None
|
717 |
|
718 |
|
719 |
+
def get_reference_message(current_description, gender, generation, psychotype, business_stage, industry, legal_form):
|
720 |
import io
|
721 |
+
import numpy as np
|
722 |
+
from sentence_transformers import SentenceTransformer
|
723 |
repo = "fruitpicker01/Storage_dev"
|
724 |
file_path = "messages.csv"
|
|
|
725 |
url = f"https://api.github.com/repos/{repo}/contents/{file_path}"
|
726 |
headers = {
|
727 |
"Authorization": f"token {token}",
|
728 |
"Content-Type": "application/json"
|
729 |
}
|
|
|
730 |
response = requests.get(url, headers=headers)
|
|
|
731 |
if response.status_code == 200:
|
732 |
content = response.json()
|
733 |
file_content = base64.b64decode(content['content'])
|
|
|
736 |
print(f"Error accessing the file: {response.status_code}")
|
737 |
return None
|
738 |
|
|
|
739 |
for col in ["Пол", "Поколение", "Психотип", "Стадия бизнеса", "Отрасль", "ОПФ"]:
|
740 |
df[col] = df[col].astype(str).str.strip().str.lower()
|
741 |
|
|
|
742 |
params = {
|
743 |
"Пол": str(gender).strip().lower() if gender else None,
|
744 |
"Поколение": str(generation).strip().lower() if generation else None,
|
|
|
748 |
"ОПФ": str(legal_form).strip().lower() if legal_form else None
|
749 |
}
|
750 |
|
751 |
+
df = df[df["Комментарий"].isna() | (df["Комментарий"].str.strip() == '')]
|
752 |
+
|
753 |
filter_conditions = []
|
754 |
for col, value in params.items():
|
755 |
if value and value.lower() != 'none':
|
|
|
759 |
print("Не заданы параметры персонализации.")
|
760 |
return None
|
761 |
|
|
|
762 |
filter_condition = filter_conditions[0]
|
763 |
for condition in filter_conditions[1:]:
|
764 |
filter_condition &= condition
|
|
|
769 |
print("Сообщения с заданными параметрами не найдены.")
|
770 |
return None
|
771 |
|
772 |
+
if 'Описание предложения' not in filtered_df.columns:
|
773 |
+
print("Описание предложения отсутствует в данных.")
|
774 |
+
return None
|
775 |
+
|
776 |
+
filtered_df['Описание предложения'] = filtered_df['Описание предложения'].fillna('')
|
777 |
+
|
778 |
+
# Используем модель для получения эмбеддингов
|
779 |
+
model = SentenceTransformer('sergeyzh/rubert-tiny-turbo')
|
780 |
+
descriptions = filtered_df['Описание п��едложения'].tolist()
|
781 |
+
descriptions.insert(0, current_description) # Добавляем текущее описание
|
782 |
+
|
783 |
+
embeddings = model.encode(descriptions)
|
784 |
+
cosine_similarities = cosine_similarity([embeddings[0]], embeddings[1:]).flatten()
|
785 |
+
|
786 |
+
# Находим максимальное косинусное сходство
|
787 |
+
max_similarity = cosine_similarities.max()
|
788 |
|
789 |
+
# Находим индексы с максимальным сходством
|
790 |
+
max_similarity_indices = np.where(cosine_similarities == max_similarity)[0]
|
791 |
|
792 |
+
# Получаем строки с максимальным сходством
|
793 |
+
similar_rows = filtered_df.iloc[max_similarity_indices]
|
794 |
+
|
795 |
+
# Обработка Timestamp
|
796 |
+
if 'Timestamp' not in similar_rows.columns:
|
797 |
+
print("Столбец 'Timestamp' отсутствует в данных.")
|
798 |
+
similar_row = similar_rows.iloc[0]
|
799 |
else:
|
800 |
+
similar_rows = similar_rows.copy()
|
801 |
+
similar_rows['Timestamp'] = pd.to_numeric(similar_rows['Timestamp'], errors='coerce')
|
802 |
+
similar_rows = similar_rows.sort_values(by='Timestamp', ascending=False)
|
803 |
+
similar_row = similar_rows.iloc[0]
|
804 |
|
805 |
+
if pd.notnull(similar_row.get("Откорректированное сообщение", None)) and similar_row["Откорректированное сообщение"].strip():
|
806 |
+
reference_message = similar_row["Откорректированное сообщение"]
|
807 |
+
else:
|
808 |
+
reference_message = similar_row.get("Персонализированное сообщение", "")
|
809 |
|
810 |
+
reference_message = re.sub(r'\n-{6,}\nКоличество знаков: \d+', '', reference_message).strip()
|
811 |
return reference_message
|
812 |
|
813 |
|
814 |
def adapt_messages_to_best_example(
|
815 |
+
description,
|
816 |
personalized_gigachat_pro,
|
817 |
personalized_gigachat_lite,
|
818 |
personalized_gigachat_plus,
|
|
|
831 |
legal_form = selected_values[5]
|
832 |
|
833 |
# Получение эталонного сообщения (без изменений)
|
834 |
+
reference_message = get_reference_message(description, gender, generation, psychotype, business_stage, industry, legal_form)
|
835 |
|
836 |
if not reference_message:
|
837 |
# Если эталонное сообщение не найдено
|
|
|
841 |
# Шаблон промпта (без изменений)
|
842 |
prompt_template = (
|
843 |
"Сообщение для адаптации:\n\"{personalized_message}\"\n\n"
|
844 |
+
"Эталонное сообщение (НЕ ИСПОЛЬЗУЙ ФАКТЫ ИЛИ ДАННЫЕ ИЗ НИЖЕПРИВЕДЕННОГО СООБЩЕНИЯ):\n\"{reference_message}\"\n\n"
|
845 |
+
"1. Перепиши сообщение для адаптации, сохранив его смысл."
|
846 |
+
"2. Используй стиль, построение предложений и лексику, максимально похожие на эталонное сообщение."
|
847 |
+
"3. НЕ ДОБАВЛЯЙ факты, цифры, или ��юбую информацию из эталонного сообщения."
|
848 |
+
"4. Убедись, что итоговое сообщение содержит ТОЛЬКО информацию из сообщения для адаптации и адаптировано по стилю и структуре."
|
849 |
+
"5. Проверь, что итоговое сообщение включает следующую информацию: \n\"{key_message}\"\n"
|
850 |
)
|
851 |
+
|
852 |
# Инициализация пустых переменных для сообщений
|
853 |
adapted_gigachat_pro = ""
|
854 |
adapted_gigachat_lite = ""
|
|
|
912 |
yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, adapted_gigachat_plus_display, adapted_gpt4o_display, adapted_meta_llama_405b_display
|
913 |
|
914 |
|
915 |
+
def update_best_example_prompt(description, *selected_values):
|
916 |
# Extract personalization parameters
|
917 |
gender = selected_values[0]
|
918 |
generation = selected_values[1]
|
|
|
922 |
legal_form = selected_values[5]
|
923 |
|
924 |
# Retrieve the reference message
|
925 |
+
reference_message = get_reference_message(description, gender, generation, psychotype, business_stage, industry, legal_form)
|
926 |
|
927 |
if not reference_message:
|
928 |
# No reference message found
|
929 |
best_prompt = "Эталонное сообщение не найдено для выбранных параметров персонализации."
|
930 |
else:
|
931 |
best_prompt = (
|
932 |
+
"Эталонное сообщение (НЕ ИСПОЛЬЗУЙ ФАКТЫ ИЛИ ДАННЫЕ ИЗ НИЖЕПРИВЕДЕННОГО СООБЩЕНИЯ):\n\"{reference_message}\"\n\n"
|
933 |
+
"1. Перепиши сообщение для адаптации, сохранив его смысл.\n"
|
934 |
+
"2. Используй стиль, построение предложений и лексику, максимально похожие на эталонное сообщение.\n"
|
935 |
+
"3. НЕ ДОБАВЛЯЙ факты, цифры, или любую информацию из эталонного сообщения.\n"
|
936 |
+
"4. Убедись, что итоговое сообщение содержит ТОЛЬКО информацию из сообщения для адаптации и адаптировано по стилю и структуре."
|
937 |
+
).format(reference_message=reference_message)
|
938 |
+
|
939 |
return best_prompt
|
940 |
|
941 |
def adapt_messages_and_perform_checks(
|
942 |
+
description_input,
|
943 |
personalized_gigachat_pro,
|
944 |
personalized_gigachat_lite,
|
945 |
personalized_gigachat_plus,
|
|
|
950 |
*selected_values
|
951 |
):
|
952 |
adaptation_generator = adapt_messages_to_best_example(
|
953 |
+
description_input,
|
954 |
personalized_gigachat_pro,
|
955 |
personalized_gigachat_lite,
|
956 |
personalized_gigachat_plus,
|
|
|
1016 |
f"Описание предложения: {description}\n"
|
1017 |
f"Преимущества: {advantages}\n"
|
1018 |
"В тексте смс запрещено использование:\n"
|
1019 |
+
"- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, банкротство, долги, займ, срочно, лучший, главный, номер 1, гарантия, успех, лидер;\n"
|
1020 |
"- Обращение к клиенту;\n"
|
1021 |
"- Приветствие клиента;\n"
|
1022 |
"- Обещания и гарантии;\n"
|
|
|
1735 |
forbidden_patterns = [
|
1736 |
r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b',
|
1737 |
r'вкусный', r'дешёвый', r'продукт',
|
1738 |
+
r'спам', r'банкротство', r'долг[и]?', r'займ',
|
1739 |
+
r'срочный', r'главный',
|
1740 |
r'гарантия', r'успех', r'лидер'
|
1741 |
]
|
1742 |
|
|
|
1785 |
def check_no_promises(message):
|
1786 |
morph = pymorphy2.MorphAnalyzer()
|
1787 |
promise_patterns = [
|
1788 |
+
"обещать", "обещание", "гарантировать", "обязаться", "обязать", "обязательство", "обязательный"
|
1789 |
]
|
1790 |
|
1791 |
words = message.split()
|
|
|
1807 |
for i in range(len(morphs) - 1):
|
1808 |
# Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы)
|
1809 |
if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}):
|
1810 |
+
# Проверяем, является ли первый глагол "хотеть" или "начинать"
|
1811 |
+
if morphs[i].normal_form in ['хотеть', 'начинать', 'начать']:
|
1812 |
+
return True
|
1813 |
+
else:
|
1814 |
+
return False
|
1815 |
return True
|
1816 |
|
1817 |
# 6. Причастия и причастные обороты
|
|
|
1929 |
|
1930 |
def check_no_amplifiers(message):
|
1931 |
amplifiers = [
|
1932 |
+
r'\b(очень|крайне|чрезвычайно|совсем|полностью|чисто)\b'
|
1933 |
]
|
1934 |
|
1935 |
for pattern in amplifiers:
|
|
|
1941 |
|
1942 |
def check_no_time_parasites(message):
|
1943 |
time_parasites = [
|
1944 |
+
r'\b(немедленно|срочно|в данный момент|теперь)\b'
|
1945 |
]
|
1946 |
|
1947 |
for pattern in time_parasites:
|
|
|
1991 |
r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b',
|
1992 |
r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b',
|
1993 |
r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b',
|
1994 |
+
r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b'
|
|
|
1995 |
]
|
1996 |
|
1997 |
# Убедимся, что слово "как" используется не в вопросе
|
|
|
2021 |
|
2022 |
return True
|
2023 |
|
2024 |
+
# Доп правило. Повторы слов
|
2025 |
+
|
2026 |
+
def check_no_word_repetitions(message):
|
2027 |
+
morph = pymorphy2.MorphAnalyzer()
|
2028 |
+
|
2029 |
+
# Список союзов и предлогов, которые мы будем игнорировать
|
2030 |
+
ignore_words = set([
|
2031 |
+
'и', 'а', 'но', 'или', 'да', 'ни', 'как', 'так',
|
2032 |
+
'в', 'на', 'под', 'над', 'за', 'к', 'до', 'по', 'из', 'у', 'о', 'про', 'для',
|
2033 |
+
'не', 'вот', 'это', 'тот', 'тем', 'при', 'чем',
|
2034 |
+
'же', 'ли', 'бы', 'то',
|
2035 |
+
])
|
2036 |
+
|
2037 |
+
# Разбиваем текст на слова, удаляя знаки препинания
|
2038 |
+
words = re.findall(r'\b\w+\b', message.lower())
|
2039 |
+
|
2040 |
+
# Словарь для хранения нормализованных форм слов
|
2041 |
+
normalized_words = {}
|
2042 |
+
|
2043 |
+
for word in words:
|
2044 |
+
if word not in ignore_words:
|
2045 |
+
# Получаем нормальную форму слова
|
2046 |
+
normal_form = morph.parse(word)[0].normal_form
|
2047 |
+
|
2048 |
+
# Если слово уже встречалось, возвращаем False
|
2049 |
+
if normal_form in normalized_words:
|
2050 |
+
return False
|
2051 |
+
|
2052 |
+
# Добавляем слово в словарь
|
2053 |
+
normalized_words[normal_form] = True
|
2054 |
+
|
2055 |
+
# Если мы дошли до этой точки, повторов не было
|
2056 |
+
return True
|
2057 |
+
|
2058 |
# ФУНКЦИИ ПРОВЕРОК (КОНЕЦ)
|
2059 |
|
2060 |
def safe_check(func, message):
|
|
|
2083 |
"multiple_nouns": safe_check(check_no_multiple_nouns, message),
|
2084 |
"derived_prepositions": safe_check(check_no_derived_prepositions, message),
|
2085 |
"compound_sentences": safe_check(check_no_compound_sentences, message),
|
2086 |
+
"dates_written_out": safe_check(check_no_dates_written_out, message),
|
2087 |
+
"no_word_repetitions": safe_check(check_no_word_repetitions, message)
|
2088 |
}
|
2089 |
return checks
|
2090 |
|
|
|
2108 |
"multiple_nouns": "Несколько существительных подряд",
|
2109 |
"derived_prepositions": "Производные предлоги",
|
2110 |
"compound_sentences": "Сложноподчиненные предложения",
|
2111 |
+
"dates_written_out": "Даты прописью",
|
2112 |
+
"no_word_repetitions": "Повторы слов"
|
2113 |
}
|
2114 |
formatted_results = []
|
2115 |
for rule, result in checks.items():
|
|
|
2200 |
"Лимиты на расходы сотрудников.\n"
|
2201 |
"Мгновенные переводы на карты любых банков.\n "
|
2202 |
"В тексте смс запрещено использование:\n"
|
2203 |
+
"- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, банкротство, долги, займ, срочно, лучший, главный, номер 1, гарантия, успех, лидер;\n"
|
2204 |
"- Обращение к клиенту;\n"
|
2205 |
"- Приветствие клиента;\n"
|
2206 |
"- Обещания и гарантии;\n"
|
|
|
2322 |
with gr.TabItem("Аналитика", id=1):
|
2323 |
|
2324 |
with gr.Row():
|
2325 |
+
download_btn = gr.Button("Выгрузить актуальную базу сообщений (~ 45 сек)")
|
2326 |
download_link = gr.Markdown(value="", label="Ссылка для скачивания")
|
2327 |
|
2328 |
gr.Markdown("---")
|
|
|
2346 |
|
2347 |
gr.Markdown("---")
|
2348 |
|
2349 |
+
with gr.TabItem("Инструкция", id=2):
|
2350 |
+
gr.Markdown("""
|
2351 |
+
### Инструкция
|
2352 |
+
Функционал адаптации сообщений под лучший пример — в beta-версии.
|
2353 |
+
Если вы сгенерировали адаптированное сообщение, и оно вам понравилось (вы хотите сохранить его в базу), то скопируйте его, пожалуйста, в поле "Откорректированное сообщение" (а поле "Комментарий" оставьте пустым).
|
2354 |
+
|
2355 |
+
Когда вы нажимаете адаптировать, то результаты проверок ниже обновляются и приводятся для адаптированных (а не персонализированных) сообщений.
|
2356 |
+
""")
|
2357 |
+
|
2358 |
# Очистка всех полей кроме prompt_display
|
2359 |
description_input.change(
|
2360 |
fn=clear_outputs, # Сначала вызываем функцию очистки полей
|
|
|
2426 |
fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта
|
2427 |
inputs=[description_input, advantages_input, key_message_input, approach_input] + selections,
|
2428 |
outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта
|
2429 |
+
).then(
|
2430 |
+
fn=update_best_example_prompt,
|
2431 |
+
inputs=[description_input] + selections,
|
2432 |
+
outputs=best_example_prompt
|
2433 |
)
|
2434 |
|
2435 |
# Очистка всех полей кроме prompt_display
|
|
|
2661 |
# Очищаем все персонализированные сообщения и результаты проверок
|
2662 |
selection.change(
|
2663 |
fn=clear_outputs,
|
2664 |
+
inputs=[
|
2665 |
personalized_output_text_gigachat_pro,
|
2666 |
personalized_output_text_gigachat_lite,
|
2667 |
personalized_output_text_gigachat_plus,
|
|
|
2720 |
outputs=personalization_prompt # Обновляем поле с персонализированным промптом
|
2721 |
).then(
|
2722 |
fn=update_best_example_prompt,
|
2723 |
+
inputs=[description_input] + selections,
|
2724 |
outputs=best_example_prompt
|
2725 |
)
|
2726 |
|
|
|
2877 |
best_example_btn.click(
|
2878 |
fn=adapt_messages_and_perform_checks,
|
2879 |
inputs=[
|
2880 |
+
description_input,
|
2881 |
personalized_output_text_gigachat_pro,
|
2882 |
personalized_output_text_gigachat_lite,
|
2883 |
personalized_output_text_gigachat_plus,
|
|
|
3047 |
personalize_message_gigachat_pro,
|
3048 |
inputs=[output_text_gigachat_pro, key_message_input, approach_input] + selections,
|
3049 |
outputs=[personalized_output_text_gigachat_pro, validation_display_1]
|
|
|
|
|
|
|
|
|
3050 |
).then(
|
3051 |
fn=lambda: (""),
|
3052 |
inputs=[],
|
3053 |
outputs=[adapted_output_text_gigachat_pro]
|
3054 |
+
).then(
|
3055 |
+
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3056 |
+
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3057 |
+
outputs=personalization_prompt # Вывод в поле с промптом
|
3058 |
)
|
3059 |
|
3060 |
personalize_gigachat_lite_btn.click(
|
3061 |
personalize_message_gigachat_lite,
|
3062 |
inputs=[output_text_gigachat_lite, key_message_input, approach_input] + selections,
|
3063 |
outputs=[personalized_output_text_gigachat_lite, validation_display_2] # Поле для проверки
|
|
|
|
|
|
|
|
|
3064 |
).then(
|
3065 |
fn=lambda: (""),
|
3066 |
inputs=[],
|
3067 |
outputs=[adapted_output_text_gigachat_lite]
|
3068 |
+
).then(
|
3069 |
+
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3070 |
+
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3071 |
+
outputs=personalization_prompt # Вывод в поле с промптом
|
3072 |
)
|
3073 |
|
3074 |
personalize_gigachat_plus_btn.click(
|
3075 |
personalize_message_gigachat_plus,
|
3076 |
inputs=[output_text_gigachat_plus, key_message_input, approach_input] + selections,
|
3077 |
outputs=[personalized_output_text_gigachat_plus, validation_display_3] # Добавляем результат проверки
|
|
|
|
|
|
|
|
|
3078 |
).then(
|
3079 |
fn=lambda: (""),
|
3080 |
inputs=[],
|
3081 |
outputs=[adapted_output_text_gigachat_plus]
|
3082 |
+
).then(
|
3083 |
+
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3084 |
+
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3085 |
+
outputs=personalization_prompt # Вывод в поле с промптом
|
3086 |
)
|
3087 |
|
3088 |
personalize_gpt4o_btn.click(
|
3089 |
personalize_message_gpt4o,
|
3090 |
inputs=[output_text_gpt4o, key_message_input, approach_input] + selections,
|
3091 |
outputs=[personalized_output_text_gpt4o, validation_display_4] # Добавляем результат проверки
|
|
|
|
|
|
|
|
|
3092 |
).then(
|
3093 |
fn=lambda: (""),
|
3094 |
inputs=[],
|
3095 |
outputs=[adapted_output_text_gpt4o]
|
3096 |
+
).then(
|
3097 |
+
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3098 |
+
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3099 |
+
outputs=personalization_prompt # Вывод в поле с промптом
|
3100 |
)
|
3101 |
|
3102 |
personalize_meta_llama_405b_btn.click(
|
3103 |
personalize_message_meta_llama_405b,
|
3104 |
inputs=[output_text_meta_llama_405b, key_message_input, approach_input] + selections,
|
3105 |
outputs=[personalized_output_text_meta_llama_405b, validation_display_5] # Добавляем результат проверки
|
|
|
|
|
|
|
|
|
3106 |
).then(
|
3107 |
fn=lambda: (""),
|
3108 |
inputs=[],
|
3109 |
outputs=[adapted_output_text_meta_llama_405b]
|
3110 |
+
).then(
|
3111 |
+
fn=generate_personalization_prompt, # Вызов генерации промпта
|
3112 |
+
inputs=[key_message_input, approach_input] + selections, # Передача нужных данных
|
3113 |
+
outputs=personalization_prompt # Вывод в поле с промптом
|
3114 |
)
|
3115 |
|
3116 |
|