fruitpicker01 commited on
Commit
cbd204e
·
verified ·
1 Parent(s): aace91f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -68
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
- filtered_df = filtered_df.sort_values(by="Timestamp", ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
754
 
755
- # Берем последнее сообщение
756
- latest_row = filtered_df.iloc[0]
757
 
758
- # Получаем сообщение
759
- if pd.notnull(latest_row.get("Откорректированное сообщение", None)) and latest_row["Откорректированное сообщение"].strip():
760
- reference_message = latest_row["Откорректированное сообщение"]
 
 
 
 
761
  else:
762
- reference_message = latest_row.get("Персонализированное сообщение", "")
 
 
 
763
 
764
- # Удаляем строку с количеством знаков
765
- reference_message = re.sub(r'\n-{6,}\nКоличество знаков: \d+', '', reference_message).strip()
 
 
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
- "Эталонное сообщение:\n\"{reference_message}\"\n\n"
800
- "Перепиши сообщение для адаптации, сохраняя его смысл, но используя стиль и построение предложений, максимально похожие на эталонное сообщение. НИ В КОЕМ СЛУЧАЕ НЕ ДОБАВЛЯЙ ИНФОРМАЦИЮ ИЗ ЭТАЛОННОГО СООБЩЕНИЯ.\n"
801
- "Перед ответом убедись, что в твоем итоговом сообщении информация из сообщения для адаптации, а не из эталонного сообщения."
802
- "Убедись, что итоговое сообщение максимально адаптировано под стиль и построение предложений эталонного сообщения."
803
- "Убедись, что в итоговом сообщении есть следующая информация: \n\"{key_message}\"\n"
 
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
- f"Эталонное сообщение:\n\"{reference_message}\"\n\n"
887
- "Перепиши сообщение для адаптации, сохраняя его смысл, но используя стиль и построение предложений, максимально похожие на эталонное сообщение. НИ В КОЕМ СЛУЧАЕ НЕ ДОБАВЛЯЙ ИНФОРМАЦИЮ ИЗ ЭТАЛОННОГО СООБЩЕНИЯ.\n"
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, вкусный, дешёвый, продукт, спам, доступный, банкротство, долги, займ, срочно, сейчас, лучший, главный, номер 1, гарантия, успех, лидер;\n"
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'доступный', r'банкротство', r'долг[и]?', r'займ',
1688
- r'срочный', 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
- return False
 
 
 
 
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(очень|крайне|чрезвычайно|совсем|абсолютно|полностью|чисто)\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(сейчас|немедленно|срочно|в данный момент|теперь)\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, вкусный, дешёвый, продукт, спам, доступный, банкротство, долги, займ, срочно, сейчас, лучший, главный, номер 1, гарантия, успех, лидер;\n"
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("Выгрузить актуальную базу сообщений (~ 30 сек)")
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