Spaces:
Sleeping
Sleeping
File size: 10,373 Bytes
cd9ea1c d59ffef cd9ea1c 5829a54 d59ffef cd9ea1c d59ffef 5829a54 d59ffef 5829a54 d59ffef 5829a54 d59ffef cd9ea1c d59ffef 5829a54 d59ffef cd9ea1c d59ffef 24b46ce d59ffef 965b4c8 d59ffef 5829a54 d59ffef 5829a54 cd9ea1c d59ffef |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
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) |