advantages / app.py
trashchenkov's picture
Update app.py
965b4c8 verified
raw
history blame
10.4 kB
from pyvis.network import Network
import pandas as pd
import pymorphy3
import re
import gradio as gr
# Инициализация pymorphy3 (лемматизатор)
morph = pymorphy3.MorphAnalyzer()
# Функция токенизации и лемматизации
def tokenize_and_lemmatize(text):
text = re.sub(r'[^\w\s]', '', text.lower()) # Удаляем пунктуацию, приводим к нижнему регистру
words = text.split()
return [morph.parse(word)[0].normal_form for word in words]
# Словарь ключевых слов для каждого сегмента (каждое слово в начальной форме)
personalization_keywords = {
"Поколение X": ["комиссия", "визит", "снижение", "ставка", "бесплатно", "экономия"],
"Поколение Y": ["онлайн", "цифровой", "бонус", "лимит", "qr", "sberpay"],
"Поколение Z": ["быстрота", "мгновенно", "минута", "оперативно", "решение"],
"Пол Женский": ["комфорт", "удобство", "забота", "легкость", "терминал"],
"ОПФ ИП": ["эффективность", "комиссия", "снижение", "ставка", "онлайн", "быстрота", "оптимизация"],
"ОПФ ООО": ["удобство", "комиссия", "открытие", "онлайн", "легкость", "автоматизация"],
"Психотип Конструктор": ["оптимизация", "снижение", "ставка", "комиссия", "льготный", "период", "выгодно", "настройка"],
"Пол Мужской": ["динамичность", "быстрота", "лимит", "решение", "активность", "оптимизация"],
"Стадия бизнеса Новичок": ["доступность", "простота", "низкий", "порог", "комиссия", "легкость"],
"Стадия бизнеса Профи": ["профессионализм", "комиссия", "снижение", "ставка", "оптимизация", "эффективность", "быстрота"],
"Психотип Рефлектор": ["премиальность", "эксклюзив", "бизнес", "зал", "акция", "привилегия", "статус"],
"Психотип Центрист": ["универсальность", "стандарт", "комиссия", "бесплатно", "надежность"],
"Стадия бизнеса Эксперт": ["максимизация", "высокий", "лимит", "снижение", "ставка", "комиссия", "выгода", "оптимизация"]
}
# Функция для классификации одного текста преимущества
def classify_advantage(text, keywords_dict):
"""
Возвращает список кортежей вида:
[
(category, { 'count': int, 'matched_lemmas': set([...]) }),
...
]
отсортированных по убыванию count.
"""
lemmas = tokenize_and_lemmatize(text)
category_matches = {}
# Проходим по всем категориям и считаем число совпадений лемм
for category, keywords in keywords_dict.items():
matches = set(lemmas) & set(keywords) # Пересечение множеств
if matches:
category_matches[category] = {
'count': len(matches),
'matched_lemmas': matches
}
# Сортируем категории по количеству совпадений (по убыванию)
sorted_matches = sorted(
category_matches.items(),
key=lambda x: x[1]['count'],
reverse=True
)
return sorted_matches
# Глобальная переменная для хранения DataFrame
df = None
def load_excel(file):
"""
Функция для загрузки Excel-файла.
Возвращает список уникальных продуктов и сообщение о статусе загрузки.
"""
global df
if file is None:
return [], "Файл не загружен. Загрузите Excel-файл."
try:
# Читаем Excel в DataFrame
df = pd.read_excel(file.name, usecols=["Продукт", "Преимущество"])
unique_products = df["Продукт"].unique().tolist()
return unique_products, "Файл успешно загружен!"
except Exception as e:
return [], f"Ошибка при чтении файла: {str(e)}"
def analyze(product):
"""
Функция, вызываемая при выборе продукта в выпадающем списке.
Анализирует все преимущества, соответствующие данному продукту,
и возвращает подробный отчёт и визуализацию графа.
"""
global df
if df is None:
return "Сначала загрузите файл.", None
if not product:
return "Пожалуйста, выберите продукт.", None
# Фильтруем DataFrame по выбранному продукту
product_advantages = df[df["Продукт"] == product]["Преимущество"]
# Создаём граф
graph_html = create_category_graph(product, product_advantages, personalization_keywords)
# Собираем результаты
results = []
for advantage in product_advantages:
matches = classify_advantage(advantage, personalization_keywords)
# Формируем текстовый отчёт по каждому преимуществу
advantage_text = f"**Преимущество**: {advantage}\n\n"
advantage_text += f"**Леммы**: {tokenize_and_lemmatize(advantage)}\n\n"
advantage_text += "**Совпадающие категории:**\n"
if matches:
for category, data in matches:
# Выводим и количество совпадений, и сами совпавшие леммы
matched_lemmas_str = ", ".join(sorted(data['matched_lemmas']))
advantage_text += f"- {category}: {data['count']} совпадений (леммы: {matched_lemmas_str})\n"
else:
advantage_text += "- Нет совпадений.\n"
advantage_text += "\n---\n"
results.append(advantage_text)
if not results:
return "Для выбранного продукта не найдено преимуществ.", None
return "\n".join(results), graph_html
def create_category_graph(product, advantages, personalization_keywords):
"""
Создаёт граф связей между продуктом, его преимуществами и категориями персонализации.
Возвращает HTML-код для отображения графа в iframe.
"""
net = Network(notebook=False, height="500px", width="100%", directed=True, cdn_resources='in_line') # Используем встроенные ресурсы
# Добавляем узел для продукта
net.add_node(product, label=product, color="lightblue", size=30)
# Проходим по всем преимуществам продукта
for advantage in advantages:
# Добавляем узел для преимущества
net.add_node(advantage, label=advantage, color="orange", size=20)
net.add_edge(product, advantage) # Связь продукта с преимуществом
# Анализируем преимущество и добавляем связи с категориями
matches = classify_advantage(advantage, personalization_keywords)
for category, data in matches:
net.add_node(category, label=category, color="green", size=15)
net.add_edge(advantage, category) # Связь преимущества с категорией
# Генерируем HTML-код для графа
html = net.generate_html(notebook=False)
# Заменяем одинарные кавычки на двойные
html = html.replace("'", '"')
# Возвращаем iframe с HTML-кодом графа
return f"""
<iframe
width="100%"
height="600"
frameborder="0"
srcdoc='{html}'>
</iframe>
"""
with gr.Blocks() as demo:
gr.Markdown("## Классификация преимуществ по признакам персонализации")
gr.Markdown("**Шаг 1:** Загрузите Excel-файл с двумя столбцами: 'Продукт' и 'Преимущество'.")
file_input = gr.File(label="Загрузите Excel-файл", file_types=[".xlsx"])
load_button = gr.Button("Загрузить файл")
load_status = gr.Markdown("")
gr.Markdown("**Шаг 2:** Выберите продукт из списка (по умолчанию ничего не выбрано).")
product_dropdown = gr.Dropdown(choices=[], label="Продукты", value=None)
analyze_button = gr.Button("Анализировать")
output_text = gr.Markdown("")
output_graph = gr.HTML(label="Визуализация графа")
# Логика при нажатии "Загрузить файл"
def on_file_upload(file):
unique_products, status_message = load_excel(file)
return gr.update(choices=unique_products), status_message
load_button.click(
fn=on_file_upload,
inputs=file_input,
outputs=[product_dropdown, load_status]
)
# Логика при нажатии "Анализировать"
analyze_button.click(
fn=analyze,
inputs=product_dropdown,
outputs=[output_text, output_graph]
)
# Запускаем демо
if __name__ == "__main__":
demo.launch(debug=True)