winsweb commited on
Commit
db079a5
·
1 Parent(s): 7fb8f94

Deploy FastAPI Hugging Face

Browse files
Dockerfile CHANGED
@@ -1,9 +1,8 @@
1
  # Use a newer Python version for better wheel support
2
  FROM python:3.10-slim
3
 
4
- # Install a LIGHTER Java Runtime (Headless is much faster to install)
5
  RUN apt-get update && \
6
- apt-get install -y --no-install-recommends openjdk-17-jre-headless && \
7
  apt-get clean && \
8
  rm -rf /var/lib/apt/lists/*
9
 
@@ -24,8 +23,8 @@ RUN pip install --no-cache-dir --user -r requirements.txt
24
  # Copy the rest of the application
25
  COPY --chown=user . .
26
 
27
- # Create necessary directories
28
- RUN mkdir -p data/raw_csv_temp data/output_process_data data/strictly_cleaned_data data/output data/save_pdf logs
29
 
30
  # Expose port 7860 (Hugging Face default)
31
  EXPOSE 7860
 
1
  # Use a newer Python version for better wheel support
2
  FROM python:3.10-slim
3
 
4
+ # Install system dependencies (No Java needed for pdfplumber)
5
  RUN apt-get update && \
 
6
  apt-get clean && \
7
  rm -rf /var/lib/apt/lists/*
8
 
 
23
  # Copy the rest of the application
24
  COPY --chown=user . .
25
 
26
+ # Pre-create directories and set permissions (important for the 'user' account)
27
+ RUN mkdir -p data/input data/output data/save_pdf logs data/raw_csv_temp data/output_process_data data/strictly_cleaned_data
28
 
29
  # Expose port 7860 (Hugging Face default)
30
  EXPOSE 7860
requirements.txt CHANGED
@@ -2,7 +2,7 @@
2
  pandas>=1.3.0
3
  numpy>=1.21.0
4
  scikit-learn>=1.0.0
5
- tabula-py>=2.4.0
6
 
7
  # API
8
  fastapi>=0.95.0
 
2
  pandas>=1.3.0
3
  numpy>=1.21.0
4
  scikit-learn>=1.0.0
5
+ pdfplumber>=0.7.0
6
 
7
  # API
8
  fastapi>=0.95.0
telecom_anomaly/utils/pdf_processor.py CHANGED
@@ -1,12 +1,13 @@
1
- import tabula
2
  import pandas as pd
3
  import io
4
  import re
5
  import os
6
  import tempfile
 
7
  from pathlib import Path
8
 
9
- # --- CONFIGURATION (Restored) ---
10
  DATA_BASE = Path("data")
11
  RAW_CSV_DIR = DATA_BASE / "raw_csv_temp"
12
  PROCESS_OUTPUT_DIR = DATA_BASE / "output_process_data"
@@ -17,23 +18,63 @@ def setup_folders():
17
  for folder in [RAW_CSV_DIR, PROCESS_OUTPUT_DIR, STRICT_CLEAN_DIR]:
18
  try:
19
  if not os.path.exists(folder):
20
- os.makedirs(folder)
21
  except Exception as e:
22
  print(f"Warning: Could not create folder {folder}: {e}")
23
 
24
- # --- ORIGINAL FUNCTIONS (Restored) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  def extract_pdf_to_csv(pdf_path, base_name):
27
- """Stage 1: Convert PDF tables to a raw CSV file."""
28
  setup_folders()
29
  csv_path = os.path.join(RAW_CSV_DIR, f"{base_name}_raw.csv")
30
  try:
31
- tabula.convert_into(pdf_path, csv_path, output_format="csv", pages="all", lattice=True)
 
 
32
  return csv_path
33
  except Exception as e:
34
- print(f"Error extracting {pdf_path}: {e}")
35
  return None
36
 
 
 
37
  def process_telecom_data_complete(input_path, base_name):
38
  """Stage 2: Parse raw CSV and repair fragmented rows."""
39
  try:
@@ -54,21 +95,6 @@ def strict_clean_data(file_path, base_name):
54
  df_cleaned.to_csv(final_path, index=False)
55
  return final_path
56
 
57
- # --- IN-MEMORY VERSIONS (Exact same logic) ---
58
-
59
- def extract_pdf_to_lines(pdf_file_path):
60
- """Stage 1 (In-Memory): Returns raw CSV lines."""
61
- with tempfile.NamedTemporaryFile(delete=False, suffix=".csv") as tmp:
62
- tmp_path = tmp.name
63
- try:
64
- tabula.convert_into(pdf_file_path, tmp_path, output_format="csv", pages="all", lattice=True)
65
- with open(tmp_path, 'r', encoding='utf-8') as f:
66
- lines = f.readlines()
67
- return lines
68
- finally:
69
- if os.path.exists(tmp_path):
70
- os.remove(tmp_path)
71
-
72
  def process_telecom_data_df(lines, base_name):
73
  """Stage 2 (In-Memory): Returns DataFrame."""
74
  return _process_lines_logic(lines, base_name, save_files=False)
@@ -77,8 +103,6 @@ def strict_clean_df(df):
77
  """Stage 3 (In-Memory): Returns Cleaned DataFrame."""
78
  return _strict_clean_logic(df)
79
 
80
- # --- SHARED LOGIC (To ensure 100% parity) ---
81
-
82
  def _process_lines_logic(lines, base_name, save_files=False):
83
  header_idx = -1
84
  for i, line in enumerate(lines):
@@ -92,13 +116,21 @@ def _process_lines_logic(lines, base_name, save_files=False):
92
  if save_files:
93
  setup_folders()
94
  customer_text = "".join(lines[:header_idx])
95
- df_customer = pd.read_csv(io.StringIO(customer_text))
96
- df_customer.columns = [re.sub(r'[\r\n\s]+', ' ', c).strip() for c in df_customer.columns]
97
- cust_path = os.path.join(PROCESS_OUTPUT_DIR, f'{base_name}_customer_info.csv')
98
- df_customer.to_csv(cust_path, index=False)
 
 
 
 
99
 
100
  call_text = "".join(lines[header_idx:])
101
- df_raw = pd.read_csv(io.StringIO(call_text))
 
 
 
 
102
  df_raw.columns = [c.strip() for c in df_raw.columns]
103
  main_col = df_raw.columns[0]
104
  df_raw = df_raw[df_raw[main_col].astype(str).str.contains("event_date_time") == False]
@@ -122,6 +154,9 @@ def _process_lines_logic(lines, base_name, save_files=False):
122
  if current_row is not None:
123
  fixed_rows.append(current_row)
124
 
 
 
 
125
  df_calls = pd.DataFrame(fixed_rows)
126
  df_calls[main_col] = df_calls[main_col].str.replace(r'[\r\n]+', '', regex=True).str.replace(r'\s+', ' ', regex=True).str.strip()
127
  dt_series = pd.to_datetime(df_calls[main_col], errors='coerce')
 
1
+ import pdfplumber
2
  import pandas as pd
3
  import io
4
  import re
5
  import os
6
  import tempfile
7
+ import csv
8
  from pathlib import Path
9
 
10
+ # --- CONFIGURATION ---
11
  DATA_BASE = Path("data")
12
  RAW_CSV_DIR = DATA_BASE / "raw_csv_temp"
13
  PROCESS_OUTPUT_DIR = DATA_BASE / "output_process_data"
 
18
  for folder in [RAW_CSV_DIR, PROCESS_OUTPUT_DIR, STRICT_CLEAN_DIR]:
19
  try:
20
  if not os.path.exists(folder):
21
+ os.makedirs(folder, exist_ok=True)
22
  except Exception as e:
23
  print(f"Warning: Could not create folder {folder}: {e}")
24
 
25
+ # --- UPDATED EXTRACTION LOGIC (using pdfplumber) ---
26
+
27
+ def extract_pdf_to_lines(pdf_file_path):
28
+ """Stage 1: Returns raw CSV lines using pdfplumber (no Java required)."""
29
+ setup_folders()
30
+ output_lines = []
31
+
32
+ try:
33
+ with pdfplumber.open(pdf_file_path) as pdf:
34
+ for page in pdf.pages:
35
+ tables = page.extract_tables()
36
+ if not tables:
37
+ # If no tables found, try extracting text directly as a fallback
38
+ text = page.extract_text()
39
+ if text:
40
+ output_lines.extend([line + "\n" for line in text.splitlines()])
41
+ continue
42
+
43
+ for table in tables:
44
+ # Write each table to a CSV-formatted string
45
+ si = io.StringIO()
46
+ cw = csv.writer(si)
47
+ # Clean the data: remove None and replace newlines with spaces
48
+ cleaned_table = []
49
+ for row in table:
50
+ if row:
51
+ cleaned_row = [str(cell).replace('\n', ' ').strip() if cell is not None else "" for cell in row]
52
+ cleaned_table.append(cleaned_row)
53
+
54
+ cw.writerows(cleaned_table)
55
+ output_lines.extend(si.getvalue().splitlines(True))
56
+ si.close()
57
+
58
+ return output_lines
59
+ except Exception as e:
60
+ print(f"Error extracting {pdf_file_path} with pdfplumber: {e}")
61
+ return []
62
 
63
  def extract_pdf_to_csv(pdf_path, base_name):
64
+ """Stage 1: Convert PDF to a raw CSV file using pdfplumber."""
65
  setup_folders()
66
  csv_path = os.path.join(RAW_CSV_DIR, f"{base_name}_raw.csv")
67
  try:
68
+ lines = extract_pdf_to_lines(pdf_path)
69
+ with open(csv_path, 'w', encoding='utf-8') as f:
70
+ f.writelines(lines)
71
  return csv_path
72
  except Exception as e:
73
+ print(f"Error saving CSV for {pdf_path}: {e}")
74
  return None
75
 
76
+ # --- REMAINING LOGIC (Exactly same as before) ---
77
+
78
  def process_telecom_data_complete(input_path, base_name):
79
  """Stage 2: Parse raw CSV and repair fragmented rows."""
80
  try:
 
95
  df_cleaned.to_csv(final_path, index=False)
96
  return final_path
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  def process_telecom_data_df(lines, base_name):
99
  """Stage 2 (In-Memory): Returns DataFrame."""
100
  return _process_lines_logic(lines, base_name, save_files=False)
 
103
  """Stage 3 (In-Memory): Returns Cleaned DataFrame."""
104
  return _strict_clean_logic(df)
105
 
 
 
106
  def _process_lines_logic(lines, base_name, save_files=False):
107
  header_idx = -1
108
  for i, line in enumerate(lines):
 
116
  if save_files:
117
  setup_folders()
118
  customer_text = "".join(lines[:header_idx])
119
+ if customer_text.strip():
120
+ try:
121
+ df_customer = pd.read_csv(io.StringIO(customer_text))
122
+ df_customer.columns = [re.sub(r'[\r\n\s]+', ' ', c).strip() for c in df_customer.columns]
123
+ cust_path = os.path.join(PROCESS_OUTPUT_DIR, f'{base_name}_customer_info.csv')
124
+ df_customer.to_csv(cust_path, index=False)
125
+ except:
126
+ pass
127
 
128
  call_text = "".join(lines[header_idx:])
129
+ try:
130
+ df_raw = pd.read_csv(io.StringIO(call_text))
131
+ except:
132
+ return None
133
+
134
  df_raw.columns = [c.strip() for c in df_raw.columns]
135
  main_col = df_raw.columns[0]
136
  df_raw = df_raw[df_raw[main_col].astype(str).str.contains("event_date_time") == False]
 
154
  if current_row is not None:
155
  fixed_rows.append(current_row)
156
 
157
+ if not fixed_rows:
158
+ return None
159
+
160
  df_calls = pd.DataFrame(fixed_rows)
161
  df_calls[main_col] = df_calls[main_col].str.replace(r'[\r\n]+', '', regex=True).str.replace(r'\s+', ' ', regex=True).str.strip()
162
  dt_series = pd.to_datetime(df_calls[main_col], errors='coerce')