DocUA commited on
Commit
9177daf
·
1 Parent(s): 044e3c4

Для деплоя на HF

Browse files
.~lock.kw_questions_tested.csv# DELETED
@@ -1 +0,0 @@
1
- ,docsa,docsa-HP-ProBook-450-G7,03.02.2025 12:17,file:///home/docsa/.config/libreoffice/4;
 
 
classifier_app.py CHANGED
@@ -19,7 +19,7 @@ class Config:
19
  DEFAULT_SIGNATURES_FILE: str = "signatures.npz"
20
  CACHE_FILE: str = "embeddings_cache.db"
21
  MODEL_INFO_FILE: str = "model_info.json"
22
- DEFAULT_OPENAI_MODELS: List[str] = field(default_factory=lambda: ["text-embedding-3-large", "text-embedding-3-small"])
23
  DEFAULT_LOCAL_MODEL: str = "cambridgeltl/SapBERT-from-PubMedBERT-fulltext"
24
 
25
  config = Config()
@@ -33,8 +33,8 @@ class ClassifierApp:
33
  "classes_info": {},
34
  "errors": []
35
  }
36
- self.model_type = "Local" # Додати цей рядок
37
- # self.model_type = "OpenAI" # Нова версія
38
 
39
  def initialize_environment(self) -> Tuple[Dict, Optional[SDCClassifier]]:
40
  """Ініціалізація середовища при першому запуску"""
@@ -56,7 +56,7 @@ class ClassifierApp:
56
  with open(config.MODEL_INFO_FILE, 'r') as f:
57
  model_info = json.load(f)
58
  if not model_info.get('using_local', True):
59
- signatures_model = "text-embedding-3-small" # Модель, яка використовувалась
60
 
61
  # Створюємо класифікатор з тією ж моделлю
62
  self.classifier = SDCClassifier(openai_api_key=os.getenv("OPENAI_API_KEY"))
 
19
  DEFAULT_SIGNATURES_FILE: str = "signatures.npz"
20
  CACHE_FILE: str = "embeddings_cache.db"
21
  MODEL_INFO_FILE: str = "model_info.json"
22
+ DEFAULT_OPENAI_MODELS: List[str] = field(default_factory=lambda: ["text-embedding-3-large"])
23
  DEFAULT_LOCAL_MODEL: str = "cambridgeltl/SapBERT-from-PubMedBERT-fulltext"
24
 
25
  config = Config()
 
33
  "classes_info": {},
34
  "errors": []
35
  }
36
+ # self.model_type = "Local" # Додати цей рядок
37
+ self.model_type = "OpenAI" # Нова версія
38
 
39
  def initialize_environment(self) -> Tuple[Dict, Optional[SDCClassifier]]:
40
  """Ініціалізація середовища при першому запуску"""
 
56
  with open(config.MODEL_INFO_FILE, 'r') as f:
57
  model_info = json.load(f)
58
  if not model_info.get('using_local', True):
59
+ signatures_model = "text-embedding-3-large" # Модель, яка використовувалась
60
 
61
  # Створюємо класифікатор з тією ж моделлю
62
  self.classifier = SDCClassifier(openai_api_key=os.getenv("OPENAI_API_KEY"))
model_info.json CHANGED
@@ -3,15 +3,15 @@
3
  "classes_count": 358,
4
  "signatures_count": 358,
5
  "cache_stats": {
6
- "total_entries": 14822,
7
- "cache_size_mb": 58.9,
8
- "hits": 1159,
9
- "misses": 7066,
10
- "hit_rate_percent": 14.09
11
  },
12
  "local_model": {
13
  "model_name": "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
14
- "device": "cuda",
15
  "embedding_size": 768,
16
  "max_length": 512,
17
  "batch_size": 32
 
3
  "classes_count": 358,
4
  "signatures_count": 358,
5
  "cache_stats": {
6
+ "total_entries": 29633,
7
+ "cache_size_mb": 179.21,
8
+ "hits": 0,
9
+ "misses": 0,
10
+ "hit_rate_percent": 0
11
  },
12
  "local_model": {
13
  "model_name": "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
14
+ "device": "cpu",
15
  "embedding_size": 768,
16
  "max_length": 512,
17
  "batch_size": 32
sdc_classifier.py CHANGED
@@ -11,6 +11,7 @@ class SDCClassifier:
11
  def __init__(self,
12
  openai_api_key: str = None,
13
  cache_path: str = "embeddings_cache.db",
 
14
  local_model: str = "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
15
  device: str = None):
16
  """
@@ -134,34 +135,47 @@ class SDCClassifier:
134
  except (FileNotFoundError, IOError):
135
  return None
136
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  def get_embedding(self, text: str, model_name: str = None) -> list:
138
  """
139
  Отримання ембедінгу тексту
140
 
141
  Args:
142
  text: текст для ембедінгу
143
- model_name: назва моделі (OpenAI) або None для локальної
144
 
145
  Returns:
146
  list: ембедінг тексту
147
  """
148
  # Перевіряємо кеш
149
- cached_embedding = self.cache.get(text, model_name or "local")
 
150
  if cached_embedding is not None:
151
  return cached_embedding.tolist()
152
 
153
  # Отримуємо ембедінг
154
- if self.using_local and model_name is None:
155
  embedding = self.local_embedder.get_embeddings(text)[0]
156
  else:
157
  response = self.client.embeddings.create(
158
  input=text,
159
- model=model_name or "text-embedding-3-large"
160
  )
161
  embedding = response.data[0].embedding
162
 
163
  # Зберігаємо в кеш
164
- self.cache.put(text, model_name or "local", embedding)
165
 
166
  return embedding
167
 
@@ -430,8 +444,8 @@ class SDCClassifier:
430
 
431
  with open(path, 'w', encoding='utf-8') as f:
432
  json.dump(info, f, indent=2)
433
-
434
- def evaluate_classification(self, csv_path: str, threshold: float = 0.3) -> pd.DataFrame:
435
  """
436
  Оцінка класифікації текстів з CSV файлу
437
 
@@ -440,50 +454,73 @@ class SDCClassifier:
440
  threshold: поріг впевненості для класифікації
441
 
442
  Returns:
443
- pd.DataFrame: результати класифікації з додатковими метриками
444
  """
445
  if self.class_signatures is None:
446
  raise ValueError("Спочатку збудуйте signatures!")
447
 
448
  # Завантаження даних
 
449
  df = pd.read_csv(csv_path)
450
  if not {'Category', 'Question'}.issubset(df.columns):
451
  raise ValueError("CSV повинен містити колонки 'Category' та 'Question'")
452
 
453
  # Підготовка результатів
454
  results = []
 
 
 
455
 
456
  for idx, row in df.iterrows():
457
- # Отримуємо ембедінг для питання
458
- emb = np.array(self.get_embedding(row['Question']))
459
-
460
- # Нормалізуємо якщо потрібно
461
- if self.embeddings_mean is not None and self.embeddings_std is not None and not self.using_local:
462
- emb = (emb - self.embeddings_mean) / self.embeddings_std
463
 
464
- # Отримуємо всі передбачення
465
- predictions = self.predict_classes(emb, threshold)
466
-
467
- # Формуємо список класів за рівнем впевненості
468
- sorted_classes = list(predictions.keys())
469
-
470
- # Знаходимо позицію очікуваного класу
471
- expected_class = row['Category']
472
- expected_position = sorted_classes.index(expected_class) + 1 if expected_class in sorted_classes else -1
473
-
474
- # Отримуємо рівень впевненості для очікуваного класу
475
- expected_confidence = predictions.get(expected_class, 0.0)
476
-
477
- # Додаємо результат
478
- results.append({
479
- 'Category': row['Category'],
480
- 'Question': row['Question'],
481
- 'ExpectedClassPosition': expected_position,
482
- 'ExpectedClassConfidence': expected_confidence,
483
- 'ClassificationResults': json.dumps(predictions)
484
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
 
486
- return pd.DataFrame(results)
487
 
488
  def save_evaluation_results(self, df: pd.DataFrame, output_path: str = "evaluation_results.csv") -> str:
489
  """
 
11
  def __init__(self,
12
  openai_api_key: str = None,
13
  cache_path: str = "embeddings_cache.db",
14
+ openai_model = None, # Модель OpenAI за замовчуванням
15
  local_model: str = "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
16
  device: str = None):
17
  """
 
135
  except (FileNotFoundError, IOError):
136
  return None
137
 
138
+ def set_openai_model(self, model_name: str) -> None:
139
+ """
140
+ Встановлює модель OpenAI для використання
141
+
142
+ Args:
143
+ model_name: назва моделі OpenAI
144
+ """
145
+ print(f"Встановлення OpenAI моделі: {model_name}")
146
+ self.using_local = False
147
+ self.local_embedder = None # Видаляємо локальний ембедер
148
+ self.openai_model = model_name # Зберігаємо назву моделі
149
+
150
  def get_embedding(self, text: str, model_name: str = None) -> list:
151
  """
152
  Отримання ембедінгу тексту
153
 
154
  Args:
155
  text: текст для ембедінгу
156
+ model_name: назва моделі (OpenAI) або None для використання поточної
157
 
158
  Returns:
159
  list: ембедінг тексту
160
  """
161
  # Перевіряємо кеш
162
+ model_key = model_name or (self.openai_model if not self.using_local else "local")
163
+ cached_embedding = self.cache.get(text, model_key)
164
  if cached_embedding is not None:
165
  return cached_embedding.tolist()
166
 
167
  # Отримуємо ембедінг
168
+ if self.using_local:
169
  embedding = self.local_embedder.get_embeddings(text)[0]
170
  else:
171
  response = self.client.embeddings.create(
172
  input=text,
173
+ model=model_name or self.openai_model or "text-embedding-3-large"
174
  )
175
  embedding = response.data[0].embedding
176
 
177
  # Зберігаємо в кеш
178
+ self.cache.put(text, model_key, embedding)
179
 
180
  return embedding
181
 
 
444
 
445
  with open(path, 'w', encoding='utf-8') as f:
446
  json.dump(info, f, indent=2)
447
+
448
+ def evaluate_classification(self, csv_path: str, threshold: float = 0.3) -> tuple[pd.DataFrame, dict]:
449
  """
450
  Оцінка класифікації текстів з CSV файлу
451
 
 
454
  threshold: поріг впевненості для класифікації
455
 
456
  Returns:
457
+ tuple[pd.DataFrame, dict]: результати класифікації та статистика
458
  """
459
  if self.class_signatures is None:
460
  raise ValueError("Спочатку збудуйте signatures!")
461
 
462
  # Завантаження даних
463
+ print(f"\nЗавантаження даних з {csv_path}...")
464
  df = pd.read_csv(csv_path)
465
  if not {'Category', 'Question'}.issubset(df.columns):
466
  raise ValueError("CSV повинен містити колонки 'Category' та 'Question'")
467
 
468
  # Підготовка результатів
469
  results = []
470
+ total = len(df)
471
+ print(f"Знайдено {total} рядків для класифікації")
472
+ print(f"Використовується {'OpenAI' if not self.using_local else 'локальна'} модель")
473
 
474
  for idx, row in df.iterrows():
475
+ if idx % 10 == 0: # Логуємо прогрес кожні 10 рядків
476
+ print(f"Обробка рядка {idx + 1}/{total}")
 
 
 
 
477
 
478
+ try:
479
+ # Отримуємо ембедінг для питання
480
+ emb = np.array(self.get_embedding(row['Question']))
481
+
482
+ # Нормалізуємо ембедінг
483
+ emb_norm = np.linalg.norm(emb)
484
+ if emb_norm > 0:
485
+ emb = emb / emb_norm
486
+
487
+ # Отримуємо всі передбачення
488
+ predictions = self.predict_classes(emb, threshold)
489
+
490
+ # Формуємо список класів за рівнем впевненості
491
+ sorted_classes = list(predictions.keys())
492
+
493
+ # Знаходимо позицію очікуваного класу
494
+ expected_class = row['Category']
495
+ expected_position = sorted_classes.index(expected_class) + 1 if expected_class in sorted_classes else -1
496
+
497
+ # Отримуємо рівень впевненості для очікуваного класу
498
+ expected_confidence = predictions.get(expected_class, 0.0)
499
+
500
+ # Додаємо результат
501
+ results.append({
502
+ 'Category': row['Category'],
503
+ 'Question': row['Question'],
504
+ 'ExpectedClassPosition': expected_position,
505
+ 'ExpectedClassConfidence': expected_confidence,
506
+ 'ClassificationResults': json.dumps(predictions, ensure_ascii=False)
507
+ })
508
+
509
+ except Exception as e:
510
+ print(f"Помилка при обробці рядка {idx + 1}: {str(e)}")
511
+ results.append({
512
+ 'Category': row['Category'],
513
+ 'Question': row['Question'],
514
+ 'ExpectedClassPosition': -1,
515
+ 'ExpectedClassConfidence': 0.0,
516
+ 'ClassificationResults': json.dumps({})
517
+ })
518
+
519
+ print("\nОбробка завершена")
520
+ results_df = pd.DataFrame(results)
521
+ statistics = self.get_evaluation_statistics(results_df)
522
 
523
+ return results_df, statistics
524
 
525
  def save_evaluation_results(self, df: pd.DataFrame, output_path: str = "evaluation_results.csv") -> str:
526
  """