trashchenkov commited on
Commit
d59ffef
·
verified ·
1 Parent(s): 5829a54

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -51
app.py CHANGED
@@ -1,64 +1,201 @@
1
- import gradio as gr
2
  from pyvis.network import Network
 
 
 
 
3
 
4
- def create_knowledge_graph():
5
- # Создаем граф с pyvis
6
- net = Network(
7
- height="600px",
8
- width="100%",
9
- bgcolor="#222222",
10
- font_color="white",
11
- cdn_resources="in_line" # Встраиваем JS/CSS в HTML
12
- )
13
 
14
- # Добавляем узлы (концепции)
15
- nodes = ["Python", "Gradio", "Pyvis", "Data Science", "Machine Learning"]
16
- for node in nodes:
17
- net.add_node(node, label=node)
18
-
19
- # Добавляем ребра (связи между концепциями)
20
- edges = [
21
- ("Python", "Gradio"),
22
- ("Python", "Pyvis"),
23
- ("Python", "Data Science"),
24
- ("Data Science", "Machine Learning"),
25
- ("Gradio", "Machine Learning"),
26
- ("Pyvis", "Data Science")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ]
28
- for source, target in edges:
29
- net.add_edge(source, target)
 
 
30
 
31
- # Генерируем HTML-код графа
32
- html_content = net.generate_html(notebook=False)
 
 
 
 
 
 
33
 
34
- # Экранируем двойные кавычки для корректной вставки в srcdoc
35
- html_content_escaped = html_content.replace('"', '"')
 
 
 
 
 
36
 
37
- # Оборачиваем HTML в iframe
38
- iframe_code = f'''
39
- <iframe
40
- srcdoc="{html_content_escaped}"
41
- width="100%"
42
- height="600"
43
- frameborder="0"
44
- ></iframe>
45
- '''
46
- return iframe_code
47
 
48
- with gr.Blocks() as demo:
49
- gr.Markdown("# Граф Знаний с Pyvis и Gradio (Blocks)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- # Кнопка для генерации графа
52
- generate_button = gr.Button("Создать граф")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- # Выводим результат в виде HTML
55
- graph_html = gr.HTML()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
- # Связываем кнопку с функцией
58
- generate_button.click(
59
- fn=create_knowledge_graph,
60
- inputs=[],
61
- outputs=graph_html
62
  )
63
 
64
- demo.launch()
 
 
 
 
1
  from pyvis.network import Network
2
+ import pandas as pd
3
+ import pymorphy3
4
+ import re
5
+ import gradio as gr
6
 
 
 
 
 
 
 
 
 
 
7
 
8
+ # Инициализация pymorphy3 (лемматизатор)
9
+ morph = pymorphy3.MorphAnalyzer()
10
+
11
+ # Функция токенизации и лемматизации
12
+ def tokenize_and_lemmatize(text):
13
+ text = re.sub(r'[^\w\s]', '', text.lower()) # Удаляем пунктуацию, приводим к нижнему регистру
14
+ words = text.split()
15
+ return [morph.parse(word)[0].normal_form for word in words]
16
+
17
+ # Словарь ключевых слов для каждого сегмента (каждое слово в начальной форме)
18
+ personalization_keywords = {
19
+ "Поколение X": ["комиссия", "визит", "снижение", "ставка", "бесплатно", "экономия"],
20
+ "Поколение Y": ["онлайн", "цифровой", "бонус", "лимит", "qr", "sberpay"],
21
+ "Поколение Z": ["быстрота", "мгновенно", "минута", "оперативно", "решение"],
22
+ "Пол Женский": ["комфорт", "удобство", "забота", "легкость", "терминал"],
23
+ "ОПФ ИП": ["эффективность", "комиссия", "снижение", "ставка", "онлайн", "быстрота", "оптимизация"],
24
+ "ОПФ ООО": ["удобство", "комиссия", "открытие", "онлайн", "легкость", "автоматизация"],
25
+ "Психотип Конструктор": ["оптимизация", "снижение", "ставка", "комиссия", "льготный", "период", "выгодно", "настройка"],
26
+ "Пол Мужской": ["динамичность", "быстрота", "лимит", "решение", "активность", "оптимизация"],
27
+ "Стадия бизнеса Новичок": ["доступность", "простота", "низкий", "порог", "комиссия", "легкость"],
28
+ "Стадия бизнеса Профи": ["профессионализм", "комиссия", "снижение", "ставка", "оптимизация", "эффективность", "быстрота"],
29
+ "Психотип Рефлектор": ["премиальность", "эксклюзив", "бизнес", "зал", "акция", "привилегия", "статус"],
30
+ "Психотип Центрист": ["универсальность", "стандарт", "комиссия", "бесплатно", "надежность"],
31
+ "Стадия бизнеса Эксперт": ["максимизация", "высокий", "лимит", "снижение", "ставка", "комиссия", "выгода", "оптимизация"]
32
+ }
33
+
34
+ # Функция для классификации одного текста преимущества
35
+ def classify_advantage(text, keywords_dict):
36
+ """
37
+ Возвращает список кортежей вида:
38
+ [
39
+ (category, { 'count': int, 'matched_lemmas': set([...]) }),
40
+ ...
41
  ]
42
+ отсортированных по убыванию count.
43
+ """
44
+ lemmas = tokenize_and_lemmatize(text)
45
+ category_matches = {}
46
 
47
+ # Проходим по всем категориям и считаем число совпадений лемм
48
+ for category, keywords in keywords_dict.items():
49
+ matches = set(lemmas) & set(keywords) # Пересечение множеств
50
+ if matches:
51
+ category_matches[category] = {
52
+ 'count': len(matches),
53
+ 'matched_lemmas': matches
54
+ }
55
 
56
+ # Сортируем категории по количеству совпадений (по убыванию)
57
+ sorted_matches = sorted(
58
+ category_matches.items(),
59
+ key=lambda x: x[1]['count'],
60
+ reverse=True
61
+ )
62
+ return sorted_matches
63
 
64
+ # Глобальная переменная для хранения DataFrame
65
+ df = None
 
 
 
 
 
 
 
 
66
 
67
+ def load_excel(file):
68
+ """
69
+ Функция для загрузки Excel-файла.
70
+ Возвращает список уникальных продуктов и сообщение о статусе загрузки.
71
+ """
72
+ global df
73
+ if file is None:
74
+ return [], "Файл не загружен. Загрузите Excel-файл."
75
+ try:
76
+ # Читаем Excel в DataFrame
77
+ df = pd.read_excel(file.name, usecols=["Продукт", "Преимущество"])
78
+ unique_products = df["Продукт"].unique().tolist()
79
+ return unique_products, "Файл успешно загружен!"
80
+ except Exception as e:
81
+ return [], f"Ошибка при чтении файла: {str(e)}"
82
+
83
+
84
+ def analyze(product):
85
+ """
86
+ Функция, вызываемая при выборе продукта в выпадающем списке.
87
+ Анализирует все преимущества, соответствующие данному продукту,
88
+ и возвращает подробный отчёт и визуализацию графа.
89
+ """
90
+ global df
91
+ if df is None:
92
+ return "Сначала загрузите файл.", None
93
+
94
+ if not product:
95
+ return "Пожалуйста, выберите продукт.", None
96
 
97
+ # Фильтруем DataFrame по выбранному продукту
98
+ product_advantages = df[df["Продукт"] == product]["Преимущество"]
99
+
100
+ # Создаём граф
101
+ graph_html = create_category_graph(product, product_advantages, personalization_keywords)
102
+
103
+ # Собираем результаты
104
+ results = []
105
+ for advantage in product_advantages:
106
+ matches = classify_advantage(advantage, personalization_keywords)
107
+ # Формируем текстовый отчёт по каждому преимуществу
108
+ advantage_text = f"**Преимущество**: {advantage}\n\n"
109
+ advantage_text += f"**Леммы**: {tokenize_and_lemmatize(advantage)}\n\n"
110
+ advantage_text += "**Совпадающие категории:**\n"
111
+
112
+ if matches:
113
+ for category, data in matches:
114
+ # Выводим и количество совпадений, и сами совпавшие леммы
115
+ matched_lemmas_str = ", ".join(sorted(data['matched_lemmas']))
116
+ advantage_text += f"- {category}: {data['count']} совпадений (леммы: {matched_lemmas_str})\n"
117
+ else:
118
+ advantage_text += "- Нет совпадений.\n"
119
+ advantage_text += "\n---\n"
120
+ results.append(advantage_text)
121
 
122
+ if not results:
123
+ return "Для выбранного продукта не найдено преимуществ.", None
124
+
125
+ return "\n".join(results), graph_html
126
+
127
+
128
+ def create_category_graph(product, advantages, personalization_keywords):
129
+ """
130
+ Создаёт граф связей между продуктом, его преимуществами и категориями персонализации.
131
+ Возвращает HTML-код для отображения графа в iframe.
132
+ """
133
+ net = Network(notebook=True, height="500px", width="100%", directed=True, cdn_resources='in_line') # Используем встроенные ресурсы
134
+
135
+ # Добавляем узел для продукта
136
+ net.add_node(product, label=product, color="lightblue", size=30)
137
+
138
+ # Проходим по всем преимуществам продукта
139
+ for advantage in advantages:
140
+ # Добавляем узел для преимущества
141
+ net.add_node(advantage, label=advantage, color="orange", size=20)
142
+ net.add_edge(product, advantage) # Связь продукта с преимуществом
143
+
144
+ # Анализируем преимущество и добавляем связи с категориями
145
+ matches = classify_advantage(advantage, personalization_keywords)
146
+ for category, data in matches:
147
+ net.add_node(category, label=category, color="green", size=15)
148
+ net.add_edge(advantage, category) # Связь преимущества с категорией
149
+
150
+ # Генерируем HTML-код для графа
151
+ html = net.generate_html() #notebook=False)
152
+
153
+ # Заменяем одинарные кавычки на двойные
154
+ html = html.replace("'", '&quot;')
155
+
156
+ # Возвращаем iframe с HTML-кодом графа
157
+ return f"""
158
+ <iframe
159
+ width="100%"
160
+ height="600"
161
+ frameborder="0"
162
+ srcdoc='{html}'>
163
+ </iframe>
164
+ """
165
+
166
+ with gr.Blocks() as demo:
167
+ gr.Markdown("## Классификация преимуществ по признакам персонализации")
168
+ gr.Markdown("**Шаг 1:** Загрузите Excel-файл с двумя столбцами: 'Продукт' и 'Преимущество'.")
169
+
170
+ file_input = gr.File(label="Загрузите Excel-файл", file_types=[".xlsx"])
171
+ load_button = gr.Button("Загрузить файл")
172
+ load_status = gr.Markdown("")
173
+
174
+ gr.Markdown("**Шаг 2:** Выберите продукт из списка (по умолчанию ничего не выбрано).")
175
+ product_dropdown = gr.Dropdown(choices=[], label="Продукты", value=None)
176
+ analyze_button = gr.Button("Анализировать")
177
+
178
+ output_text = gr.Markdown("")
179
+ output_graph = gr.HTML(label="Визуализация графа")
180
+
181
+ # Логика при нажатии "Загрузить файл"
182
+ def on_file_upload(file):
183
+ unique_products, status_message = load_excel(file)
184
+ return gr.update(choices=unique_products), status_message
185
+
186
+ load_button.click(
187
+ fn=on_file_upload,
188
+ inputs=file_input,
189
+ outputs=[product_dropdown, load_status]
190
+ )
191
 
192
+ # Логика при нажатии "Анализировать"
193
+ analyze_button.click(
194
+ fn=analyze,
195
+ inputs=product_dropdown,
196
+ outputs=[output_text, output_graph]
197
  )
198
 
199
+ # Запускаем демо
200
+ if __name__ == "__main__":
201
+ demo.launch(debug=True)