Yuvvan Talreja commited on
Commit
e13d740
·
1 Parent(s): 881f8b5
Files changed (4) hide show
  1. Dockerfile +11 -0
  2. fastapi_app.py +27 -7
  3. requirements.txt +2 -1
  4. topic_segmenter.py +64 -11
Dockerfile CHANGED
@@ -6,6 +6,7 @@ WORKDIR /app
6
  RUN apt-get update && apt-get install -y --no-install-recommends \
7
  ffmpeg \
8
  build-essential \
 
9
  && apt-get clean \
10
  && rm -rf /var/lib/apt/lists/*
11
 
@@ -13,9 +14,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
13
  COPY requirements.txt .
14
  RUN pip install --no-cache-dir -r requirements.txt
15
 
 
 
 
 
 
 
 
16
  # Run NLTK downloads
17
  RUN python -m nltk.downloader punkt wordnet
18
 
 
 
 
19
  # Copy the rest of the application
20
  COPY . .
21
 
 
6
  RUN apt-get update && apt-get install -y --no-install-recommends \
7
  ffmpeg \
8
  build-essential \
9
+ git \
10
  && apt-get clean \
11
  && rm -rf /var/lib/apt/lists/*
12
 
 
14
  COPY requirements.txt .
15
  RUN pip install --no-cache-dir -r requirements.txt
16
 
17
+ # Install additional dependencies directly
18
+ RUN pip install --no-cache-dir sentence-transformers>=2.2.2
19
+
20
+ # Download model files
21
+ RUN python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"
22
+ RUN python -c "from transformers import pipeline; pipeline('automatic-speech-recognition', 'openai/whisper-base', from_tf=True)"
23
+
24
  # Run NLTK downloads
25
  RUN python -m nltk.downloader punkt wordnet
26
 
27
+ # Cache the torch hub directory to avoid unnecessary downloads
28
+ RUN mkdir -p /root/.cache/torch/hub
29
+
30
  # Copy the rest of the application
31
  COPY . .
32
 
fastapi_app.py CHANGED
@@ -86,13 +86,33 @@ def get_model(model_name):
86
 
87
  logging.info(f"Converting Xenova model {model_name} to {hf_model_name}")
88
 
89
- models[model_name] = pipeline(
90
- "automatic-speech-recognition",
91
- hf_model_name,
92
- chunk_length_s=30,
93
- stride_length_s=5
94
- )
95
- logging.info(f"Model {model_name} loaded successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  return models[model_name]
97
 
98
  def process_audio(audio_data, sample_rate=16000, model_name="openai/whisper-base"):
 
86
 
87
  logging.info(f"Converting Xenova model {model_name} to {hf_model_name}")
88
 
89
+ try:
90
+ models[model_name] = pipeline(
91
+ "automatic-speech-recognition",
92
+ hf_model_name,
93
+ chunk_length_s=30,
94
+ stride_length_s=5,
95
+ from_tf=True, # Added this parameter to handle TensorFlow models
96
+ model_kwargs={"use_fast": True}, # Use fast version of tokenizer
97
+ tokenizer_kwargs={"use_fast": True}
98
+ )
99
+ logging.info(f"Model {model_name} loaded successfully")
100
+ except Exception as e:
101
+ logging.error(f"Error loading model with from_tf=True, trying with from_tf=False: {str(e)}")
102
+ try:
103
+ # Fallback to PyTorch version if TensorFlow fails
104
+ models[model_name] = pipeline(
105
+ "automatic-speech-recognition",
106
+ hf_model_name,
107
+ chunk_length_s=30,
108
+ stride_length_s=5,
109
+ model_kwargs={"use_fast": True}, # Use fast version of tokenizer
110
+ tokenizer_kwargs={"use_fast": True}
111
+ )
112
+ logging.info(f"Model {model_name} loaded successfully with from_tf=False")
113
+ except Exception as e2:
114
+ logging.error(f"Failed to load model {model_name}: {str(e2)}")
115
+ raise RuntimeError(f"Failed to load model {model_name}: {str(e2)}")
116
  return models[model_name]
117
 
118
  def process_audio(audio_data, sample_rate=16000, model_name="openai/whisper-base"):
requirements.txt CHANGED
@@ -7,7 +7,8 @@ numpy>=1.19.0
7
  scikit-learn>=1.0.0
8
  nltk>=3.6.0
9
  torch>=1.9.0
10
- transformers>=4.0.0
 
11
  keybert>=0.5.0
12
  spacy>=3.0.0
13
  librosa>=0.8.0
 
7
  scikit-learn>=1.0.0
8
  nltk>=3.6.0
9
  torch>=1.9.0
10
+ transformers>=4.20.0
11
+ sentence-transformers>=2.2.2
12
  keybert>=0.5.0
13
  spacy>=3.0.0
14
  librosa>=0.8.0
topic_segmenter.py CHANGED
@@ -10,7 +10,7 @@ from sklearn.cluster import AgglomerativeClustering
10
 
11
  class TopicSegmenter:
12
  def __init__(self, window_size=3, similarity_threshold=0.2, context_size=2, min_segment_size=2, topic_similarity_threshold=0.3,
13
- max_topics=8, hierarchical_threshold=0.6):
14
  self.window_size = window_size
15
  self.similarity_threshold = similarity_threshold
16
  self.context_size = context_size
@@ -18,7 +18,25 @@ class TopicSegmenter:
18
  self.topic_similarity_threshold = topic_similarity_threshold
19
  self.max_topics = max_topics # Maximum number of main topics
20
  self.hierarchical_threshold = hierarchical_threshold # Threshold for hierarchical clustering
21
- self.keyword_extractor = KeyBERT()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  self.vectorizer = TfidfVectorizer(
24
  stop_words='english',
@@ -102,16 +120,51 @@ class TopicSegmenter:
102
  text = ' '.join(sentences)
103
  else:
104
  text = sentences
105
-
106
- keywords = self.keyword_extractor.extract_keywords(
107
- text,
108
- keyphrase_ngram_range=(1, 2), # Allow for 1-2 word keyphrases
109
- stop_words='english',
110
- top_n=top_n
111
- )
112
 
113
- sorted_keywords = sorted(keywords, key=lambda x: x[1], reverse=True)
114
- return [kw[0] for kw in sorted_keywords[:top_n]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  def detect_speaker_changes(self, text):
117
  """
 
10
 
11
  class TopicSegmenter:
12
  def __init__(self, window_size=3, similarity_threshold=0.2, context_size=2, min_segment_size=2, topic_similarity_threshold=0.3,
13
+ max_topics=8, hierarchical_threshold=0.6, model_name="all-MiniLM-L6-v2"):
14
  self.window_size = window_size
15
  self.similarity_threshold = similarity_threshold
16
  self.context_size = context_size
 
18
  self.topic_similarity_threshold = topic_similarity_threshold
19
  self.max_topics = max_topics # Maximum number of main topics
20
  self.hierarchical_threshold = hierarchical_threshold # Threshold for hierarchical clustering
21
+
22
+ try:
23
+ # Explicitly set the model to a lightweight and compatible one
24
+ import os
25
+ os.environ["TOKENIZERS_PARALLELISM"] = "false" # Prevent parallelism warning
26
+
27
+ # Try using sentence-transformers directly first
28
+ try:
29
+ from sentence_transformers import SentenceTransformer
30
+ embedding_model = SentenceTransformer(model_name)
31
+ self.keyword_extractor = KeyBERT(model=embedding_model)
32
+ except (ImportError, ValueError, RuntimeError) as e:
33
+ # Fallback to default model with lower-level settings
34
+ self.keyword_extractor = KeyBERT(model='distilbert-base-nli-mean-tokens')
35
+ except Exception as e:
36
+ import logging
37
+ logging.error(f"Error initializing KeyBERT model: {str(e)}")
38
+ # Last resort fallback to simple keyword extraction without a model
39
+ self.keyword_extractor = None
40
 
41
  self.vectorizer = TfidfVectorizer(
42
  stop_words='english',
 
120
  text = ' '.join(sentences)
121
  else:
122
  text = sentences
 
 
 
 
 
 
 
123
 
124
+ # If KeyBERT was not properly initialized, use TF-IDF as a fallback
125
+ if self.keyword_extractor is None:
126
+ try:
127
+ # Use scikit-learn's TF-IDF for keyword extraction as fallback
128
+ from sklearn.feature_extraction.text import TfidfVectorizer
129
+
130
+ # Create a temporary vectorizer for this text only
131
+ temp_vectorizer = TfidfVectorizer(
132
+ max_features=50,
133
+ stop_words='english',
134
+ ngram_range=(1, 2)
135
+ )
136
+
137
+ # Fit and transform on this specific text
138
+ tfidf_matrix = temp_vectorizer.fit_transform([text])
139
+ feature_names = temp_vectorizer.get_feature_names_out()
140
+
141
+ # Get top keywords based on TF-IDF scores
142
+ tfidf_scores = tfidf_matrix.toarray()[0]
143
+ scored_tokens = [(feature_names[i], tfidf_scores[i]) for i in range(len(feature_names))]
144
+ sorted_tokens = sorted(scored_tokens, key=lambda x: x[1], reverse=True)
145
+
146
+ return [token for token, score in sorted_tokens[:top_n]]
147
+ except Exception as e:
148
+ import logging
149
+ logging.error(f"Error in TF-IDF fallback keyword extraction: {str(e)}")
150
+ # If everything fails, just return some generic keywords
151
+ return ["topic", "section", "content"]
152
+
153
+ try:
154
+ keywords = self.keyword_extractor.extract_keywords(
155
+ text,
156
+ keyphrase_ngram_range=(1, 2), # Allow for 1-2 word keyphrases
157
+ stop_words='english',
158
+ top_n=top_n
159
+ )
160
+
161
+ sorted_keywords = sorted(keywords, key=lambda x: x[1], reverse=True)
162
+ return [kw[0] for kw in sorted_keywords[:top_n]]
163
+ except Exception as e:
164
+ import logging
165
+ logging.error(f"Error in KeyBERT keyword extraction: {str(e)}")
166
+ # Fall back to TF-IDF method
167
+ return self.extract_keywords(text, top_n)
168
 
169
  def detect_speaker_changes(self, text):
170
  """