Spaces:
Sleeping
Sleeping
import gradio as gr | |
import pandas as pd | |
import os | |
import random | |
from openai import OpenAI | |
XAI_API_KEY = os.getenv("XAI_API_KEY") | |
client = OpenAI( | |
api_key=XAI_API_KEY, | |
base_url="https://api.x.ai/v1", | |
) | |
def load_dropdown_data(file_path, sheet_name, column_name): | |
data = pd.read_excel(file_path, sheet_name=sheet_name) | |
return data[column_name].dropna().unique().tolist() | |
file_path = "Исходные данные.xlsx" | |
products, data_products = load_dropdown_data(file_path, "Продукты", "Наименование продукта"), pd.read_excel(file_path, sheet_name="Продукты") | |
genders_data = pd.read_excel(file_path, sheet_name="Пол") | |
generations_data = pd.read_excel(file_path, sheet_name="Поколение") | |
psychotypes_data = pd.read_excel(file_path, sheet_name="Психотип") | |
business_stages_data = pd.read_excel(file_path, sheet_name="Стадия бизнеса") | |
industries_data = pd.read_excel(file_path, sheet_name="Отрасль") | |
opfs_data = pd.read_excel(file_path, sheet_name="ОПФ") | |
genders = genders_data["Пол"].dropna().unique().tolist() | |
generations = generations_data["Поколение"].dropna().unique().tolist() | |
psychotypes = psychotypes_data["Психотип"].dropna().unique().tolist() | |
business_stages = business_stages_data["Стадия бизнеса"].dropna().unique().tolist() | |
industries = industries_data["Отрасль"].dropna().unique().tolist() | |
opfs = opfs_data["ОПФ"].dropna().unique().tolist() | |
approaches_data = pd.read_excel(file_path, sheet_name="Подход") | |
approach_dict = { | |
"Указание на пользу": { | |
"prefix": "Начни SMS с указания на пользу продукта. Используй глагол в побудительном наклонении. Не начинай с вопроса", | |
"suffix": "Убедись, что SMS начинается с указания на пользу продукта и использования глагола в побудительном наклонении и не начинается с вопроса" | |
}, | |
"Вопрос": { | |
"prefix": "Начни сообщение с вопроса, который указывает на пользу продукта для клиента", | |
"suffix": "Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента" | |
}, | |
"Призыв к действию": { | |
"prefix": "Начни SMS с призыва к действию с продуктом. Не начинай с вопроса", | |
"suffix": "Убедись, что готовый текст начинается с призыва к действию с продуктом и не начинается с вопроса" | |
} | |
} | |
def fill_product_details(selected_product, data): | |
if selected_product: | |
product_row = data[data["Наименование продукта"] == selected_product].iloc[0] | |
return ( | |
product_row.get("Описание предложения", ""), | |
product_row.get("Наименование продукта", ""), | |
product_row.get("Преимущества", ""), | |
product_row.get("Ключевое сообщение", "") | |
) | |
return "", "", "", "" | |
def get_approaches(gender, generation, psychotype, approaches_df): | |
if approaches_df is None or approaches_df.empty: | |
return "Подход не найден для выбранных параметров." | |
filters = [] | |
for param_name, param_value in [('Пол', gender), ('Поколение', generation), ('Психотип', psychotype)]: | |
if not param_value or param_value == "Не выбрано": | |
filters.append(approaches_df[param_name].isnull() | (approaches_df[param_name].fillna('') == '')) | |
else: | |
filters.append(approaches_df[param_name].fillna('') == param_value) | |
combined_filter = filters[0] | |
for f in filters[1:]: | |
combined_filter &= f | |
matching_rows = approaches_df[combined_filter] | |
if matching_rows.empty: | |
return "Подход не найден для выбранных параметров." | |
approach_list = [] | |
for approaches in matching_rows['Подход']: | |
approach_names = [a.strip() for a in str(approaches).split(',')] | |
approach_list.extend(approach_names) | |
approach_list = list(set(approach_list)) | |
return ', '.join(approach_list) | |
def get_instructions_for_param(param_value, df, col): | |
if not param_value or param_value == "Не выбрано": | |
return None | |
row = df[df[col] == param_value] | |
if row.empty: | |
return None | |
instr1 = row.iloc[0].get("Инструкция 1", "") | |
if not instr1.strip(): | |
return None | |
return instr1 | |
def format_instruction_string(instr): | |
terms = [t.strip() for t in instr.split(',') if t.strip()] | |
return " или ".join(terms) if terms else "" | |
def generate_display_prompts(description, product_name, benefits, key_message, chosen_approach, | |
gender, generation, psychotype, business_stage, industry, opf): | |
if chosen_approach == "Подход не найден для выбранных параметров.": | |
return ("Для формирования промпта выберите хотя бы один личный персональный параметр для определения подхода", | |
"Для формирования промпта выберите хотя бы один личный персональный параметр для определения подхода") | |
approach_list = [a.strip() for a in chosen_approach.split(',') if a.strip()] | |
prefix_parts = [] | |
suffix_parts = [] | |
for a in approach_list: | |
if a in approach_dict: | |
prefix_parts.append(approach_dict[a]["prefix"]) | |
suffix_parts.append(approach_dict[a]["suffix"]) | |
if len(prefix_parts) > 1: | |
approach_prefix = " / ".join(prefix_parts) | |
approach_suffix = " / ".join(suffix_parts) | |
else: | |
approach_prefix = prefix_parts[0] if prefix_parts else "" | |
approach_suffix = suffix_parts[0] if suffix_parts else "" | |
instructions_data = [ | |
(gender, genders_data, "Пол"), | |
(generation, generations_data, "Поколение"), | |
(psychotype, psychotypes_data, "Психотип"), | |
(business_stage, business_stages_data, "Стадия бизнеса"), | |
(industry, industries_data, "Отрасль"), | |
(opf, opfs_data, "ОПФ") | |
] | |
chosen_params_instructions = [] | |
for (param_value, df, col) in instructions_data: | |
instr1 = get_instructions_for_param(param_value, df, col) | |
if instr1: | |
chosen_params_instructions.append(instr1) | |
if not chosen_params_instructions: | |
return ("Для формирования промпта выберите хотя бы один личный персональный параметр для определения подхода", | |
"Для формирования промпта выберите хотя бы один личный персональный параметр для определения подхода") | |
lines = [] | |
for i, instr_line in enumerate(chosen_params_instructions, start=1): | |
formatted_line = format_instruction_string(instr_line) | |
lines.append(f"{i}. {formatted_line}.") | |
mandatory_terms = "\n".join(lines) | |
prompt = f"""Напиши три или четыре предложения. {approach_prefix}. | |
Напиши рекламное SMS для следующего продукта: | |
«{description}». | |
Не изменяй название продукта: «{product_name}». | |
Преимущества: | |
«{benefits}». | |
ОБЯЗАТЕЛЬНО используй в SMS КАЖДЫЙ из следующих терминов: | |
{mandatory_terms} | |
Убедись, что написал не меньше трех и не больше четырех предложений. | |
{approach_suffix}. | |
Убедись, что УМЕСТНО использовал КАЖДЫЙ необходимый термин. | |
Убедись, что в SMS без изменений, синонимов и перестановок слов используется наименование продукта: «{product_name}». | |
Убедись, что в SMS есть следующая ключевая информация: «{key_message}».""" | |
return prompt, prompt | |
def generate_model_prompt(description, product_name, benefits, key_message, | |
gender, generation, psychotype, business_stage, industry, opf, | |
single_approach): | |
prefix = approach_dict[single_approach]["prefix"] | |
suffix = approach_dict[single_approach]["suffix"] | |
instructions_data = [ | |
(gender, genders_data, "Пол"), | |
(generation, generations_data, "Поколение"), | |
(psychotype, psychotypes_data, "Психотип"), | |
(business_stage, business_stages_data, "Стадия бизнеса"), | |
(industry, industries_data, "Отрасль"), | |
(opf, opfs_data, "ОПФ") | |
] | |
chosen_params_instructions = [] | |
for (param_value, df, col) in instructions_data: | |
instr1 = get_instructions_for_param(param_value, df, col) | |
if instr1: | |
chosen_params_instructions.append(instr1) | |
if chosen_params_instructions: | |
lines = [] | |
for i, instr_line in enumerate(chosen_params_instructions, start=1): | |
formatted_line = format_instruction_string(instr_line) | |
lines.append(f"{i}. {formatted_line}.") | |
mandatory_terms = "\n".join(lines) | |
else: | |
mandatory_terms = None | |
if mandatory_terms: | |
model_prompt = f"""Напиши три или четыре предложения. {prefix}. | |
Напиши рекламное SMS для следующего продукта: | |
«{description}». | |
Не изменяй название продукта: «{product_name}». | |
Преимущества: | |
«{benefits}». | |
ОБЯЗАТЕЛЬНО используй в SMS КАЖДЫЙ из следующих терминов: | |
{mandatory_terms} | |
Убедись, что написал не меньше трех и не больше четырех предложений. | |
{suffix}. | |
Убедись, что УМЕСТНО использовал КАЖДЫЙ необходимый термин. | |
Убедись, что в SMS без изменений, синонимов и перестановок слов используется наименование продукта: «{product_name}». | |
Убедись, что в SMS есть следующая ключевая информация: «{key_message}».""" | |
else: | |
model_prompt = "" | |
return model_prompt | |
def call_model(model_prompt): | |
completion = client.chat.completions.create( | |
model="grok-2-1212", | |
messages=[ | |
{"role": "system", "content": "You are a world-class expert in creating personalized SMS who returns only the SMS and nothing else."}, | |
{"role": "user", "content": model_prompt}, | |
], | |
) | |
return completion.choices[0].message.content.strip() | |
def update_prompts_on_params_change(description, product_name, benefits, key_message, | |
gender, generation, psychotype, business_stage, industry, opf): | |
chosen_approach = get_approaches(gender, generation, psychotype, approaches_data) | |
prompt_1, prompt_2 = generate_display_prompts(description, product_name, benefits, key_message, | |
chosen_approach, gender, generation, psychotype, | |
business_stage, industry, opf) | |
return chosen_approach, prompt_1, prompt_2 | |
def generate_personalized_sms(description, product_name, benefits, key_message, | |
gender, generation, psychotype, business_stage, industry, opf, | |
chosen_approach, prompt_1, prompt_2): | |
# Если нет персональных параметров или подхода, показываем предупреждение: | |
if "Для формирования промпта выберите хотя бы один личный персональный параметр" in prompt_1 or chosen_approach == "Подход не найден для выбранных параметров.": | |
gr.Warning("Задайте хотя бы один личный персональный параметр для определения подхода, чтобы был сформирован промпт") | |
# Возвращаем пустые результаты для SMS | |
return "", "" | |
approach_list = [a.strip() for a in chosen_approach.split(',') if a.strip()] | |
if not approach_list: | |
gr.Warning("Задайте хотя бы один личный персональный параметр для определения подхода, чтобы был сформирован промпт") | |
return "", "" | |
chosen_single_approach_1 = random.choice(approach_list) if len(approach_list) > 1 else approach_list[0] | |
chosen_single_approach_2 = random.choice(approach_list) if len(approach_list) > 1 else approach_list[0] | |
model_prompt_1 = generate_model_prompt(description, product_name, benefits, key_message, | |
gender, generation, psychotype, business_stage, industry, opf, | |
chosen_single_approach_1) | |
model_prompt_2 = generate_model_prompt(description, product_name, benefits, key_message, | |
gender, generation, psychotype, business_stage, industry, opf, | |
chosen_single_approach_2) | |
sms_1 = call_model(model_prompt_1) | |
sms_2 = call_model(model_prompt_2) | |
return sms_1, sms_2 | |
with gr.Blocks(theme="default") as demo: | |
gr.Markdown("**Процент созданных SMS по выбранному продукту**") | |
progress_bar_html = """ | |
<div style="width: 100%; background-color: #e0e0e0; border-radius: 10px; overflow: hidden;"> | |
<div style="width: 0%; background-color: #4caf50; height: 20px; text-align: center; color: white;"> | |
0% | |
</div> | |
</div> | |
""" | |
gr.HTML(progress_bar_html) | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("**Продукт**") | |
product_dropdown = gr.Dropdown(label="Продукт", choices=products, value=None) | |
description = gr.Textbox(label="Описание предложения", lines=5, value="") | |
product_name = gr.Textbox(label="Наименование продукта", lines=1, value="") | |
benefits = gr.Textbox(label="Преимущества", lines=9, value="") | |
key_message = gr.Textbox(label="Ключевое сообщение", lines=2, value="") | |
product_dropdown.change( | |
fn=lambda selected: fill_product_details(selected, data_products), | |
inputs=[product_dropdown], | |
outputs=[description, product_name, benefits, key_message] | |
) | |
with gr.Column(scale=1): | |
gr.Markdown("**Клиент**") | |
gender_dropdown = gr.Dropdown(label="Пол", choices=["Не выбрано"]+genders, value=None) | |
generation_dropdown = gr.Dropdown(label="Поколение", choices=["Не выбрано"]+generations, value=None) | |
psychotype_dropdown = gr.Dropdown(label="Психотип", choices=["Не выбрано"]+psychotypes, value=None) | |
business_stage_dropdown = gr.Dropdown(label="Стадия бизнеса", choices=["Не выбрано"]+business_stages, value=None) | |
industry_dropdown = gr.Dropdown(label="Отрасль", choices=["Не выбрано"]+industries, value=None) | |
opf_dropdown = gr.Dropdown(label="ОПФ", choices=["Не выбрано"]+opfs, value=None) | |
chosen_approach = gr.Textbox(label="Выбранный подход", lines=1, value="") | |
presence_in_db = gr.Textbox(label="Комментарий", lines=1, value="", interactive=False) | |
with gr.Row(): | |
return_params_btn = gr.Button("Вернуть параметры предыдущего запроса") | |
set_unused_params_btn = gr.Button("Задать ранее невыставленные параметры") | |
create_personal_sms_btn = gr.Button("Создать персонализированное SMS") | |
with gr.Row(): | |
with gr.Column(): | |
model_1_name = gr.Textbox(label="Модель 1", value="Grok-2-1212", interactive=False) | |
prompt_1 = gr.Textbox(label="Промпт 1", value="", interactive=False, lines=10) | |
sms_1 = gr.Textbox(label="SMS 1", lines=3, value="") | |
with gr.Column(): | |
model_2_name = gr.Textbox(label="Модель 2", value="Grok-2-1212", interactive=False) | |
prompt_2 = gr.Textbox(label="Промпт 2", value="", interactive=False, lines=10) | |
sms_2 = gr.Textbox(label="SMS 2", lines=3, value="") | |
with gr.Row(): | |
prefer_sms_1_btn = gr.Button("Я предпочитаю это SMS") | |
prefer_sms_2_btn = gr.Button("Я предпочитаю это SMS") | |
regen_btn = gr.Button("Перегенерировать SMS (не нравится ни одно из SMS)") | |
with gr.Row(): | |
comment_sms_1 = gr.Textbox(label="Комментарий к SMS 1", lines=2, value="") | |
comment_sms_2 = gr.Textbox(label="Комментарий к SMS 2", lines=2, value="") | |
with gr.Row(): | |
corrected_sms_1 = gr.Textbox(label="Откорректированное SMS 1", lines=3, value="") | |
corrected_sms_2 = gr.Textbox(label="Откорректированное SMS 2", lines=3, value="") | |
with gr.Row(): | |
save_sms_1_btn = gr.Button("Сохранить в базу") | |
save_sms_2_btn = gr.Button("Сохранить в базу") | |
# Обновляем промпты при изменении параметров клиента | |
client_params = [gender_dropdown, generation_dropdown, psychotype_dropdown, business_stage_dropdown, industry_dropdown, opf_dropdown] | |
for cp in client_params: | |
cp.change( | |
fn=update_prompts_on_params_change, | |
inputs=[description, product_name, benefits, key_message, | |
gender_dropdown, generation_dropdown, psychotype_dropdown, | |
business_stage_dropdown, industry_dropdown, opf_dropdown], | |
outputs=[chosen_approach, prompt_1, prompt_2] | |
) | |
# Генерация SMS по нажатию кнопки | |
# Если персональные параметры не выбраны - выдаём gr.Warning | |
create_personal_sms_btn.click( | |
fn=generate_personalized_sms, | |
inputs=[description, product_name, benefits, key_message, | |
gender_dropdown, generation_dropdown, psychotype_dropdown, | |
business_stage_dropdown, industry_dropdown, opf_dropdown, | |
chosen_approach, prompt_1, prompt_2], | |
outputs=[sms_1, sms_2] | |
) | |
# Обязательно включаем очередь: | |
demo.queue().launch() |