PMI25 commited on
Commit
b5f9e29
·
verified ·
1 Parent(s): c1e1d95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -401
app.py CHANGED
@@ -1,424 +1,64 @@
1
  import gradio as gr
2
- import pandas as pd
3
- from datetime import datetime
4
- from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer
5
  import time
6
- import warnings
7
- warnings.filterwarnings('ignore')
8
 
9
- # Глобальные переменные
10
- history = []
11
- MAX_INPUT_LENGTH = 2000
12
-
13
- # Доступные модели для классификации тональности
14
- MODELS = {
15
- "distilbert-base-uncased-finetuned-sst-2-english": {
16
- "name": "DistilBERT SST-2",
17
- "description": "Быстрая модель для бинарной классификации (позитив/негатив)",
18
- "max_length": 512
19
- },
20
- "nlptown/bert-base-multilingual-uncased-sentiment": {
21
- "name": "BERT Multilingual Sentiment",
22
- "description": "Многоязычная модель с 5 классами (1-5 звёзд)",
23
- "max_length": 512
24
- },
25
- "cardiffnlp/twitter-roberta-base-sentiment-latest": {
26
- "name": "Twitter-RoBERTa",
27
- "description": "Модель, обученная на твитах, 3 класса (негатив/нейтрал/позитив)",
28
- "max_length": 512
29
- }
30
- }
31
-
32
- # Инициализация моделей
33
- loaded_models = {}
34
-
35
- def load_model(model_id):
36
- """Загрузка модели по требованию"""
37
- if model_id not in loaded_models:
38
- print(f"Загрузка модели {model_id}...")
39
- try:
40
- tokenizer = AutoTokenizer.from_pretrained(model_id)
41
- model = AutoModelForSequenceClassification.from_pretrained(model_id)
42
- classifier = pipeline(
43
- "sentiment-analysis",
44
- model=model,
45
- tokenizer=tokenizer,
46
- truncation=True,
47
- max_length=MODELS[model_id]["max_length"]
48
- )
49
- loaded_models[model_id] = classifier
50
- print(f"Модель {model_id} загружена успешно")
51
- except Exception as e:
52
- print(f"Ошибка загрузки модели: {e}")
53
- return None
54
- return loaded_models[model_id]
55
-
56
- def predict_sentiment(text, model_id, temperature=1.0):
57
- """
58
- Предсказание тональности текста
59
-
60
- Args:
61
- text: Входной текст
62
- model_id: Идентификатор модели
63
- temperature: Параметр для смягчения предсказаний (не используется в классификации,
64
- но оставлен для единообразия интерфейса)
65
-
66
- Returns:
67
- dict: Результаты классификации
68
- """
69
- # Проверка ввода
70
  if not text or not text.strip():
71
- return {"error": "Введите текст для анализа"}
72
-
73
- if len(text) > MAX_INPUT_LENGTH:
74
- return {"error": f"Текст слишком длинный. Максимум {MAX_INPUT_LENGTH} символов"}
75
-
76
- # Загрузка модели
77
- classifier = load_model(model_id)
78
- if classifier is None:
79
- return {"error": "Ошибка загрузки модели"}
80
-
81
- # Измерение времени выполнения
82
- start_time = time.time()
83
-
84
- try:
85
- # Выполнение предсказания
86
- result = classifier(text[:MODELS[model_id]["max_length"] * 4])[0]
87
-
88
- # Форматирование результата в зависимости от модели
89
- if model_id == "nlptown/bert-base-multilingual-uncased-sentiment":
90
- # Преобразование оценки 1-5 в текстовую форму
91
- stars = int(result['label'].split()[0])
92
- if stars <= 2:
93
- sentiment = "Негативный"
94
- emoji = "😞"
95
- elif stars == 3:
96
- sentiment = "Нейтральный"
97
- emoji = "😐"
98
- else:
99
- sentiment = "Позитивный"
100
- emoji = "😊"
101
-
102
- confidence = result['score']
103
- label = f"{stars} звёзд"
104
- else:
105
- # Для других моделей
106
- label_map = {
107
- "POSITIVE": "Позитивный",
108
- "NEGATIVE": "Негативный",
109
- "NEUTRAL": "Нейтральный",
110
- "LABEL_0": "Негативный",
111
- "LABEL_1": "Нейтральный",
112
- "LABEL_2": "Позитивный"
113
- }
114
-
115
- original_label = result['label']
116
- sentiment = label_map.get(original_label, original_label)
117
- confidence = result['score']
118
-
119
- # Эмодзи для визуализации
120
- if "позитив" in sentiment.lower():
121
- emoji = "😊"
122
- elif "негатив" in sentiment.lower():
123
- emoji = "😞"
124
- else:
125
- emoji = "😐"
126
-
127
- label = original_label
128
-
129
- latency = time.time() - start_time
130
-
131
- # Сохранение в историю
132
- history_entry = {
133
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
134
- "text": text[:100] + "..." if len(text) > 100 else text,
135
- "model": MODELS[model_id]["name"],
136
- "sentiment": sentiment,
137
- "confidence": round(confidence, 3),
138
- "latency": round(latency, 3)
139
- }
140
- history.insert(0, history_entry)
141
-
142
- # Ограничение истории
143
- if len(history) > 10:
144
- history.pop()
145
-
146
- return {
147
- "sentiment": sentiment,
148
- "confidence": confidence,
149
- "label": label,
150
- "latency": latency,
151
- "emoji": emoji,
152
- "model_name": MODELS[model_id]["name"],
153
- "error": None
154
- }
155
-
156
- except Exception as e:
157
- return {"error": f"Ошибка обработки: {str(e)}"}
158
-
159
- def batch_process(file, model_id):
160
- """Пакетная обработка CSV файла"""
161
- if file is None:
162
- return None, "Загрузите CSV файл"
163
 
164
  try:
165
- # Чтение CSV
166
- df = pd.read_csv(file.name)
167
 
168
- # Проверка наличия колонки с текстом
169
- if 'text' not in df.columns:
170
- # Попробуем найти колонку с текстом
171
- text_columns = [col for col in df.columns if any(word in col.lower() for word in ['text', 'review', 'comment', 'отзыв'])]
172
- if text_columns:
173
- df['text'] = df[text_columns[0]]
174
- else:
175
- return None, "Не найдена колонка 'text' или аналогичная"
176
 
177
- results = []
178
- total_texts = min(len(df), 50) # Ограничим количество для скорости
179
 
180
- with gr.Progress() as progress:
181
- task = progress.add_task("Обработка...", total=total_texts)
182
-
183
- for i, row in progress.tqdm(enumerate(df.head(total_texts).itertuples()), total=total_texts):
184
- text = str(getattr(row, 'text'))
185
- if len(text) > 500:
186
- text = text[:500] + "..."
187
-
188
- result = predict_sentiment(text, model_id)
189
- if "error" not in result or result["error"] is None:
190
- results.append({
191
- "Текст": text[:100] + "..." if len(text) > 100 else text,
192
- "Тональность": result["sentiment"],
193
- "Уверенность": round(result["confidence"], 3),
194
- "Модель": result["model_name"]
195
- })
196
-
197
- progress.update(task, advance=1)
198
 
199
- results_df = pd.DataFrame(results)
200
- return results_df, f"Обработано {len(results)} отзывов"
201
 
202
  except Exception as e:
203
- return None, f"Ошибка обработки файла: {str(e)}"
204
-
205
- def get_history_html():
206
- """Получение истории в HTML формате"""
207
- if not history:
208
- return "<p>История пуста</p>"
209
-
210
- html = "<div style='max-height: 300px; overflow-y: auto;'>"
211
- html += "<table style='width: 100%; border-collapse: collapse;'>"
212
- html += "<tr style='background-color: #f2f2f2;'><th>Время</th><th>Текст</th><th>Модель</th><th>Тональность</th><th>Уверенность</th><th>Время, сек</th></tr>"
213
-
214
- for entry in history:
215
- html += f"""
216
- <tr style='border-bottom: 1px solid #ddd;'>
217
- <td>{entry['timestamp']}</td>
218
- <td>{entry['text']}</td>
219
- <td>{entry['model']}</td>
220
- <td>{entry['sentiment']}</td>
221
- <td>{entry['confidence']}</td>
222
- <td>{entry['latency']}</td>
223
- </tr>
224
- """
225
-
226
- html += "</table></div>"
227
- return html
228
 
229
- def calculate_metrics():
230
- """Расчёт простых метрик качества"""
231
- # Тестовые примеры с ожидаемой тональностью
232
- test_cases = [
233
- {"text": "This coffee is absolutely amazing! Best I've ever had.", "expected": "POSITIVE"},
234
- {"text": "The coffee was cold and tasted bitter. Very disappointing.", "expected": "NEGATIVE"},
235
- {"text": "I ordered a coffee. It was delivered on time.", "expected": "NEUTRAL"},
236
- {"text": "Ароматный кофе с приятным послевкусием. Рекомендую!", "expected": "POSITIVE"},
237
- {"text": "Кофе был пережарен, чувствуется горечь. Не понравилось.", "expected": "NEGATIVE"}
238
- ]
239
-
240
- results = []
241
- model_id = list(MODELS.keys())[0] # Используем первую модель
242
-
243
- for test in test_cases:
244
- result = predict_sentiment(test["text"], model_id)
245
- if "error" not in result or result["error"] is None:
246
- predicted = "POSITIVE" if "позитив" in result["sentiment"].lower() else \
247
- "NEGATIVE" if "негатив" in result["sentiment"].lower() else "NEUTRAL"
248
- results.append({
249
- "text": test["text"][:50] + "...",
250
- "expected": test["expected"],
251
- "predicted": predicted,
252
- "correct": predicted == test["expected"]
253
- })
254
-
255
- accuracy = sum(1 for r in results if r["correct"]) / len(results) if results else 0
256
-
257
- return pd.DataFrame(results), f"Точность на тестовых примерах: {accuracy:.2%}"
258
-
259
- # Создание интерфейса Gradio
260
- with gr.Blocks(title="Анализ тональности отзывов о кофе", theme=gr.themes.Soft()) as demo:
261
- gr.Markdown("# ☕ Анализ тональности отзывов о кофе")
262
- gr.Markdown("Определите эмоциональную окраску отзывов о кофе с помощью нейросетевых моделей")
263
 
264
  with gr.Row():
265
- with gr.Column(scale=2):
266
- # Входные данные
267
- input_text = gr.Textbox(
268
- label="Введите отзыв о кофе",
269
- placeholder="Например: Этот кофе имеет богатый аромат и приятное послевкусие...",
270
- lines=4,
271
- max_lines=8
272
- )
273
-
274
- # Выбор модели
275
- model_dropdown = gr.Dropdown(
276
- choices=list(MODELS.keys()),
277
- value=list(MODELS.keys())[0],
278
- label="Выберите модель",
279
- info=[f"{MODELS[m]['name']}: {MODELS[m]['description']}" for m in MODELS][0]
280
- )
281
-
282
- # Параметры
283
- temperature = gr.Slider(
284
- minimum=0.1,
285
- maximum=2.0,
286
- value=1.0,
287
- step=0.1,
288
- label="Температура (влияет на уверенность)",
289
- info="Меньше = более уверенные предсказания"
290
- )
291
-
292
- # Кнопки
293
- with gr.Row():
294
- submit_btn = gr.Button("📊 Анализировать", variant="primary")
295
- clear_btn = gr.Button("🗑️ Очистить")
296
- metrics_btn = gr.Button("📈 Тестовые метрики")
297
-
298
- # Примеры
299
- gr.Examples(
300
- examples=[
301
- ["Этот кофе просто восхитителен! Идеальный баланс кислотности и горечи.", list(MODELS.keys())[0]],
302
- ["Кофе был холодным и безвкусным. Очень разочарован.", list(MODELS.keys())[0]],
303
- ["Заказал капучино. Доставка заняла 15 минут.", list(MODELS.keys())[1]],
304
- ["Кофе имеет насыщенный вкус с нотками шоколада и ореха. Рекомендую!", list(MODELS.keys())[2]],
305
- ["Горький и пережаренный кофе. Никому не советую покупать.", list(MODELS.keys())[2]]
306
- ],
307
- inputs=[input_text, model_dropdown],
308
- label="Примеры отзывов"
309
- )
310
-
311
- with gr.Column(scale=1):
312
- # Результаты
313
- result_emoji = gr.Textbox(label="Результат", interactive=False)
314
- result_sentiment = gr.Textbox(label="Тональность", interactive=False)
315
- result_confidence = gr.Textbox(label="Уверенность", interactive=False)
316
- result_latency = gr.Textbox(label="Время обработки", interactive=False)
317
- result_model = gr.Textbox(label="Использованная модель", interactive=False)
318
-
319
- # История запросов
320
- with gr.Accordion("📜 История запросов (последние 10)", open=False):
321
- history_html = gr.HTML(value=get_history_html())
322
- refresh_history = gr.Button("🔄 Обновить историю")
323
-
324
- # Пакетная обработка
325
- with gr.Accordion("📁 Пакетная обработка CSV", open=False):
326
- gr.Markdown("Загрузите CSV файл с колонкой 'text' для обработки нескольких отзывов")
327
- file_input = gr.File(label="CSV файл", file_types=[".csv"])
328
- batch_model_dropdown = gr.Dropdown(
329
- choices=list(MODELS.keys()),
330
- value=list(MODELS.keys())[0],
331
- label="Модель для пакетной обработки"
332
  )
333
- batch_btn = gr.Button("🚀 Обработать файл", variant="secondary")
334
- batch_output = gr.Dataframe(label="Результаты пакетной обработки")
335
- batch_status = gr.Textbox(label="Статус", interactive=False)
336
-
337
- # Тестовые метрики
338
- with gr.Accordion("📊 Тестирование качества модели", open=False):
339
- metrics_output = gr.Dataframe(label="Результаты тестирования")
340
- metrics_status = gr.Textbox(label="Метрики", interactive=False)
341
-
342
- # Обработчики событий
343
- def update_result(text, model_id, temp):
344
- result = predict_sentiment(text, model_id, temp)
345
-
346
- if "error" in result and result["error"]:
347
- return [
348
- "❌ Ошибка",
349
- f"Ошибка: {result['error']}",
350
- "-",
351
- "-",
352
- "-",
353
- get_history_html()
354
- ]
355
-
356
- return [
357
- f"{result['emoji']} {result['sentiment']}",
358
- result['sentiment'],
359
- f"{result['confidence']:.2%}",
360
- f"{result['latency']:.3f} сек",
361
- result['model_name'],
362
- get_history_html()
363
- ]
364
 
365
- # Связывание обработчиков
366
- submit_btn.click(
367
- fn=update_result,
368
- inputs=[input_text, model_dropdown, temperature],
369
- outputs=[result_emoji, result_sentiment, result_confidence, result_latency, result_model, history_html]
370
- )
371
-
372
- clear_btn.click(
373
- fn=lambda: ["", list(MODELS.keys())[0], 1.0, "", "", "", "", "", get_history_html()],
374
- outputs=[input_text, model_dropdown, temperature, result_emoji, result_sentiment,
375
- result_confidence, result_latency, result_model, history_html]
376
- )
377
-
378
- refresh_history.click(
379
- fn=get_history_html,
380
- outputs=history_html
381
- )
382
-
383
- batch_btn.click(
384
- fn=batch_process,
385
- inputs=[file_input, batch_model_dropdown],
386
- outputs=[batch_output, batch_status]
387
- )
388
 
389
- metrics_btn.click(
390
- fn=calculate_metrics,
391
- outputs=[metrics_output, metrics_status]
 
 
 
 
 
 
 
 
 
392
  )
393
 
394
- # Информация о модели при изменении выбора
395
- def update_model_info(model_id):
396
- model_info = MODELS.get(model_id, {})
397
- return gr.Dropdown.update(info=f"{model_info.get('name', '')}: {model_info.get('description', '')}")
398
-
399
- model_dropdown.change(
400
- fn=update_model_info,
401
- inputs=model_dropdown,
402
- outputs=model_dropdown
403
  )
404
-
405
- # Предзагрузка первой модели
406
- gr.Markdown("### Информация о моделях")
407
- model_info_text = "Доступные модели:\n\n"
408
- for model_id, info in MODELS.items():
409
- model_info_text += f"**{info['name']}** (`{model_id}`)\n"
410
- model_info_text += f" - {info['description']}\n\n"
411
-
412
- gr.Markdown(model_info_text)
413
 
414
  if __name__ == "__main__":
415
- # Предзагрузка первой модели
416
- print("Предзагрузка моделей...")
417
- for model_id in list(MODELS.keys())[:1]: # Загружаем только первую для скорости
418
- load_model(model_id)
419
-
420
- demo.launch(
421
- server_name="0.0.0.0",
422
- server_port=7860,
423
- share=False
424
- )
 
1
  import gradio as gr
2
+ from transformers import pipeline
 
 
3
  import time
 
 
4
 
5
+ # Простая функция для тестирования
6
+ def analyze_coffee_sentiment(text):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  if not text or not text.strip():
8
+ return "⚠️ Введите текст отзыва о кофе", "0ms"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  try:
11
+ start_time = time.time()
 
12
 
13
+ # Используем легкую модель для быстрого старта
14
+ classifier = pipeline(
15
+ "sentiment-analysis",
16
+ model="distilbert-base-uncased-finetuned-sst-2-english"
17
+ )
 
 
 
18
 
19
+ result = classifier(text[:500])[0]
20
+ latency = f"{(time.time() - start_time)*1000:.0f}ms"
21
 
22
+ sentiment = "😊 Позитивный" if result['label'] == "POSITIVE" else "😞 Негативный"
23
+ confidence = f"{result['score']:.1%}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ return f"{sentiment} (уверенность: {confidence})", latency
 
26
 
27
  except Exception as e:
28
+ return f"Ошибка: {str(e)}", "0ms"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ # Минимальный интерфейс
31
+ with gr.Blocks(title="Анализатор тональности кофе") as demo:
32
+ gr.Markdown("# Анализатор тональности отзывов о кофе")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  with gr.Row():
35
+ text_input = gr.Textbox(
36
+ label="Введите отзыв о кофе",
37
+ placeholder="Пример: Этот кофе имеет богатый аромат...",
38
+ lines=3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ analyze_btn = gr.Button("Анализировать", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ with gr.Row():
44
+ result_output = gr.Textbox(label="Результат")
45
+ time_output = gr.Textbox(label="Время выполнения")
46
+
47
+ # Примеры
48
+ gr.Examples(
49
+ examples=[
50
+ ["This coffee is absolutely amazing! Best I've ever had."],
51
+ ["Кофе был холодным и безвкусным. Очень разочарован."],
52
+ ["Standard coffee, nothing special. Acceptable for the price."]
53
+ ],
54
+ inputs=text_input
55
  )
56
 
57
+ analyze_btn.click(
58
+ fn=analyze_coffee_sentiment,
59
+ inputs=text_input,
60
+ outputs=[result_output, time_output]
 
 
 
 
 
61
  )
 
 
 
 
 
 
 
 
 
62
 
63
  if __name__ == "__main__":
64
+ demo.launch(debug=False)