fix
Browse files- dummy.py +13 -27
- main_jsonl.py +6 -15
- main_parquet.py +7 -19
dummy.py
CHANGED
@@ -13,25 +13,16 @@ Użycie:
|
|
13 |
python interactive_classifier.py
|
14 |
"""
|
15 |
|
16 |
-
# --- Importy bibliotek ---
|
17 |
-
|
18 |
-
# Biblioteki standardowe
|
19 |
-
import os
|
20 |
import pickle
|
21 |
import joblib
|
22 |
import pandas as pd
|
23 |
from text_analyzer.analyzer import TextAnalyzer
|
24 |
from text_analyzer import constants
|
25 |
|
26 |
-
# --- Stałe globalne ---
|
27 |
-
|
28 |
MODELS_DIR = 'models'
|
29 |
|
30 |
# --- Ładowanie modeli ---
|
31 |
|
32 |
-
# Modele i analizator są ładowane globalnie tylko raz przy starcie skryptu.
|
33 |
-
# Dzięki temu unika się wielokrotnego, kosztownego odczytu plików z dysku
|
34 |
-
# w pętli interaktywnej, co zapewnia natychmiastową odpowiedź na zapytanie użytkownika.
|
35 |
print("Ładowanie modeli i analizatora...")
|
36 |
|
37 |
with open('models/scaler.pkl', 'rb') as f:
|
@@ -48,7 +39,7 @@ def classify_single_text(text_to_classify: str) -> tuple[str | None, float | Non
|
|
48 |
używając tego samego potoku co w przetwarzaniu wsadowym.
|
49 |
|
50 |
Potok inferencyjny:
|
51 |
-
1. Ekstrakcja cech
|
52 |
2. Uporządkowanie cech zgodnie z `constants.COLUMN_ORDER`.
|
53 |
3. Skalowanie cech za pomocą wczytanego skalera.
|
54 |
4. Predykcja prawdopodobieństw klas za pomocą modelu.
|
@@ -60,7 +51,7 @@ def classify_single_text(text_to_classify: str) -> tuple[str | None, float | Non
|
|
60 |
Returns:
|
61 |
tuple[str | None, float | None]: zawiera:
|
62 |
- Przewidywaną kategorię ('LOW', 'MEDIUM', 'HIGH') lub None w przypadku błędu.
|
63 |
-
- Pewność predykcji (w procentach
|
64 |
"""
|
65 |
# Krok walidacji wejścia
|
66 |
if not isinstance(text_to_classify, str) or not text_to_classify.strip():
|
@@ -69,27 +60,24 @@ def classify_single_text(text_to_classify: str) -> tuple[str | None, float | Non
|
|
69 |
|
70 |
try:
|
71 |
# Krok 1: Ekstrakcja cech. Używamy `analyze_batch` z listą jednoelementową,
|
72 |
-
#
|
73 |
-
# `next()` pobiera pierwszy (i jedyny) wynik z generatora.
|
74 |
features_dict = next(text_analyzer.analyze_batch([text_to_classify]))
|
75 |
|
76 |
-
# Krok 2: Uporządkowanie cech
|
77 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
78 |
|
79 |
-
# Krok 3: Przygotowanie danych do predykcji (DataFrame z jedną próbką)
|
80 |
features_df = pd.DataFrame([ordered_features], columns=constants.COLUMN_ORDER)
|
81 |
input_features_scaled = scaler.transform(features_df)
|
82 |
|
83 |
# Krok 4: Wykonanie predykcji.
|
84 |
-
# Używamy `predict_proba` aby uzyskać pewność (confidence score).
|
85 |
y_pred_proba = classifier.predict_proba(input_features_scaled)
|
86 |
|
87 |
-
# Krok 5: Przetworzenie wyników predykcji
|
88 |
-
|
89 |
-
hardcoded_labels = ["LOW", "MEDIUM", "HIGH"]
|
90 |
category_probabilities = {
|
91 |
label: prob
|
92 |
-
for label, prob in zip(
|
93 |
}
|
94 |
|
95 |
most_probable_category = max(category_probabilities, key=category_probabilities.get)
|
@@ -106,29 +94,27 @@ def classify_single_text(text_to_classify: str) -> tuple[str | None, float | Non
|
|
106 |
# --- Główny blok wykonawczy ---
|
107 |
|
108 |
if __name__ == '__main__':
|
109 |
-
# Wyświetlenie instrukcji dla użytkownika.
|
110 |
print("\n--- Interaktywny Klasyfikator Jakości Tekstu ---")
|
111 |
print("Wpisz tekst i naciśnij Enter, aby uzyskać klasyfikację.")
|
112 |
print("Wpisz 'quit' lub 'exit', aby zakończyć.")
|
113 |
|
114 |
-
# Główna pętla interaktywna
|
115 |
while True:
|
116 |
try:
|
117 |
-
# Read: Pobierz dane wejściowe od użytkownika
|
118 |
user_input = input("\n> ")
|
119 |
|
120 |
-
# Sprawdź warunek wyjścia z pętli.
|
121 |
if user_input.lower() in ['quit', 'exit']:
|
122 |
print("Zamykanie programu...")
|
123 |
break
|
124 |
|
125 |
-
#
|
126 |
category, confidence = classify_single_text(user_input)
|
127 |
|
128 |
-
#
|
129 |
if category is not None:
|
130 |
print(f" └── Predykcja: {category} (Pewność: {confidence}%)")
|
131 |
|
132 |
-
except KeyboardInterrupt:
|
133 |
print("\nPrzerwano przez użytkownika. Zamykanie programu...")
|
134 |
break
|
|
|
13 |
python interactive_classifier.py
|
14 |
"""
|
15 |
|
|
|
|
|
|
|
|
|
16 |
import pickle
|
17 |
import joblib
|
18 |
import pandas as pd
|
19 |
from text_analyzer.analyzer import TextAnalyzer
|
20 |
from text_analyzer import constants
|
21 |
|
|
|
|
|
22 |
MODELS_DIR = 'models'
|
23 |
|
24 |
# --- Ładowanie modeli ---
|
25 |
|
|
|
|
|
|
|
26 |
print("Ładowanie modeli i analizatora...")
|
27 |
|
28 |
with open('models/scaler.pkl', 'rb') as f:
|
|
|
39 |
używając tego samego potoku co w przetwarzaniu wsadowym.
|
40 |
|
41 |
Potok inferencyjny:
|
42 |
+
1. Ekstrakcja cech za pomocą TextAnalyzer.
|
43 |
2. Uporządkowanie cech zgodnie z `constants.COLUMN_ORDER`.
|
44 |
3. Skalowanie cech za pomocą wczytanego skalera.
|
45 |
4. Predykcja prawdopodobieństw klas za pomocą modelu.
|
|
|
51 |
Returns:
|
52 |
tuple[str | None, float | None]: zawiera:
|
53 |
- Przewidywaną kategorię ('LOW', 'MEDIUM', 'HIGH') lub None w przypadku błędu.
|
54 |
+
- Pewność predykcji (w procentach) lub None w przypadku błędu.
|
55 |
"""
|
56 |
# Krok walidacji wejścia
|
57 |
if not isinstance(text_to_classify, str) or not text_to_classify.strip():
|
|
|
60 |
|
61 |
try:
|
62 |
# Krok 1: Ekstrakcja cech. Używamy `analyze_batch` z listą jednoelementową,
|
63 |
+
# `next()` pobiera pierwszy (i jedyny) wynik z generatora
|
|
|
64 |
features_dict = next(text_analyzer.analyze_batch([text_to_classify]))
|
65 |
|
66 |
+
# Krok 2: Uporządkowanie cech
|
67 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
68 |
|
69 |
+
# Krok 3: Przygotowanie danych do predykcji (DataFrame z jedną próbką)
|
70 |
features_df = pd.DataFrame([ordered_features], columns=constants.COLUMN_ORDER)
|
71 |
input_features_scaled = scaler.transform(features_df)
|
72 |
|
73 |
# Krok 4: Wykonanie predykcji.
|
|
|
74 |
y_pred_proba = classifier.predict_proba(input_features_scaled)
|
75 |
|
76 |
+
# Krok 5: Przetworzenie wyników predykcji
|
77 |
+
labels = ["LOW", "MEDIUM", "HIGH"]
|
|
|
78 |
category_probabilities = {
|
79 |
label: prob
|
80 |
+
for label, prob in zip(labels, y_pred_proba[0])
|
81 |
}
|
82 |
|
83 |
most_probable_category = max(category_probabilities, key=category_probabilities.get)
|
|
|
94 |
# --- Główny blok wykonawczy ---
|
95 |
|
96 |
if __name__ == '__main__':
|
|
|
97 |
print("\n--- Interaktywny Klasyfikator Jakości Tekstu ---")
|
98 |
print("Wpisz tekst i naciśnij Enter, aby uzyskać klasyfikację.")
|
99 |
print("Wpisz 'quit' lub 'exit', aby zakończyć.")
|
100 |
|
101 |
+
# Główna pętla interaktywna
|
102 |
while True:
|
103 |
try:
|
104 |
+
# Read: Pobierz dane wejściowe od użytkownika
|
105 |
user_input = input("\n> ")
|
106 |
|
|
|
107 |
if user_input.lower() in ['quit', 'exit']:
|
108 |
print("Zamykanie programu...")
|
109 |
break
|
110 |
|
111 |
+
# Przetwórz dane wejściowe.
|
112 |
category, confidence = classify_single_text(user_input)
|
113 |
|
114 |
+
# Wyświetl wynik
|
115 |
if category is not None:
|
116 |
print(f" └── Predykcja: {category} (Pewność: {confidence}%)")
|
117 |
|
118 |
+
except KeyboardInterrupt:
|
119 |
print("\nPrzerwano przez użytkownika. Zamykanie programu...")
|
120 |
break
|
main_jsonl.py
CHANGED
@@ -22,22 +22,16 @@ from tqdm import tqdm
|
|
22 |
from typing import List
|
23 |
|
24 |
from text_analyzer.analyzer import TextAnalyzer
|
25 |
-
from text_analyzer import constants
|
26 |
|
27 |
# --- Ładowanie modeli i konfiguracja ---
|
28 |
|
29 |
-
# Modele są ładowane na poziomie globalnym. W systemach uniksowych (Linux/macOS)
|
30 |
-
# dzięki mechanizmowi 'fork', procesy-dzieci dziedziczą te obiekty bez ponownego
|
31 |
-
# odczytu z dysku. Na Windowsie ('spawn'), każdy proces-dziecko musi zaimportować
|
32 |
-
# skrypt i załadować modele od nowa.
|
33 |
-
|
34 |
with open('models/scaler.pkl', 'rb') as f:
|
35 |
scaler = pickle.load(f)
|
36 |
classifier = joblib.load("models/model.joblib")
|
37 |
text_analyzer = TextAnalyzer()
|
38 |
|
39 |
-
|
40 |
-
NUM_PROCESSES = 10
|
41 |
|
42 |
class NumpyJSONEncoder(json.JSONEncoder):
|
43 |
"""
|
@@ -61,9 +55,8 @@ def predict_batch(texts: List[str], analyzer: TextAnalyzer, scaler_model, classi
|
|
61 |
"""
|
62 |
all_features = []
|
63 |
|
64 |
-
# Krok 1: Ekstrakcja cech dla wszystkich tekstów
|
65 |
-
|
66 |
-
feature_generator = analyzer.analyze_batch(texts, batch_size=NUM_PROCESSES) # Dostosuj batch_size
|
67 |
for features_dict in tqdm(feature_generator, total=len(texts), desc="Analiza cech"):
|
68 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
69 |
all_features.append(ordered_features)
|
@@ -80,16 +73,14 @@ def predict_batch(texts: List[str], analyzer: TextAnalyzer, scaler_model, classi
|
|
80 |
|
81 |
# Krok 4: Przetworzenie wyników
|
82 |
results = []
|
83 |
-
|
84 |
for single_pred_proba in pred_probas:
|
85 |
category_prob = {
|
86 |
label: prob
|
87 |
-
for label, prob in zip(
|
88 |
}
|
89 |
# Sortujemy, aby znaleźć kategorię z najwyższym prawdopodobieństwem
|
90 |
sorted_category_prob = sorted(category_prob.items(), key=lambda item: item[1], reverse=True)
|
91 |
-
|
92 |
-
# Pobieramy nazwę i wartość
|
93 |
most_probable_category, confidence = sorted_category_prob[0]
|
94 |
|
95 |
results.append((most_probable_category, round(float(confidence) * 100, 2)))
|
|
|
22 |
from typing import List
|
23 |
|
24 |
from text_analyzer.analyzer import TextAnalyzer
|
25 |
+
from text_analyzer import constants
|
26 |
|
27 |
# --- Ładowanie modeli i konfiguracja ---
|
28 |
|
|
|
|
|
|
|
|
|
|
|
29 |
with open('models/scaler.pkl', 'rb') as f:
|
30 |
scaler = pickle.load(f)
|
31 |
classifier = joblib.load("models/model.joblib")
|
32 |
text_analyzer = TextAnalyzer()
|
33 |
|
34 |
+
batch_size = 10
|
|
|
35 |
|
36 |
class NumpyJSONEncoder(json.JSONEncoder):
|
37 |
"""
|
|
|
55 |
"""
|
56 |
all_features = []
|
57 |
|
58 |
+
# Krok 1: Ekstrakcja cech dla wszystkich tekstów
|
59 |
+
feature_generator = analyzer.analyze_batch(texts, batch_size=batch_size)
|
|
|
60 |
for features_dict in tqdm(feature_generator, total=len(texts), desc="Analiza cech"):
|
61 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
62 |
all_features.append(ordered_features)
|
|
|
73 |
|
74 |
# Krok 4: Przetworzenie wyników
|
75 |
results = []
|
76 |
+
labels = ["LOW", "MEDIUM", "HIGH"]
|
77 |
for single_pred_proba in pred_probas:
|
78 |
category_prob = {
|
79 |
label: prob
|
80 |
+
for label, prob in zip(labels, single_pred_proba)
|
81 |
}
|
82 |
# Sortujemy, aby znaleźć kategorię z najwyższym prawdopodobieństwem
|
83 |
sorted_category_prob = sorted(category_prob.items(), key=lambda item: item[1], reverse=True)
|
|
|
|
|
84 |
most_probable_category, confidence = sorted_category_prob[0]
|
85 |
|
86 |
results.append((most_probable_category, round(float(confidence) * 100, 2)))
|
main_parquet.py
CHANGED
@@ -9,7 +9,6 @@ wyniki do nowego pliku w folderze wyjściowym, zachowując oryginalną struktur
|
|
9 |
danych i dodając wyniki klasyfikacji.
|
10 |
"""
|
11 |
|
12 |
-
# --- Importy bibliotek ---
|
13 |
import os
|
14 |
import glob
|
15 |
import time
|
@@ -22,22 +21,16 @@ from tqdm import tqdm
|
|
22 |
from typing import List
|
23 |
|
24 |
from text_analyzer.analyzer import TextAnalyzer
|
25 |
-
from text_analyzer import constants
|
26 |
|
27 |
# --- Ładowanie modeli i konfiguracja ---
|
28 |
|
29 |
-
# Modele są ładowane na poziomie globalnym. W systemach uniksowych (Linux/macOS)
|
30 |
-
# dzięki mechanizmowi 'fork', procesy-dzieci dziedziczą te obiekty bez ponownego
|
31 |
-
# odczytu z dysku. Na Windowsie ('spawn'), każdy proces-dziecko musi zaimportować
|
32 |
-
# skrypt i załadować modele od nowa.
|
33 |
-
|
34 |
with open('models/scaler.pkl', 'rb') as f:
|
35 |
scaler = pickle.load(f)
|
36 |
classifier = joblib.load("models/model.joblib")
|
37 |
text_analyzer = TextAnalyzer()
|
38 |
|
39 |
-
|
40 |
-
NUM_PROCESSES = 10
|
41 |
|
42 |
class NumpyJSONEncoder(json.JSONEncoder):
|
43 |
"""
|
@@ -61,9 +54,8 @@ def predict_batch(texts: List[str], analyzer: TextAnalyzer, scaler_model, classi
|
|
61 |
"""
|
62 |
all_features = []
|
63 |
|
64 |
-
# Krok 1: Ekstrakcja cech dla wszystkich tekstów
|
65 |
-
|
66 |
-
feature_generator = analyzer.analyze_batch(texts, batch_size=NUM_PROCESSES) # Dostosuj batch_size
|
67 |
for features_dict in tqdm(feature_generator, total=len(texts), desc="Analiza cech"):
|
68 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
69 |
all_features.append(ordered_features)
|
@@ -80,16 +72,14 @@ def predict_batch(texts: List[str], analyzer: TextAnalyzer, scaler_model, classi
|
|
80 |
|
81 |
# Krok 4: Przetworzenie wyników
|
82 |
results = []
|
83 |
-
|
84 |
for single_pred_proba in pred_probas:
|
85 |
category_prob = {
|
86 |
label: prob
|
87 |
-
for label, prob in zip(
|
88 |
}
|
89 |
# Sortujemy, aby znaleźć kategorię z najwyższym prawdopodobieństwem
|
90 |
sorted_category_prob = sorted(category_prob.items(), key=lambda item: item[1], reverse=True)
|
91 |
-
|
92 |
-
# Pobieramy nazwę i wartość
|
93 |
most_probable_category, confidence = sorted_category_prob[0]
|
94 |
|
95 |
results.append((most_probable_category, round(float(confidence) * 100, 2)))
|
@@ -119,11 +109,10 @@ def process_parquet_file(input_file: str, output_file: str):
|
|
119 |
print(f"Wczytano {len(texts_to_process)} wierszy. Rozpoczynam przetwarzanie wsadowe...")
|
120 |
|
121 |
# Krok 3: Wywołaj funkcję wsadową (ta część pozostaje bez zmian)
|
122 |
-
# Zakładamy, że predict_batch zwraca listę
|
123 |
results = predict_batch(texts_to_process, text_analyzer, scaler, classifier)
|
124 |
|
125 |
# Krok 4: Dodaj wyniki jako nowe kolumny do ramki danych
|
126 |
-
# "Rozpakowujemy" listę krotek na dwie oddzielne listy
|
127 |
categories = [res[0] for res in results]
|
128 |
confidences = [res[1] for res in results]
|
129 |
|
@@ -132,7 +121,6 @@ def process_parquet_file(input_file: str, output_file: str):
|
|
132 |
|
133 |
# Krok 5: Zapisz zmodyfikowaną ramkę danych do nowego pliku Parquet
|
134 |
try:
|
135 |
-
# index=False zapobiega zapisaniu indeksu pandas jako kolumny w pliku
|
136 |
df.to_parquet(output_file, index=False)
|
137 |
print(df.head(10))
|
138 |
print(f"Pomyślnie zapisano przetworzone dane do pliku {output_file}")
|
|
|
9 |
danych i dodając wyniki klasyfikacji.
|
10 |
"""
|
11 |
|
|
|
12 |
import os
|
13 |
import glob
|
14 |
import time
|
|
|
21 |
from typing import List
|
22 |
|
23 |
from text_analyzer.analyzer import TextAnalyzer
|
24 |
+
from text_analyzer import constants
|
25 |
|
26 |
# --- Ładowanie modeli i konfiguracja ---
|
27 |
|
|
|
|
|
|
|
|
|
|
|
28 |
with open('models/scaler.pkl', 'rb') as f:
|
29 |
scaler = pickle.load(f)
|
30 |
classifier = joblib.load("models/model.joblib")
|
31 |
text_analyzer = TextAnalyzer()
|
32 |
|
33 |
+
batch_size = 10
|
|
|
34 |
|
35 |
class NumpyJSONEncoder(json.JSONEncoder):
|
36 |
"""
|
|
|
54 |
"""
|
55 |
all_features = []
|
56 |
|
57 |
+
# Krok 1: Ekstrakcja cech dla wszystkich tekstów
|
58 |
+
feature_generator = analyzer.analyze_batch(texts, batch_size=batch_size)
|
|
|
59 |
for features_dict in tqdm(feature_generator, total=len(texts), desc="Analiza cech"):
|
60 |
ordered_features = [features_dict.get(fname, 0.0) for fname in constants.COLUMN_ORDER]
|
61 |
all_features.append(ordered_features)
|
|
|
72 |
|
73 |
# Krok 4: Przetworzenie wyników
|
74 |
results = []
|
75 |
+
labels = ["LOW", "MEDIUM", "HIGH"]
|
76 |
for single_pred_proba in pred_probas:
|
77 |
category_prob = {
|
78 |
label: prob
|
79 |
+
for label, prob in zip(labels, single_pred_proba)
|
80 |
}
|
81 |
# Sortujemy, aby znaleźć kategorię z najwyższym prawdopodobieństwem
|
82 |
sorted_category_prob = sorted(category_prob.items(), key=lambda item: item[1], reverse=True)
|
|
|
|
|
83 |
most_probable_category, confidence = sorted_category_prob[0]
|
84 |
|
85 |
results.append((most_probable_category, round(float(confidence) * 100, 2)))
|
|
|
109 |
print(f"Wczytano {len(texts_to_process)} wierszy. Rozpoczynam przetwarzanie wsadowe...")
|
110 |
|
111 |
# Krok 3: Wywołaj funkcję wsadową (ta część pozostaje bez zmian)
|
112 |
+
# Zakładamy, że predict_batch zwraca listę tuple: [(kategoria, pewność), ...]
|
113 |
results = predict_batch(texts_to_process, text_analyzer, scaler, classifier)
|
114 |
|
115 |
# Krok 4: Dodaj wyniki jako nowe kolumny do ramki danych
|
|
|
116 |
categories = [res[0] for res in results]
|
117 |
confidences = [res[1] for res in results]
|
118 |
|
|
|
121 |
|
122 |
# Krok 5: Zapisz zmodyfikowaną ramkę danych do nowego pliku Parquet
|
123 |
try:
|
|
|
124 |
df.to_parquet(output_file, index=False)
|
125 |
print(df.head(10))
|
126 |
print(f"Pomyślnie zapisano przetworzone dane do pliku {output_file}")
|