Spaces:
Runtime error
Runtime error
Enhance error handling and logging in initialization process
Browse files- Add detailed logging and error tracking in ClassifierApp initialization
- Improve error reporting in main() function
- Add sync_system_info() method to update system information
- Refactor model creation and initialization with more robust error handling
- Update model_info.json with latest signature and cache statistics
Ніби робочий варіант, але потрібно розібратися із створенням і оновленням сигнатур різними моделями!
- app.py +32 -24
- classifier_app.py +113 -29
- model_info.json +6 -6
app.py
CHANGED
@@ -2,9 +2,13 @@ import gradio as gr
|
|
2 |
import torch
|
3 |
import os
|
4 |
from classifier_app import ClassifierApp, config
|
|
|
5 |
|
6 |
def create_interface(app: ClassifierApp) -> gr.Blocks:
|
7 |
"""Створення веб-інтерфейсу"""
|
|
|
|
|
|
|
8 |
with gr.Blocks() as demo:
|
9 |
gr.Markdown("# SDC Classifier")
|
10 |
|
@@ -113,19 +117,6 @@ def create_interface(app: ClassifierApp) -> gr.Blocks:
|
|
113 |
save_btn = gr.Button("Зберегти розмічені дані")
|
114 |
save_out = gr.Label()
|
115 |
|
116 |
-
gr.Markdown("""
|
117 |
-
### Інструкція:
|
118 |
-
1. У вкладці "Налаштування моделі" можна:
|
119 |
-
- Вибрати тип моделі (OpenAI або Local)
|
120 |
-
- Налаштувати параметри вибраної моделі
|
121 |
-
- Завантажити новий JSON файл з класами
|
122 |
-
- Примусово перебудувати signatures
|
123 |
-
2. Після зміни налаштувань натисніть "Оновити signatures"
|
124 |
-
3. Використовуйте повзунок "Поріг впевненості" для фільтрації результатів
|
125 |
-
4. На вкладці "Пакетна обробка" можна аналізувати багато повідомлень
|
126 |
-
5. Результати можна зберегти в CSV файл
|
127 |
-
""")
|
128 |
-
|
129 |
# Підключення обробників подій
|
130 |
model_type.change(
|
131 |
fn=app.update_model_inputs,
|
@@ -185,20 +176,37 @@ def create_interface(app: ClassifierApp) -> gr.Blocks:
|
|
185 |
|
186 |
return demo
|
187 |
|
|
|
188 |
def main():
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
print("
|
194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
|
200 |
-
|
201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
|
203 |
if __name__ == "__main__":
|
204 |
main()
|
|
|
2 |
import torch
|
3 |
import os
|
4 |
from classifier_app import ClassifierApp, config
|
5 |
+
from typing import Dict
|
6 |
|
7 |
def create_interface(app: ClassifierApp) -> gr.Blocks:
|
8 |
"""Створення веб-інтерфейсу"""
|
9 |
+
# Синхронізуємо інформацію перед створенням інтерфейсу
|
10 |
+
initial_info = app.sync_system_info()
|
11 |
+
|
12 |
with gr.Blocks() as demo:
|
13 |
gr.Markdown("# SDC Classifier")
|
14 |
|
|
|
117 |
save_btn = gr.Button("Зберегти розмічені дані")
|
118 |
save_out = gr.Label()
|
119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
# Підключення обробників подій
|
121 |
model_type.change(
|
122 |
fn=app.update_model_inputs,
|
|
|
176 |
|
177 |
return demo
|
178 |
|
179 |
+
|
180 |
def main():
|
181 |
+
try:
|
182 |
+
print("\nЗапуск програми...")
|
183 |
+
app = ClassifierApp()
|
184 |
+
|
185 |
+
print("\nПочаток ініціалізації середовища...")
|
186 |
+
init_result, classifier = app.initialize_environment()
|
187 |
+
|
188 |
+
print("\nРезультат ініціалізації:")
|
189 |
+
print(f"Статус: {init_result['status']}")
|
190 |
+
|
191 |
+
if init_result.get('errors'):
|
192 |
+
print("Помилки:", init_result['errors'])
|
193 |
+
|
194 |
+
if classifier is None or init_result["status"] != "success":
|
195 |
+
print("\nНе вдалося ініціалізувати середовище")
|
196 |
+
return
|
197 |
|
198 |
+
print(f"\nІнформація про систему:")
|
199 |
+
print(f"Кількість завантажених класів: {len(init_result['classes_info']['classes_list'])}")
|
200 |
+
print(f"Сигнатури: {'Завантажено' if os.path.exists(config.DEFAULT_SIGNATURES_FILE) else 'Створюються'}")
|
201 |
|
202 |
+
demo = create_interface(app)
|
203 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
|
204 |
+
|
205 |
+
except Exception as e:
|
206 |
+
print(f"\nКритична помилка в main(): {str(e)}")
|
207 |
+
import traceback
|
208 |
+
print("\nДетальний traceback:")
|
209 |
+
print(traceback.format_exc())
|
210 |
|
211 |
if __name__ == "__main__":
|
212 |
main()
|
classifier_app.py
CHANGED
@@ -32,53 +32,98 @@ class ClassifierApp:
|
|
32 |
|
33 |
def initialize_environment(self) -> Tuple[Dict, Optional[SDCClassifier]]:
|
34 |
"""Ініціалізація середовища при першому запуску"""
|
35 |
-
|
36 |
-
if not os.path.exists(config.DEFAULT_CLASSES_FILE):
|
37 |
-
self.initial_info["errors"].append(
|
38 |
-
f"ПОМИЛКА: Файл {config.DEFAULT_CLASSES_FILE} не знайдено!"
|
39 |
-
)
|
40 |
-
self.initial_info["status"] = "error"
|
41 |
-
return self.initial_info, None
|
42 |
-
|
43 |
try:
|
44 |
-
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
"
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
|
|
53 |
if os.path.exists(config.DEFAULT_SIGNATURES_FILE):
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
else:
|
|
|
57 |
self.initial_info["status"] = "creating_signatures"
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
self.initial_info["status"] = "error"
|
66 |
return self.initial_info, None
|
67 |
|
|
|
68 |
try:
|
69 |
self.classifier.save_model_info(config.MODEL_INFO_FILE)
|
70 |
with open(config.MODEL_INFO_FILE, "r") as f:
|
71 |
self.initial_info["model_info"] = json.load(f)
|
72 |
|
73 |
self.initial_info["status"] = "success"
|
|
|
74 |
return self.initial_info, self.classifier
|
75 |
-
|
76 |
-
except
|
|
|
77 |
self.initial_info["errors"].append(f"Помилка при читанні model_info: {str(e)}")
|
78 |
self.initial_info["status"] = "error"
|
79 |
return self.initial_info, None
|
80 |
-
|
81 |
except Exception as e:
|
|
|
82 |
self.initial_info["errors"].append(f"ПОМИЛКА при ініціалізації: {str(e)}")
|
83 |
self.initial_info["status"] = "error"
|
84 |
return self.initial_info, None
|
@@ -91,10 +136,16 @@ class ClassifierApp:
|
|
91 |
device: Optional[str] = None
|
92 |
) -> SDCClassifier:
|
93 |
"""Створення класифікатора з відповідними параметрами"""
|
|
|
|
|
94 |
if model_type == "OpenAI":
|
95 |
-
|
|
|
96 |
else:
|
97 |
-
|
|
|
|
|
|
|
98 |
|
99 |
def update_model_inputs(
|
100 |
self,
|
@@ -261,6 +312,39 @@ class ClassifierApp:
|
|
261 |
except Exception as e:
|
262 |
return f"Помилка: {str(e)}"
|
263 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
@staticmethod
|
265 |
def update_system_markdown(info: Dict) -> str:
|
266 |
"""Оновлення Markdown з системною інформацією"""
|
|
|
32 |
|
33 |
def initialize_environment(self) -> Tuple[Dict, Optional[SDCClassifier]]:
|
34 |
"""Ініціалізація середовища при першому запуску"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
try:
|
36 |
+
# Перевіряємо наявність необхідних файлів
|
37 |
+
if not os.path.exists(config.DEFAULT_CLASSES_FILE):
|
38 |
+
self.initial_info["errors"].append(
|
39 |
+
f"ПОМИЛКА: Файл {config.DEFAULT_CLASSES_FILE} не знайдено!"
|
40 |
+
)
|
41 |
+
self.initial_info["status"] = "error"
|
42 |
+
print(f"\nПомилка: Файл {config.DEFAULT_CLASSES_FILE} не знайдено!")
|
43 |
+
return self.initial_info, None
|
44 |
+
|
45 |
+
print("\nСтворення класифікатора...")
|
46 |
+
try:
|
47 |
+
# Визначаємо яка модель використовувалась для сигнатур
|
48 |
+
signatures_model = None
|
49 |
+
if os.path.exists(config.MODEL_INFO_FILE):
|
50 |
+
with open(config.MODEL_INFO_FILE, 'r') as f:
|
51 |
+
model_info = json.load(f)
|
52 |
+
if not model_info.get('using_local', True):
|
53 |
+
signatures_model = "text-embedding-3-small" # Модель, яка використовувалась
|
54 |
+
|
55 |
+
# Створюємо класифікатор з тією ж моделлю
|
56 |
+
self.classifier = SDCClassifier(openai_api_key=os.getenv("OPENAI_API_KEY"))
|
57 |
+
print(f"Використовується модель: {signatures_model or 'local'}")
|
58 |
+
|
59 |
+
except Exception as e:
|
60 |
+
print(f"\nПомилка при створенні класифікатора: {str(e)}")
|
61 |
+
self.initial_info["errors"].append(f"Помилка при створенні класифікатора: {str(e)}")
|
62 |
+
self.initial_info["status"] = "error"
|
63 |
+
return self.initial_info, None
|
64 |
|
65 |
+
print("\nЗавантаження класів...")
|
66 |
+
try:
|
67 |
+
classes = self.classifier.load_classes(config.DEFAULT_CLASSES_FILE)
|
68 |
+
self.initial_info["classes_info"] = {
|
69 |
+
"total_classes": len(classes),
|
70 |
+
"classes_list": list(classes.keys()),
|
71 |
+
"hints_per_class": {cls: len(hints) for cls, hints in classes.items()}
|
72 |
+
}
|
73 |
+
except Exception as e:
|
74 |
+
print(f"\nПомилка при завантаженні класів: {str(e)}")
|
75 |
+
self.initial_info["errors"].append(f"Помилка при завантаженні класів: {str(e)}")
|
76 |
+
self.initial_info["status"] = "error"
|
77 |
+
return self.initial_info, None
|
78 |
|
79 |
+
print("\nПеревірка та завантаження сигнатур...")
|
80 |
if os.path.exists(config.DEFAULT_SIGNATURES_FILE):
|
81 |
+
try:
|
82 |
+
self.classifier.load_signatures(config.DEFAULT_SIGNATURES_FILE)
|
83 |
+
self.initial_info["status"] = "success"
|
84 |
+
print("Сигнатури завантажено успішно")
|
85 |
+
except Exception as e:
|
86 |
+
print(f"\nПомилка при завантаженні сигнатур: {str(e)}")
|
87 |
+
self.initial_info["errors"].append(f"Помилка при завантаженні сигнатур: {str(e)}")
|
88 |
+
self.initial_info["status"] = "error"
|
89 |
+
return self.initial_info, None
|
90 |
else:
|
91 |
+
print("\nСтворення нових сигнатур...")
|
92 |
self.initial_info["status"] = "creating_signatures"
|
93 |
+
try:
|
94 |
+
result = self.classifier.initialize_signatures(
|
95 |
+
force_rebuild=True,
|
96 |
+
signatures_file=config.DEFAULT_SIGNATURES_FILE
|
97 |
+
)
|
98 |
+
if isinstance(result, str) and "error" in result.lower():
|
99 |
+
print(f"\nПомилка при створенні сигнатур: {result}")
|
100 |
+
self.initial_info["errors"].append(result)
|
101 |
+
self.initial_info["status"] = "error"
|
102 |
+
return self.initial_info, None
|
103 |
+
except Exception as e:
|
104 |
+
print(f"\nПомилка при створенні сигнатур: {str(e)}")
|
105 |
+
self.initial_info["errors"].append(f"Помилка при створенні сигнатур: {str(e)}")
|
106 |
self.initial_info["status"] = "error"
|
107 |
return self.initial_info, None
|
108 |
|
109 |
+
print("\nЗбереження інформації про модель...")
|
110 |
try:
|
111 |
self.classifier.save_model_info(config.MODEL_INFO_FILE)
|
112 |
with open(config.MODEL_INFO_FILE, "r") as f:
|
113 |
self.initial_info["model_info"] = json.load(f)
|
114 |
|
115 |
self.initial_info["status"] = "success"
|
116 |
+
print("\nІніціалізація завершена успішно")
|
117 |
return self.initial_info, self.classifier
|
118 |
+
|
119 |
+
except Exception as e:
|
120 |
+
print(f"\nПомилка при збереженні інформації про модель: {str(e)}")
|
121 |
self.initial_info["errors"].append(f"Помилка при читанні model_info: {str(e)}")
|
122 |
self.initial_info["status"] = "error"
|
123 |
return self.initial_info, None
|
124 |
+
|
125 |
except Exception as e:
|
126 |
+
print(f"\nЗагальна помилка при ініціалізації: {str(e)}")
|
127 |
self.initial_info["errors"].append(f"ПОМИЛКА при ініціалізації: {str(e)}")
|
128 |
self.initial_info["status"] = "error"
|
129 |
return self.initial_info, None
|
|
|
136 |
device: Optional[str] = None
|
137 |
) -> SDCClassifier:
|
138 |
"""Створення класифікатора з відповідними параметрами"""
|
139 |
+
classifier = SDCClassifier()
|
140 |
+
|
141 |
if model_type == "OpenAI":
|
142 |
+
if hasattr(classifier, 'set_openai_model'):
|
143 |
+
classifier.set_openai_model(openai_model)
|
144 |
else:
|
145 |
+
if hasattr(classifier, 'set_local_model'):
|
146 |
+
classifier.set_local_model(local_model, device)
|
147 |
+
|
148 |
+
return classifier
|
149 |
|
150 |
def update_model_inputs(
|
151 |
self,
|
|
|
312 |
except Exception as e:
|
313 |
return f"Помилка: {str(e)}"
|
314 |
|
315 |
+
def sync_system_info(self) -> Dict:
|
316 |
+
"""Синхронізація системної інформації"""
|
317 |
+
try:
|
318 |
+
if self.classifier is None:
|
319 |
+
raise ValueError("Класифікатор не ініціалізовано")
|
320 |
+
|
321 |
+
self.classifier.save_model_info(config.MODEL_INFO_FILE)
|
322 |
+
with open(config.MODEL_INFO_FILE, "r") as f:
|
323 |
+
model_info = json.load(f)
|
324 |
+
|
325 |
+
self.initial_info = {
|
326 |
+
"status": "success",
|
327 |
+
"model_info": model_info,
|
328 |
+
"classes_info": {
|
329 |
+
"total_classes": len(self.classifier.classes_json),
|
330 |
+
"classes_list": list(self.classifier.classes_json.keys()),
|
331 |
+
"hints_per_class": {
|
332 |
+
cls: len(hints)
|
333 |
+
for cls, hints in self.classifier.classes_json.items()
|
334 |
+
}
|
335 |
+
},
|
336 |
+
"errors": []
|
337 |
+
}
|
338 |
+
return self.initial_info
|
339 |
+
except Exception as e:
|
340 |
+
self.initial_info = {
|
341 |
+
"status": "error",
|
342 |
+
"model_info": {},
|
343 |
+
"classes_info": {},
|
344 |
+
"errors": [str(e)]
|
345 |
+
}
|
346 |
+
return self.initial_info
|
347 |
+
|
348 |
@staticmethod
|
349 |
def update_system_markdown(info: Dict) -> str:
|
350 |
"""Оновлення Markdown з системною інформацією"""
|
model_info.json
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
{
|
2 |
"using_local": true,
|
3 |
"classes_count": 131,
|
4 |
-
"signatures_count":
|
5 |
"cache_stats": {
|
6 |
-
"total_entries":
|
7 |
-
"cache_size_mb":
|
8 |
-
"hits":
|
9 |
-
"misses":
|
10 |
-
"hit_rate_percent":
|
11 |
},
|
12 |
"local_model": {
|
13 |
"model_name": "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
|
|
|
1 |
{
|
2 |
"using_local": true,
|
3 |
"classes_count": 131,
|
4 |
+
"signatures_count": 131,
|
5 |
"cache_stats": {
|
6 |
+
"total_entries": 8746,
|
7 |
+
"cache_size_mb": 51.91,
|
8 |
+
"hits": 122,
|
9 |
+
"misses": 1450,
|
10 |
+
"hit_rate_percent": 7.76
|
11 |
},
|
12 |
"local_model": {
|
13 |
"model_name": "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
|