fruitpicker01 commited on
Commit
891644e
·
verified ·
1 Parent(s): c2c8e95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -25
app.py CHANGED
@@ -2,6 +2,8 @@ import gradio as gr
2
  import pandas as pd
3
  import os
4
  import random
 
 
5
  from openai import OpenAI
6
 
7
  XAI_API_KEY = os.getenv("XAI_API_KEY")
@@ -16,7 +18,10 @@ def load_dropdown_data(file_path, sheet_name, column_name):
16
 
17
  file_path = "Исходные данные.xlsx"
18
 
19
- products, data_products = load_dropdown_data(file_path, "Продукты", "Наименование продукта"), pd.read_excel(file_path, sheet_name="Продукты")
 
 
 
20
  genders_data = pd.read_excel(file_path, sheet_name="Пол")
21
  generations_data = pd.read_excel(file_path, sheet_name="Поколение")
22
  psychotypes_data = pd.read_excel(file_path, sheet_name="Психотип")
@@ -49,15 +54,25 @@ approach_dict = {
49
  }
50
 
51
  def fill_product_details(selected_product, data):
52
- if selected_product:
53
- product_row = data[data["Наименование продукта"] == selected_product].iloc[0]
54
- return (
55
- product_row.get("Описание предложения", ""),
56
- product_row.get("Наименование продукта", ""),
57
- product_row.get("Преимущества", ""),
58
- product_row.get("Ключевое сообщение", "")
59
- )
60
- return "", "", "", ""
 
 
 
 
 
 
 
 
 
 
61
 
62
  def get_approaches(gender, generation, psychotype, approaches_df):
63
  if approaches_df is None or approaches_df.empty:
@@ -221,6 +236,114 @@ def call_model(model_prompt):
221
  )
222
  return completion.choices[0].message.content.strip()
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  def update_prompts_on_params_change(description, product_name, benefits, key_message,
225
  gender, generation, psychotype, business_stage, industry, opf):
226
  chosen_approach = get_approaches(gender, generation, psychotype, approaches_data)
@@ -232,10 +355,9 @@ def update_prompts_on_params_change(description, product_name, benefits, key_mes
232
  def generate_personalized_sms(description, product_name, benefits, key_message,
233
  gender, generation, psychotype, business_stage, industry, opf,
234
  chosen_approach, prompt_1, prompt_2):
235
- # Если нет персональных параметров или подхода, показываем предупреждение:
236
  if "Для формирования промпта выберите хотя бы один личный персональный параметр" in prompt_1 or chosen_approach == "Подход не найден для выбранных параметров.":
237
  gr.Warning("Задайте хотя бы один личный персональный параметр для определения подхода, чтобы был сформирован промпт")
238
- # Возвращаем пустые результаты для SMS
239
  return "", ""
240
 
241
  approach_list = [a.strip() for a in chosen_approach.split(',') if a.strip()]
@@ -253,8 +375,8 @@ def generate_personalized_sms(description, product_name, benefits, key_message,
253
  gender, generation, psychotype, business_stage, industry, opf,
254
  chosen_single_approach_2)
255
 
256
- sms_1 = call_model(model_prompt_1)
257
- sms_2 = call_model(model_prompt_2)
258
 
259
  return sms_1, sms_2
260
 
@@ -272,11 +394,11 @@ with gr.Blocks(theme="default") as demo:
272
  with gr.Row():
273
  with gr.Column(scale=1):
274
  gr.Markdown("**Продукт**")
275
- product_dropdown = gr.Dropdown(label="Продукт", choices=products, value=None)
276
- description = gr.Textbox(label="Описание предложения", lines=5, value="")
277
- product_name = gr.Textbox(label="Наименование продукта", lines=1, value="")
278
- benefits = gr.Textbox(label="Преимущества", lines=9, value="")
279
- key_message = gr.Textbox(label="Ключевое сообщение", lines=2, value="")
280
 
281
  product_dropdown.change(
282
  fn=lambda selected: fill_product_details(selected, data_products),
@@ -292,7 +414,7 @@ with gr.Blocks(theme="default") as demo:
292
  business_stage_dropdown = gr.Dropdown(label="Стадия бизнеса", choices=["Не выбрано"]+business_stages, value=None)
293
  industry_dropdown = gr.Dropdown(label="Отрасль", choices=["Не выбрано"]+industries, value=None)
294
  opf_dropdown = gr.Dropdown(label="ОПФ", choices=["Не выбрано"]+opfs, value=None)
295
- chosen_approach = gr.Textbox(label="Выбранный подход", lines=1, value="")
296
  presence_in_db = gr.Textbox(label="Комментарий", lines=1, value="", interactive=False)
297
 
298
  with gr.Row():
@@ -304,12 +426,12 @@ with gr.Blocks(theme="default") as demo:
304
  with gr.Column():
305
  model_1_name = gr.Textbox(label="Модель 1", value="Grok-2-1212", interactive=False)
306
  prompt_1 = gr.Textbox(label="Промпт 1", value="", interactive=False, lines=10)
307
- sms_1 = gr.Textbox(label="SMS 1", lines=3, value="")
308
 
309
  with gr.Column():
310
  model_2_name = gr.Textbox(label="Модель 2", value="Grok-2-1212", interactive=False)
311
  prompt_2 = gr.Textbox(label="Промпт 2", value="", interactive=False, lines=10)
312
- sms_2 = gr.Textbox(label="SMS 2", lines=3, value="")
313
 
314
  with gr.Row():
315
  prefer_sms_1_btn = gr.Button("Я предпочитаю это SMS")
@@ -341,9 +463,8 @@ with gr.Blocks(theme="default") as demo:
341
  )
342
 
343
  # Генерация SMS по нажатию кнопки
344
- # Если персональные параметры не выбраны - выдаём gr.Warning
345
  create_personal_sms_btn.click(
346
- fn=generate_personalized_sms,
347
  inputs=[description, product_name, benefits, key_message,
348
  gender_dropdown, generation_dropdown, psychotype_dropdown,
349
  business_stage_dropdown, industry_dropdown, opf_dropdown,
@@ -351,5 +472,4 @@ with gr.Blocks(theme="default") as demo:
351
  outputs=[sms_1, sms_2]
352
  )
353
 
354
- # Обязательно включаем очередь:
355
  demo.queue().launch()
 
2
  import pandas as pd
3
  import os
4
  import random
5
+ import re
6
+ import pymorphy3
7
  from openai import OpenAI
8
 
9
  XAI_API_KEY = os.getenv("XAI_API_KEY")
 
18
 
19
  file_path = "Исходные данные.xlsx"
20
 
21
+ products_list, data_products = load_dropdown_data(file_path, "Продукты", "Наименование продукта"), pd.read_excel(file_path, sheet_name="Продукты")
22
+ # Добавляем "Свой продукт" в начало списка
23
+ products = ["Свой продукт"] + list(products_list)
24
+
25
  genders_data = pd.read_excel(file_path, sheet_name="Пол")
26
  generations_data = pd.read_excel(file_path, sheet_name="Поколение")
27
  psychotypes_data = pd.read_excel(file_path, sheet_name="Психотип")
 
54
  }
55
 
56
  def fill_product_details(selected_product, data):
57
+ # Если выбран "Свой продукт", поля очищаем и даём редактировать
58
+ if selected_product == "Свой продукт":
59
+ return gr.update(value="", interactive=True), \
60
+ gr.update(value="", interactive=True), \
61
+ gr.update(value="", interactive=True), \
62
+ gr.update(value="", interactive=True)
63
+ else:
64
+ # Иначе заполняем из файла и делаем поля неактивными
65
+ if selected_product and selected_product in data["Наименование продукта"].values:
66
+ product_row = data[data["Наименование продукта"] == selected_product].iloc[0]
67
+ return (gr.update(value=product_row.get("Описание предложения", ""), interactive=False),
68
+ gr.update(value=product_row.get("Наименование продукта", ""), interactive=False),
69
+ gr.update(value=product_row.get("Преимущества", ""), interactive=False),
70
+ gr.update(value=product_row.get("Ключевое сообщение", ""), interactive=False))
71
+ else:
72
+ return gr.update(value="", interactive=False), \
73
+ gr.update(value="", interactive=False), \
74
+ gr.update(value="", interactive=False), \
75
+ gr.update(value="", interactive=False)
76
 
77
  def get_approaches(gender, generation, psychotype, approaches_df):
78
  if approaches_df is None or approaches_df.empty:
 
236
  )
237
  return completion.choices[0].message.content.strip()
238
 
239
+ # Функция для корректировки
240
+ def correct_dash_usage(text):
241
+ morph = pymorphy3.MorphAnalyzer()
242
+ text = re.sub(r'\s[-–—]\s', ' — ', text)
243
+ text = re.sub(r'(?<=\d)[-–—](?=\d)', '–', text)
244
+ text = re.sub(r'(?<=[a-zA-Zа-яА-Я0-9])[-–—](?=[a-zA-Zа-яА-Я0-9])', '-', text)
245
+ text = re.sub(r'"([^\"]+)"', r'«\1»', text)
246
+ if text.count('"') == 1:
247
+ text = text.replace('"', '')
248
+ if (text.startswith('"') and text.endswith('"')) or (text.startswith('«') and text.endswith('»')):
249
+ text = text[1:-1].strip()
250
+ text = re.sub(r'(\d+)[kкКK]', r'\1 000', text, flags=re.IGNORECASE)
251
+
252
+ greeting_patterns = [
253
+ r"привет\b", r"здравствуй", r"добрый\s(день|вечер|утро)",
254
+ r"дорогой\b", r"уважаемый\b", r"дорогая\b", r"уважаемая\b",
255
+ r"господин\b", r"госпожа\b", r"друг\b", r"коллега\b",
256
+ r"товарищ\b", r"приятель\b", r"подруга\b"
257
+ ]
258
+ def is_greeting_sentence(sentence):
259
+ words = sentence.split()
260
+ if len(words) < 5:
261
+ for word in words:
262
+ parsed = morph.parse(word.lower())[0]
263
+ for pattern in greeting_patterns:
264
+ if re.search(pattern, parsed.normal_form):
265
+ return True
266
+ return False
267
+
268
+ sentences = re.split(r'(?<=[.!?])\s+', text)
269
+ if sentences and is_greeting_sentence(sentences[0]):
270
+ sentences = sentences[1:]
271
+ text = ' '.join(sentences)
272
+
273
+ def restore_yo(text):
274
+ morph2 = pymorphy3.MorphAnalyzer()
275
+ words = text.split()
276
+ restored_words = []
277
+ for word in words:
278
+ if word.isupper():
279
+ restored_words.append(word)
280
+ continue
281
+ if word.lower() == "все":
282
+ restored_words.append(word)
283
+ continue
284
+ parsed = morph2.parse(word)[0]
285
+ restored_word = parsed.word
286
+ if word and word[0].isupper():
287
+ restored_word = restored_word.capitalize()
288
+ restored_words.append(restored_word)
289
+ return ' '.join(restored_words)
290
+
291
+ text = restore_yo(text)
292
+ text = re.sub(r'\bИп\b', 'ИП', text, flags=re.IGNORECASE)
293
+ text = re.sub(r'\bОоо\b', 'ООО', text, flags=re.IGNORECASE)
294
+ text = re.sub(r'\bРф\b', 'РФ', text, flags=re.IGNORECASE)
295
+ text = re.sub(r'\bпользовуйтесь\b', 'пользуйтесь', text, flags=re.IGNORECASE)
296
+ text = re.sub(r'\bею\b', 'ей', text, flags=re.IGNORECASE)
297
+ text = re.sub(r'\bповышьте\b', 'повысьте', text, flags=re.IGNORECASE)
298
+ text = re.sub(r'\bСбербизнес(?:а|е)?\b', 'СберБизнес', text, flags=re.IGNORECASE)
299
+ text = re.sub(r'\bСбербанк\b', 'СберБанк', text, flags=re.IGNORECASE)
300
+ text = re.sub(r'\bвашего ООО\b', 'вашей компании', text, flags=re.IGNORECASE)
301
+ text = re.sub(r'\b0₽\b', '0 р', text, flags=re.IGNORECASE)
302
+ text = re.sub(r'\b₽\b', 'р', text, flags=re.IGNORECASE)
303
+ text = re.sub(r'\bруб\.(?=\W|$)', 'р', text, flags=re.IGNORECASE)
304
+ text = re.sub(r'\bруб(?:ля|лей)\b', 'р', text, flags=re.IGNORECASE)
305
+ text = re.sub(r'(\d+)\s+тысяч(?:а|и)?(?:\s+рублей)?', r'\1 000 р', text, flags=re.IGNORECASE)
306
+ text = re.sub(r'(\d+)\s*тыс\.\s*руб\.', r'\1 000 р', text, flags=re.IGNORECASE)
307
+ text = re.sub(r'(\d+)\s*тыс\.\s*р\.?', r'\1 000 р', text, flags=re.IGNORECASE)
308
+ text = re.sub(r'(\d+)\s+миллиона\b|\bмиллионов\b', r'\1 млн', text, flags=re.IGNORECASE)
309
+ text = re.sub(r'(\d+)\s*млн\s*руб\.', r'\1 млн р', text, flags=re.IGNORECASE)
310
+ text = re.sub(r'(\d+)\s*р\b', r'\1 р', text)
311
+
312
+ def remove_specific_sentences(text):
313
+ sents = re.split(r'(?<=[.!?])\s+', text)
314
+ filtered = [s for s in sents if not re.search(r'\bникаких\s+(посещений|визитов)\b', s, re.IGNORECASE)]
315
+ return ' '.join(filtered)
316
+
317
+ text = re.sub(r'\b(\d+)\s+000\s+000\s*р\b', r'\1 млн р', text, flags=re.IGNORECASE)
318
+ text = re.sub(r' р р ', r' р ', text, flags=re.IGNORECASE)
319
+ text = remove_specific_sentences(text)
320
+ return text
321
+
322
+ def clean_message(message):
323
+ if not message.endswith(('.', '!', '?')):
324
+ last_period = max(message.rfind('.'), message.rfind('!'), message.rfind('?'))
325
+ if last_period != -1:
326
+ message = message[:last_period + 1]
327
+ return message
328
+
329
+ def generate_message_with_retry(model_prompt):
330
+ # До 10 попыток, чтобы длина была от 160 до 250 символов
331
+ last_message = ""
332
+ for _ in range(10):
333
+ msg = call_model(model_prompt)
334
+ msg = correct_dash_usage(msg)
335
+ msg = clean_message(msg)
336
+ length = len(msg)
337
+ if 160 <= length <= 250:
338
+ # Добавляем информацию о количестве знаков
339
+ msg += f"\n\n------\nКоличество знаков: {length}"
340
+ return msg
341
+ last_message = msg
342
+ # Если не удалось подобрать длину
343
+ length = len(last_message)
344
+ last_message += f"\n\n------\nКоличество знаков: {length}"
345
+ return last_message
346
+
347
  def update_prompts_on_params_change(description, product_name, benefits, key_message,
348
  gender, generation, psychotype, business_stage, industry, opf):
349
  chosen_approach = get_approaches(gender, generation, psychotype, approaches_data)
 
355
  def generate_personalized_sms(description, product_name, benefits, key_message,
356
  gender, generation, psychotype, business_stage, industry, opf,
357
  chosen_approach, prompt_1, prompt_2):
358
+ # Если нет персональных параметров или подхода
359
  if "Для формирования промпта выберите хотя бы один личный персональный параметр" in prompt_1 or chosen_approach == "Подход не найден для выбранных параметров.":
360
  gr.Warning("Задайте хотя бы один личный персональный параметр для определения подхода, чтобы был сформирован промпт")
 
361
  return "", ""
362
 
363
  approach_list = [a.strip() for a in chosen_approach.split(',') if a.strip()]
 
375
  gender, generation, psychotype, business_stage, industry, opf,
376
  chosen_single_approach_2)
377
 
378
+ sms_1 = generate_message_with_retry(model_prompt_1)
379
+ sms_2 = generate_message_with_retry(model_prompt_2)
380
 
381
  return sms_1, sms_2
382
 
 
394
  with gr.Row():
395
  with gr.Column(scale=1):
396
  gr.Markdown("**Продукт**")
397
+ product_dropdown = gr.Dropdown(label="Продукт", choices=products, value=products[0])
398
+ description = gr.Textbox(label="Описание предложения", lines=5, value="", interactive=True)
399
+ product_name = gr.Textbox(label="Наименование продукта", lines=1, value="", interactive=True)
400
+ benefits = gr.Textbox(label="Преимущества", lines=9, value="", interactive=True)
401
+ key_message = gr.Textbox(label="Ключевое сообщение", lines=2, value="", interactive=True)
402
 
403
  product_dropdown.change(
404
  fn=lambda selected: fill_product_details(selected, data_products),
 
414
  business_stage_dropdown = gr.Dropdown(label="Стадия бизнеса", choices=["Не выбрано"]+business_stages, value=None)
415
  industry_dropdown = gr.Dropdown(label="Отрасль", choices=["Не выбрано"]+industries, value=None)
416
  opf_dropdown = gr.Dropdown(label="ОПФ", choices=["Не выбрано"]+opfs, value=None)
417
+ chosen_approach = gr.Textbox(label="Выбранный подход", lines=1, value="", interactive=False)
418
  presence_in_db = gr.Textbox(label="Комментарий", lines=1, value="", interactive=False)
419
 
420
  with gr.Row():
 
426
  with gr.Column():
427
  model_1_name = gr.Textbox(label="Модель 1", value="Grok-2-1212", interactive=False)
428
  prompt_1 = gr.Textbox(label="Промпт 1", value="", interactive=False, lines=10)
429
+ sms_1 = gr.Textbox(label="SMS 1", lines=3, value="", interactive=False)
430
 
431
  with gr.Column():
432
  model_2_name = gr.Textbox(label="Модель 2", value="Grok-2-1212", interactive=False)
433
  prompt_2 = gr.Textbox(label="Промпт 2", value="", interactive=False, lines=10)
434
+ sms_2 = gr.Textbox(label="SMS 2", lines=3, value="", interactive=False)
435
 
436
  with gr.Row():
437
  prefer_sms_1_btn = gr.Button("Я предпочитаю это SMS")
 
463
  )
464
 
465
  # Генерация SMS по нажатию кнопки
 
466
  create_personal_sms_btn.click(
467
+ fn=generate_personal_sms,
468
  inputs=[description, product_name, benefits, key_message,
469
  gender_dropdown, generation_dropdown, psychotype_dropdown,
470
  business_stage_dropdown, industry_dropdown, opf_dropdown,
 
472
  outputs=[sms_1, sms_2]
473
  )
474
 
 
475
  demo.queue().launch()