Okba-Sa-20 commited on
Commit
d6c3df7
·
verified ·
1 Parent(s): 1e634b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +203 -4
app.py CHANGED
@@ -22,19 +22,218 @@ nltk.download('stopwords', quiet=True)
22
  # --- Custom Layers ---
23
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
24
  class FeatureExtractor(tf.keras.layers.Layer):
25
- # Keep the same implementation from training code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
28
  class SentimentAdjuster(tf.keras.layers.Layer):
29
- # Keep the same implementation from training code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
32
  class SimpleAttention(tf.keras.layers.Layer):
33
- # Keep the same implementation from training code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  # --- Text Preprocessing ---
36
  def preprocess_for_lstm(text, remove_stopwords=False):
37
- # Keep the same implementation from training code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  # --- Load model resources ---
40
  @st.cache_resource
 
22
  # --- Custom Layers ---
23
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
24
  class FeatureExtractor(tf.keras.layers.Layer):
25
+ def __init__(self, **kwargs):
26
+ super(FeatureExtractor, self).__init__(**kwargs)
27
+
28
+ def build(self, input_shape):
29
+ self.contrast_kernel = self.add_weight(
30
+ name='contrast_kernel',
31
+ shape=(input_shape[-1], 1),
32
+ initializer='glorot_uniform'
33
+ )
34
+ self.negation_kernel = self.add_weight(
35
+ name='negation_kernel',
36
+ shape=(input_shape[-1], 1),
37
+ initializer='glorot_uniform'
38
+ )
39
+ self.intensifier_kernel = self.add_weight(
40
+ name='intensifier_kernel',
41
+ shape=(input_shape[-1], 1),
42
+ initializer='glorot_uniform'
43
+ )
44
+ super(FeatureExtractor, self).build(input_shape)
45
+
46
+ def call(self, inputs):
47
+ # Detect features
48
+ contrast = tf.tensordot(inputs, self.contrast_kernel, axes=1)
49
+ contrast = tf.squeeze(contrast, axis=-1)
50
+
51
+ negation = tf.tensordot(inputs, self.negation_kernel, axes=1)
52
+ negation = tf.squeeze(negation, axis=-1)
53
+
54
+ intensifier = tf.tensordot(inputs, self.intensifier_kernel, axes=1)
55
+ intensifier = tf.squeeze(intensifier, axis=-1)
56
+
57
+ # Combine features
58
+ features = tf.stack([contrast, negation, intensifier], axis=-1)
59
+ return features
60
+
61
+ def compute_output_shape(self, input_shape):
62
+ return (input_shape[0], input_shape[1], 3)
63
 
64
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
65
  class SentimentAdjuster(tf.keras.layers.Layer):
66
+ def __init__(self, **kwargs):
67
+ super(SentimentAdjuster, self).__init__(**kwargs)
68
+
69
+ def build(self, input_shape):
70
+ self.contrast_weight = self.add_weight(
71
+ name='contrast_weight',
72
+ shape=(3,),
73
+ initializer='zeros'
74
+ )
75
+ self.negation_weight = self.add_weight(
76
+ name='negation_weight',
77
+ shape=(3,),
78
+ initializer='zeros'
79
+ )
80
+ super(SentimentAdjuster, self).build(input_shape)
81
+
82
+ def call(self, inputs):
83
+ predictions, features = inputs
84
+
85
+ # Aggregate features (max pooling)
86
+ contrast_features = tf.reduce_max(features[..., 0], axis=1)
87
+ negation_features = tf.reduce_max(features[..., 1], axis=1)
88
+ intensifier_features = tf.reduce_max(features[..., 2], axis=1)
89
+
90
+ # Rule 1: Contrast adjustment
91
+ contrast_mask = tf.cast(contrast_features > 0.5, tf.float32)
92
+ contrast_adjustment = contrast_mask * self.contrast_weight[0]
93
+
94
+ # Rule 2: Negation adjustment
95
+ negation_mask = tf.cast(negation_features > 0.5, tf.float32)
96
+ negation_adjustment = negation_mask * self.negation_weight[0]
97
+
98
+ # Rule 3: Intensifier adjustment
99
+ intensifier_mask = tf.cast(intensifier_features > 0.5, tf.float32)
100
+ intensifier_adjustment = intensifier_mask * self.contrast_weight[1]
101
+
102
+ # Combine adjustments
103
+ total_adjustment = contrast_adjustment + negation_adjustment + intensifier_adjustment
104
+
105
+ # Create adjustment matrix
106
+ adjustment_matrix = tf.stack([
107
+ total_adjustment * self.contrast_weight[2], # Positive adjustment
108
+ tf.zeros_like(total_adjustment), # Neutral adjustment
109
+ -total_adjustment * self.negation_weight[1] # Negative adjustment
110
+ ], axis=1)
111
+
112
+ # Apply adjustments
113
+ adjusted = predictions + adjustment_matrix
114
+
115
+ # Ensure valid probabilities
116
+ adjusted = tf.clip_by_value(adjusted, 1e-7, 1 - 1e-7)
117
+ adjusted = adjusted / tf.reduce_sum(adjusted, axis=1, keepdims=True)
118
+
119
+ return adjusted
120
+
121
+ def compute_output_shape(self, input_shape):
122
+ return input_shape[0]
123
 
124
  @tf.keras.utils.register_keras_serializable(package="CustomLayers")
125
  class SimpleAttention(tf.keras.layers.Layer):
126
+ def __init__(self, **kwargs):
127
+ super(SimpleAttention, self).__init__(**kwargs)
128
+
129
+ def build(self, input_shape):
130
+ self.W = self.add_weight(
131
+ name="attention_weight",
132
+ shape=(input_shape[-1], 1),
133
+ initializer="glorot_uniform",
134
+ trainable=True
135
+ )
136
+ super(SimpleAttention, self).build(input_shape)
137
+
138
+ def call(self, inputs):
139
+ e = tf.keras.backend.tanh(tf.keras.backend.dot(inputs, self.W))
140
+ e = tf.keras.backend.squeeze(e, axis=-1)
141
+ alpha = tf.keras.backend.softmax(e, axis=1)
142
+ alpha = tf.keras.backend.expand_dims(alpha, axis=-1)
143
+ context = inputs * alpha
144
+ return tf.keras.backend.sum(context, axis=1)
145
+
146
+ def compute_output_shape(self, input_shape):
147
+ return (input_shape[0], input_shape[2])
148
 
149
  # --- Text Preprocessing ---
150
  def preprocess_for_lstm(text, remove_stopwords=False):
151
+ if not isinstance(text, str) or not text.strip():
152
+ return ""
153
+
154
+ try:
155
+ # Handle neutral/negation phrases
156
+ neutral_phrases = [
157
+ 'not bad', 'not great', 'okay', 'so-so', 'meh', 'average',
158
+ 'mediocre', 'acceptable', 'tolerable', 'passable', 'decent',
159
+ 'nothing special', 'middle of the road', 'run of the mill'
160
+ ]
161
+ for phrase in neutral_phrases:
162
+ text = re.sub(r'\b' + re.escape(phrase) + r'\b', ' neutral_term ', text, flags=re.IGNORECASE)
163
+
164
+ # Enhanced negation handling
165
+ negation_patterns = [
166
+ r'\b(not|no|never|without|nobody|none|nothing|nowhere|neither|nor)\b [\w]+',
167
+ r'\b(less than|barely|hardly|scarcely|rarely|seldom)\b [\w]+',
168
+ r'\b(avoid|skip|doubt|problem|issue|complaint|warning|caution|refuse)\b',
169
+ r'\b(despite|in spite of|regardless|although|even though)\b'
170
+ ]
171
+ for pattern in negation_patterns:
172
+ text = re.sub(pattern, ' negation_term ', text, flags=re.IGNORECASE)
173
+
174
+ # Emoji handling
175
+ text = emoji.demojize(text, delimiters=("", ""))
176
+
177
+ # Contractions
178
+ text = contractions.fix(text)
179
+
180
+ # URL/mention replacement
181
+ text = re.sub(r'https?://\S+|www\.\S+', ' URL ', text)
182
+ text = re.sub(r'@\S+', ' USER ', text)
183
+ text = re.sub(r'\s+', ' ', text).strip().lower()
184
+
185
+ # Emoticon preservation
186
+ emoticons = re.findall(r'(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)
187
+ text = re.sub(r'[^\w\s!?.,]', ' ', text)
188
+
189
+ # Tokenization with advanced handling
190
+ tokens = word_tokenize(text)
191
+ processed_tokens = []
192
+
193
+ # Contextual sentiment indicators
194
+ contextual_indicators = {
195
+ 'but': 'contrast_indicator',
196
+ 'however': 'contrast_indicator',
197
+ 'although': 'contrast_indicator',
198
+ 'except': 'contrast_indicator',
199
+ 'unless': 'contrast_indicator',
200
+ 'yet': 'contrast_indicator',
201
+ 'still': 'contrast_indicator',
202
+ 'nonetheless': 'contrast_indicator',
203
+ 'very': 'intensifier',
204
+ 'extremely': 'intensifier',
205
+ 'absolutely': 'intensifier',
206
+ 'completely': 'intensifier',
207
+ 'utterly': 'intensifier',
208
+ 'slightly': 'diminisher',
209
+ 'somewhat': 'diminisher',
210
+ 'barely': 'diminisher',
211
+ 'marginally': 'diminisher',
212
+ 'almost': 'diminisher',
213
+ 'only': 'diminisher',
214
+ 'wow': 'positive_exclamation',
215
+ 'awesome': 'positive_exclamation',
216
+ 'ugh': 'negative_exclamation',
217
+ 'yuck': 'negative_exclamation'
218
+ }
219
+
220
+ for token in tokens:
221
+ if not token.strip():
222
+ continue
223
+
224
+ # Handle contextual indicators
225
+ if token in contextual_indicators:
226
+ processed_tokens.append(contextual_indicators[token])
227
+ continue
228
+
229
+ processed_tokens.append(token)
230
+
231
+ processed_tokens.extend(emoticons)
232
+ return ' '.join(processed_tokens)
233
+
234
+ except Exception:
235
+ return text.lower()
236
+
237
 
238
  # --- Load model resources ---
239
  @st.cache_resource