jl commited on
Commit
420b25e
·
1 Parent(s): ee133e5

model integration and ui imporvments

Browse files
.gitignore CHANGED
@@ -8,3 +8,4 @@ wheels/
8
 
9
  # Virtual environments
10
  .venv
 
 
8
 
9
  # Virtual environments
10
  .venv
11
+ .env
.vscode/settings.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "workbench.colorCustomizations": {
3
+ "activityBar.activeBackground": "#2a4a6e",
4
+ "activityBar.background": "#2a4a6e",
5
+ "activityBar.foreground": "#e7e7e7",
6
+ "activityBar.inactiveForeground": "#e7e7e799",
7
+ "activityBarBadge.background": "#170910",
8
+ "activityBarBadge.foreground": "#e7e7e7",
9
+ "commandCenter.border": "#e7e7e799",
10
+ "sash.hoverBorder": "#2a4a6e",
11
+ "statusBar.background": "#1c3149",
12
+ "statusBar.foreground": "#e7e7e7",
13
+ "statusBarItem.hoverBackground": "#2a4a6e",
14
+ "statusBarItem.remoteBackground": "#1c3149",
15
+ "statusBarItem.remoteForeground": "#e7e7e7",
16
+ "titleBar.activeBackground": "#1c3149",
17
+ "titleBar.activeForeground": "#e7e7e7",
18
+ "titleBar.inactiveBackground": "#1c314999",
19
+ "titleBar.inactiveForeground": "#e7e7e799"
20
+ },
21
+ "peacock.color": "#1c3149"
22
+ }
Altered_SHIELD_Model.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
README.md CHANGED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🛡️ Hate Speech Detection Streamlit App
2
+
3
+ A professional web application for detecting hate speech using advanced NLP with explainable AI.
4
+
5
+ ## Features
6
+
7
+ - **Real-time Hate Speech Detection**: Classify text as hate speech or not
8
+ - **Explainable AI**: See which words influenced the prediction
9
+ - **Token Importance Visualization**: Color-coded highlighting of important tokens
10
+ - **Probability Distribution**: Visual representation of model confidence
11
+ - **Professional UI**: Clean, modern interface with interactive elements
12
+
13
+ ## Installation
14
+
15
+ 1. Install the required packages:
16
+
17
+ ```bash
18
+ pip install -r requirements.txt
19
+ ```
20
+
21
+ ## Running the Application
22
+
23
+ Run the Streamlit app with:
24
+
25
+ ```bash
26
+ streamlit run app.py
27
+ ```
28
+
29
+ The application will open in your default web browser at `http://localhost:8501`
30
+
31
+ ## Usage
32
+
33
+ 1. **Enter Text**: Type or paste text into the main input area
34
+ 2. **Optional Context**: Provide additional context or rationale (optional)
35
+ 3. **Analyze**: Click the "🔍 Analyze Text" button
36
+ 4. **View Results**:
37
+ - See the classification (Hate Speech or Not Hate Speech)
38
+ - View confidence scores and probability distribution
39
+ - Explore token importance visualization
40
+ - Check which words influenced the decision
41
+
42
+ ## Model Information
43
+
44
+ - **Architecture**: HateBERT + Rationale BERT + Multi-Scale CNN + Attention
45
+ - **Model Repository**: [seffyehl/BetterShield](https://huggingface.co/seffyehl/BetterShield)
46
+ - **Training Details**:
47
+ - Batch Size: 8
48
+ - Learning Rate: 1e-5
49
+ - Weight Decay: 0.05
50
+ - Best Validation Loss: 0.27
51
+
52
+ ## Files
53
+
54
+ - `app.py` - Main Streamlit application
55
+ - `hatespeech_model.py` - Model loading and prediction functions
56
+ - `requirements.txt` - Python dependencies
57
+ - `README.md` - This file
58
+
59
+ ## Troubleshooting
60
+
61
+ ### Model Loading Issues
62
+
63
+ If the model fails to load:
64
+ - Check your internet connection (model downloads from Hugging Face)
65
+ - Ensure you have enough disk space (~500MB for model files)
66
+ - The first run will take longer as it downloads the model
67
+
68
+ ### Memory Issues
69
+
70
+ If you encounter memory errors:
71
+ - The model requires approximately 2GB of RAM
72
+ - Close other applications to free up memory
73
+ - Use CPU mode if GPU memory is limited
74
+
75
+ ## Configuration
76
+
77
+ You can modify settings in the sidebar:
78
+ - **Show Token Importance**: Toggle token highlighting
79
+ - **Show Probability Distribution**: Toggle probability chart
80
+ - **Show Technical Details**: View raw model outputs
81
+
82
+ ## Examples
83
+
84
+ Try the built-in examples:
85
+ - **Hate Speech Example**: Clear example of offensive content
86
+ - **Not Hate Speech Example**: Disagreement expressed respectfully
87
+ - **Borderline Example**: Strong criticism without hate
88
+
89
+ ## Credits
90
+
91
+ Model trained using best practices:
92
+ - Early stopping to prevent overfitting
93
+ - Batch size optimization (8 vs 16)
94
+ - Proper regularization (weight decay, dropout)
95
+ - Extensive hyperparameter tuning
96
+
97
+ ## License
98
+
99
+ MIT License
Reddit_Base_SHIELD_Model.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
app.py CHANGED
@@ -1,27 +1,294 @@
1
  import streamlit as st
2
- from hatespeech_model import predict_hatespeech
3
- import random
 
 
 
4
 
5
- st.set_page_config(page_title="Hatespeech Classifier", layout="centered")
6
- st.title("Hatespeech Text Classifier")
7
- st.write("Enter text below to classify if it is hatespeech or not.")
 
 
 
8
 
9
- user_input = st.text_area("Text to classify", "")
10
- input_split = user_input.split(" ")
 
 
 
11
 
12
- word_probabilities = {word: round(random.uniform(0, 1), 2) for word in input_split if word}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- if st.button("Classify"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  if user_input.strip():
16
- result = predict_hatespeech(user_input)
17
- st.markdown(f"**Result:** {result}")
18
- col1, col2 = st.columns(2)
19
- col1.title("Shield Model Results")
20
- col2.title("Interpretable Shield Model Results")
21
- col1.write(f"**Result:** {result} ")
22
- col1.write(f"**Probability:** {random.uniform(0, 1)} ")
23
- col2.write(f"**Result:** {result}")
24
- col2.write(f"**Probability:** {random.uniform(0, 1)} ")
25
- col2.table({"Feature": input_split, "Importance": word_probabilities.values()})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  else:
27
- st.warning("Please enter some text to classify.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ from hatespeech_model import predict_hatespeech, load_model_from_hf
3
+ import plotly.graph_objects as go
4
+ import plotly.express as px
5
+ import pandas as pd
6
+ import numpy as np
7
 
8
+ # Page configuration
9
+ st.set_page_config(
10
+ page_title="🛡️ Hate Speech Detector",
11
+ page_icon="🛡️",
12
+ layout="wide"
13
+ )
14
 
15
+ # Cached model loading function
16
+ @st.cache_resource
17
+ def load_cached_model(model_type="altered"):
18
+ """Load and cache the model"""
19
+ return load_model_from_hf(model_type=model_type)
20
 
21
+ # Custom CSS
22
+ st.markdown("""
23
+ <style>
24
+ .main-header {
25
+ font-size: 3rem;
26
+ font-weight: bold;
27
+ text-align: center;
28
+ color: #1f77b4;
29
+ margin-bottom: 1rem;
30
+ }
31
+ .sub-header {
32
+ font-size: 1.2rem;
33
+ text-align: center;
34
+ color: #555;
35
+ margin-bottom: 2rem;
36
+ }
37
+ .prediction-box {
38
+ padding: 2rem;
39
+ border-radius: 10px;
40
+ text-align: center;
41
+ font-size: 1.5rem;
42
+ font-weight: bold;
43
+ margin: 1rem 0;
44
+ }
45
+ .hate-speech {
46
+ background-color: #ffebee;
47
+ color: #c62828;
48
+ border: 2px solid #ef5350;
49
+ }
50
+ .not-hate-speech {
51
+ background-color: #e8f5e9;
52
+ color: #2e7d32;
53
+ border: 2px solid #66bb6a;
54
+ }
55
+ </style>
56
+ """, unsafe_allow_html=True)
57
 
58
+ # Header
59
+ st.markdown('<div class="main-header">🛡️ Hate Speech Detection System</div>', unsafe_allow_html=True)
60
+ st.markdown('<div class="sub-header">Advanced NLP model with explainable AI for detecting hate speech</div>', unsafe_allow_html=True)
61
+
62
+ # Model selection
63
+ col_a, col_b, col_c = st.columns([1, 2, 1])
64
+ with col_b:
65
+ model_type = st.radio(
66
+ "Select Model:",
67
+ ["Altered Shield (Advanced)", "Base Shield (Simple)"],
68
+ horizontal=True,
69
+ help="Altered Shield uses the full architecture with CNNs and attention. Base Shield is a simpler baseline."
70
+ )
71
+
72
+ model_choice = "altered" if "Altered" in model_type else "base"
73
+
74
+ # Load model with spinner
75
+ with st.spinner('🔄 Loading model... This may take a moment on first run.'):
76
+ try:
77
+ model, tokenizer_hatebert, tokenizer_rationale, config, device = load_cached_model(model_choice)
78
+ st.success(f'✅ {model_type} loaded successfully!')
79
+ except Exception as e:
80
+ st.error(f"❌ Error loading model: {str(e)}")
81
+ st.stop()
82
+
83
+ # Sidebar
84
+ with st.sidebar:
85
+ st.header("⚙️ Settings")
86
+ st.markdown(f"**Device:** {device.upper()}")
87
+ st.markdown(f"**Max Length:** {config.get('max_length', 128)}")
88
+ st.markdown(f"**CNN Filters:** {config.get('cnn_num_filters', 128)}")
89
+
90
+ st.divider()
91
+
92
+ show_rationale_viz = st.checkbox("Show Token Importance", value=True)
93
+ show_probabilities = st.checkbox("Show Probability Distribution", value=True)
94
+ show_details = st.checkbox("Show Technical Details", value=False)
95
+
96
+ st.divider()
97
+ st.subheader("💡 About")
98
+ st.markdown("""
99
+ This model uses:
100
+ - **HateBERT** for hate speech understanding
101
+ - **Multi-Scale CNN** for feature extraction
102
+ - **Attention mechanisms** for interpretability
103
+ """)
104
+
105
+ # Main interface
106
+ col1, col2 = st.columns([2, 1])
107
+
108
+ with col1:
109
+ st.subheader("📝 Input Text")
110
+ user_input = st.text_area(
111
+ "Enter text to analyze:",
112
+ placeholder="Type or paste text here to check for hate speech...",
113
+ height=150,
114
+ help="Enter any text and the model will classify it as hate speech or not"
115
+ )
116
+
117
+ optional_rationale = st.text_area(
118
+ "Optional: Provide context or rationale (leave empty to use main text):",
119
+ placeholder="Why might this be hate speech? (optional)",
120
+ height=80
121
+ )
122
+
123
+ with col2:
124
+ st.subheader("📊 Quick Stats")
125
+ if user_input:
126
+ word_count = len(user_input.split())
127
+ char_count = len(user_input)
128
+ st.metric("Words", word_count)
129
+ st.metric("Characters", char_count)
130
+ else:
131
+ st.info("Enter text to see statistics")
132
+
133
+ # Classification button
134
+ classify_button = st.button("🔍 Analyze Text", type="primary", use_container_width=True)
135
+
136
+ if classify_button:
137
  if user_input.strip():
138
+ with st.spinner('🔄 Analyzing text...'):
139
+ # Get prediction
140
+ result = predict_hatespeech(
141
+ text=user_input,
142
+ rationale=optional_rationale if optional_rationale else None,
143
+ model=model,
144
+ tokenizer_hatebert=tokenizer_hatebert,
145
+ tokenizer_rationale=tokenizer_rationale,
146
+ config=config,
147
+ device=device
148
+ )
149
+
150
+ # Extract results
151
+ prediction = result['prediction']
152
+ confidence = result['confidence']
153
+ probabilities = result['probabilities']
154
+ rationale_scores = result['rationale_scores']
155
+ tokens = result['tokens']
156
+
157
+ # Display results
158
+ st.divider()
159
+ st.header("📈 Analysis Results")
160
+
161
+ # Prediction box
162
+ if prediction == 1:
163
+ st.markdown(f'<div class="prediction-box hate-speech">🚨 HATE SPEECH DETECTED</div>',
164
+ unsafe_allow_html=True)
165
+ else:
166
+ st.markdown(f'<div class="prediction-box not-hate-speech">✅ NOT HATE SPEECH</div>',
167
+ unsafe_allow_html=True)
168
+
169
+ # Metrics
170
+ col1, col2, col3 = st.columns(3)
171
+ with col1:
172
+ st.metric("Confidence", f"{confidence:.1%}")
173
+ with col2:
174
+ st.metric("Not Hate Speech", f"{probabilities[0]:.1%}")
175
+ with col3:
176
+ st.metric("Hate Speech", f"{probabilities[1]:.1%}")
177
+
178
+ # Probability distribution chart
179
+ if show_probabilities:
180
+ st.subheader("📊 Probability Distribution")
181
+ fig = go.Figure(data=[
182
+ go.Bar(
183
+ x=['Not Hate Speech', 'Hate Speech'],
184
+ y=probabilities,
185
+ marker_color=['#66bb6a', '#ef5350'],
186
+ text=[f"{p:.1%}" for p in probabilities],
187
+ textposition='auto',
188
+ )
189
+ ])
190
+ fig.update_layout(
191
+ yaxis_title="Probability",
192
+ yaxis_range=[0, 1],
193
+ height=300,
194
+ showlegend=False
195
+ )
196
+ st.plotly_chart(fig, use_container_width=True)
197
+
198
+ # Token importance visualization
199
+ if show_rationale_viz:
200
+ st.subheader("🔍 Token Importance Analysis")
201
+ st.caption("Highlighted words show which parts of the text influenced the prediction")
202
+
203
+ # Filter out special tokens and create visualization
204
+ token_importance = []
205
+ html_output = "<div style='font-size: 18px; line-height: 2.5; padding: 20px; background-color: #f8f9fa; border-radius: 10px;'>"
206
+
207
+ for token, score in zip(tokens, rationale_scores):
208
+ if token not in ['[CLS]', '[SEP]', '[PAD]']:
209
+ # Clean token
210
+ display_token = token.replace('##', '')
211
+ token_importance.append({'Token': display_token, 'Importance': score})
212
+
213
+ # Color intensity based on score
214
+ alpha = min(score * 1.5, 1.0) # Scale up visibility
215
+ if prediction == 1: # Hate speech
216
+ color = f"rgba(239, 83, 80, {alpha:.2f})"
217
+ else: # Not hate speech
218
+ color = f"rgba(102, 187, 106, {alpha:.2f})"
219
+
220
+ html_output += f"<span style='background-color: {color}; padding: 4px 8px; margin: 2px; border-radius: 5px; display: inline-block;'>{display_token}</span> "
221
+
222
+ html_output += "</div>"
223
+ st.markdown(html_output, unsafe_allow_html=True)
224
+
225
+ if prediction == 1:
226
+ st.caption("🔴 Darker red = Higher importance for hate speech detection")
227
+ else:
228
+ st.caption("🟢 Darker green = Higher importance for non-hate speech classification")
229
+
230
+ # Top important tokens
231
+ st.subheader("📋 Top Important Tokens")
232
+ df_importance = pd.DataFrame(token_importance)
233
+ df_importance = df_importance.sort_values('Importance', ascending=False).head(10)
234
+ df_importance['Importance'] = df_importance['Importance'].apply(lambda x: f"{x:.4f}")
235
+
236
+ st.dataframe(
237
+ df_importance,
238
+ use_container_width=True,
239
+ hide_index=True
240
+ )
241
+
242
+ # Technical details
243
+ if show_details:
244
+ st.subheader("🔧 Technical Details")
245
+ with st.expander("View Model Outputs"):
246
+ st.json({
247
+ 'prediction': int(prediction),
248
+ 'confidence': float(confidence),
249
+ 'probability_not_hate': float(probabilities[0]),
250
+ 'probability_hate': float(probabilities[1]),
251
+ 'num_tokens': len([t for t in tokens if t not in ['[CLS]', '[SEP]', '[PAD]']]),
252
+ 'device': device,
253
+ 'model_config': {
254
+ 'max_length': config.get('max_length'),
255
+ 'cnn_filters': config.get('cnn_num_filters'),
256
+ }
257
+ })
258
  else:
259
+ st.warning("⚠️ Please enter some text to analyze.")
260
+
261
+ # Examples section
262
+ st.divider()
263
+ st.subheader("💡 Try Example Texts")
264
+
265
+ col1, col2, col3 = st.columns(3)
266
+
267
+ with col1:
268
+ if st.button("Example: Hate Speech", use_container_width=True):
269
+ st.session_state.example_text = "You people are worthless and should leave this country!"
270
+ st.rerun()
271
+
272
+ with col2:
273
+ if st.button("Example: Not Hate Speech", use_container_width=True):
274
+ st.session_state.example_text = "I disagree with your opinion, but I respect your right to express it."
275
+ st.rerun()
276
+
277
+ with col3:
278
+ if st.button("Example: Borderline", use_container_width=True):
279
+ st.session_state.example_text = "This policy is terrible and will hurt everyone involved."
280
+ st.rerun()
281
+
282
+ if 'example_text' in st.session_state:
283
+ st.info(f"**Example loaded:** {st.session_state.example_text}")
284
+ st.caption("↑ Copy this text to the input box above and click 'Analyze Text'")
285
+
286
+ # Footer
287
+ st.divider()
288
+ st.markdown("""
289
+ <div style='text-align: center; color: gray; padding: 20px;'>
290
+ <p><b>Hate Speech Detection Model with Rationale Extraction</b></p>
291
+ <p>Powered by HateBERT + Multi-Scale CNN + Attention Mechanisms</p>
292
+ <p>Model trained with advanced regularization and early stopping for optimal performance</p>
293
+ </div>
294
+ """, unsafe_allow_html=True)
check_base_config.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """Check the base config file structure."""
3
+
4
+ from huggingface_hub import hf_hub_download
5
+ import json
6
+
7
+ repo_id = "seffyehl/BetterShield"
8
+ config_filename = "base_config.json"
9
+
10
+ print(f"Downloading {config_filename}...")
11
+ config_path = hf_hub_download(repo_id=repo_id, filename=config_filename)
12
+
13
+ print(f"\nReading config from: {config_path}")
14
+ with open(config_path, 'r') as f:
15
+ config = json.load(f)
16
+
17
+ print("\n" + "="*60)
18
+ print("BASE CONFIG CONTENTS:")
19
+ print("="*60)
20
+ print(json.dumps(config, indent=2))
21
+ print("="*60)
check_config.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Check the actual model configuration"""
2
+ from huggingface_hub import hf_hub_download
3
+ import json
4
+
5
+ repo_id = "seffyehl/BetterShield"
6
+
7
+ # Download and read config
8
+ config_path = hf_hub_download(repo_id=repo_id, filename="alter_config.json")
9
+
10
+ with open(config_path, 'r') as f:
11
+ config = json.load(f)
12
+
13
+ print("Model Configuration:")
14
+ print("="*60)
15
+ print(json.dumps(config, indent=2))
check_hf_files.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Check what files are available in the HuggingFace repository"""
2
+ from huggingface_hub import list_repo_files
3
+
4
+ repo_id = "seffyehl/BetterShield"
5
+
6
+ print(f"Checking files in repository: {repo_id}")
7
+ print("="*60)
8
+
9
+ try:
10
+ files = list_repo_files(repo_id)
11
+ print("Available files:")
12
+ for file in files:
13
+ print(f" - {file}")
14
+ except Exception as e:
15
+ print(f"Error: {e}")
hatespeech_model.py CHANGED
@@ -1,52 +1,386 @@
1
- import re
2
- import nltk
3
- from sklearn.feature_extraction.text import CountVectorizer
4
- from sklearn.naive_bayes import MultinomialNB
5
- import pandas as pd
6
- import os
7
-
8
- # Download NLTK data if not already present
9
- nltk.download('stopwords', quiet=True)
10
- from nltk.corpus import stopwords
11
-
12
- # Example training data (for demonstration)
13
- data = {
14
- 'text': [
15
- 'I hate you',
16
- 'You are so stupid',
17
- 'Have a nice day',
18
- 'I love this',
19
- 'You are an idiot',
20
- 'What a wonderful world',
21
- 'You are disgusting',
22
- 'Such a pleasant surprise',
23
- 'I despise your actions',
24
- 'You are amazing',
25
- ],
26
- 'label': [1, 1, 0, 0, 1, 0, 1, 0, 1, 0] # 1 = hatespeech, 0 = not
27
- }
28
- df = pd.DataFrame(data)
29
-
30
- # Preprocessing function
31
- def preprocess(text):
32
- text = text.lower()
33
- text = re.sub(r'[^a-zA-Z\s]', '', text)
34
- tokens = text.split()
35
- tokens = [t for t in tokens if t not in stopwords.words('english')]
36
- return ' '.join(tokens)
37
-
38
- df['text_clean'] = df['text'].apply(preprocess)
39
-
40
- # Vectorizer and model
41
- vectorizer = CountVectorizer()
42
- X = vectorizer.fit_transform(df['text_clean'])
43
- y = df['label']
44
-
45
- model = MultinomialNB()
46
- model.fit(X, y)
47
-
48
- def predict_hatespeech(text):
49
- text_clean = preprocess(text)
50
- X_test = vectorizer.transform([text_clean])
51
- pred = model.predict(X_test)[0]
52
- return 'Hatespeech' if pred == 1 else 'Not Hatespeech'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download
2
+ import torch
3
+ import torch.nn as nn
4
+ import json
5
+ from transformers import AutoModel, AutoTokenizer
6
+
7
+ # Model Architecture Classes
8
+ class TemporalCNN(nn.Module):
9
+ def __init__(self, input_dim=768, num_filters=128, kernel_sizes=(2,3,4,5,6,7), dropout=0.3):
10
+ super().__init__()
11
+ self.convs = nn.ModuleList([
12
+ nn.Conv1d(input_dim, num_filters, k) for k in kernel_sizes
13
+ ])
14
+ self.dropout = nn.Dropout(dropout)
15
+ # Output size is num_filters * num_kernels * 2 (max + mean pooling)
16
+ self.output_size = num_filters * len(kernel_sizes) * 2
17
+
18
+ def forward(self, x, mask=None):
19
+ x = x.transpose(1, 2) # (B, H, L)
20
+ conv_outs = []
21
+ for conv in self.convs:
22
+ c = torch.relu(conv(x)) # (B, num_filters, L')
23
+ # Both max and mean pooling
24
+ max_pool = torch.max(c, dim=2)[0] # (B, num_filters)
25
+ mean_pool = torch.mean(c, dim=2) # (B, num_filters)
26
+ conv_outs.append(max_pool)
27
+ conv_outs.append(mean_pool)
28
+ out = torch.cat(conv_outs, dim=1) # (B, num_filters * len(kernel_sizes) * 2)
29
+ out = self.dropout(out)
30
+ return out
31
+
32
+ class MultiScaleAttentionCNN(nn.Module):
33
+ def __init__(self, hidden_size=768, num_filters=128, kernel_sizes=(2,3,4,5,6,7), dropout=0.3):
34
+ super().__init__()
35
+ # Convolution layers
36
+ self.convs = nn.ModuleList([
37
+ nn.Conv1d(hidden_size, num_filters, k) for k in kernel_sizes
38
+ ])
39
+ # Attention layers - output 1 value per filter for attention weighting
40
+ self.attn = nn.ModuleList([
41
+ nn.Linear(num_filters, 1) for _ in kernel_sizes
42
+ ])
43
+ self.dropout = nn.Dropout(dropout)
44
+ self.output_size = num_filters * len(kernel_sizes)
45
+
46
+ def forward(self, x, mask=None):
47
+ x = x.transpose(1, 2) # (B, H, L)
48
+ conv_outs = []
49
+ for conv, attn in zip(self.convs, self.attn):
50
+ c = torch.relu(conv(x)) # (B, num_filters, L')
51
+ c_t = c.transpose(1, 2) # (B, L', num_filters)
52
+ # Apply attention to get weights
53
+ w = attn(c_t) # (B, L', 1)
54
+ w = torch.softmax(w, dim=1) # attention weights
55
+ # Weighted sum pooling
56
+ pooled = (c_t * w).sum(dim=1) # (B, num_filters)
57
+ conv_outs.append(pooled)
58
+ out = torch.cat(conv_outs, dim=1) # (B, num_filters * len(kernel_sizes))
59
+ out = self.dropout(out)
60
+ return out
61
+
62
+ class ProjectionMLP(nn.Module):
63
+ def __init__(self, input_size, hidden_size, num_labels, dropout=0.3):
64
+ super().__init__()
65
+ self.layers = nn.Sequential(
66
+ nn.Linear(input_size, hidden_size),
67
+ nn.ReLU(),
68
+ nn.Linear(hidden_size, num_labels)
69
+ )
70
+
71
+ def forward(self, x):
72
+ return self.layers(x)
73
+
74
+ class BaseShield(nn.Module):
75
+ """
76
+ Simple base model that concatenates HateBERT and rationale BERT CLS embeddings
77
+ """
78
+ def __init__(self, hatebert_model, additional_model, projection_mlp, hidden_size=768,
79
+ freeze_additional_model=True):
80
+ super().__init__()
81
+ self.hatebert_model = hatebert_model
82
+ self.additional_model = additional_model
83
+ self.projection_mlp = projection_mlp
84
+ self.hidden_size = hidden_size
85
+
86
+ if freeze_additional_model:
87
+ for param in self.additional_model.parameters():
88
+ param.requires_grad = False
89
+
90
+ def forward(self, input_ids, attention_mask, additional_input_ids, additional_attention_mask,
91
+ return_attentions=False):
92
+ # Main text through HateBERT - get CLS token only
93
+ hatebert_out = self.hatebert_model(input_ids=input_ids, attention_mask=attention_mask,
94
+ output_attentions=return_attentions, return_dict=True)
95
+ hatebert_cls = hatebert_out.last_hidden_state[:, 0, :] # (B, 768)
96
+
97
+ # Rationale text through frozen BERT - get CLS token only
98
+ with torch.no_grad():
99
+ add_out = self.additional_model(input_ids=additional_input_ids,
100
+ attention_mask=additional_attention_mask,
101
+ return_dict=True)
102
+ rationale_cls = add_out.last_hidden_state[:, 0, :] # (B, 768)
103
+
104
+ # Concatenate CLS embeddings: (B, 1536)
105
+ concat_emb = torch.cat((hatebert_cls, rationale_cls), dim=1)
106
+
107
+ # Classification
108
+ logits = self.projection_mlp(concat_emb)
109
+
110
+ # Return dummy rationale_probs and selector_logits for compatibility with app
111
+ batch_size = input_ids.size(0)
112
+ seq_len = input_ids.size(1)
113
+ dummy_rationale_probs = torch.zeros(batch_size, seq_len, device=input_ids.device)
114
+ dummy_selector_logits = torch.zeros(batch_size, seq_len, device=input_ids.device)
115
+
116
+ attns = hatebert_out.attentions if (return_attentions and hasattr(hatebert_out, "attentions")) else None
117
+ return logits, dummy_rationale_probs, dummy_selector_logits, attns
118
+
119
+
120
+ class ConcatModelWithRationale(nn.Module):
121
+ def __init__(self, hatebert_model, additional_model, projection_mlp, hidden_size=768,
122
+ gumbel_temp=0.5, freeze_additional_model=True, cnn_num_filters=128,
123
+ cnn_kernel_sizes=(2,3,4), cnn_dropout=0.3):
124
+ super().__init__()
125
+ self.hatebert_model = hatebert_model
126
+ self.additional_model = additional_model
127
+ self.projection_mlp = projection_mlp
128
+ self.gumbel_temp = gumbel_temp
129
+ self.hidden_size = hidden_size
130
+
131
+ if freeze_additional_model:
132
+ for param in self.additional_model.parameters():
133
+ param.requires_grad = False
134
+
135
+ self.selector = nn.Linear(hidden_size, 1)
136
+ self.temporal_cnn = TemporalCNN(input_dim=hidden_size, num_filters=cnn_num_filters,
137
+ kernel_sizes=cnn_kernel_sizes, dropout=cnn_dropout)
138
+ self.temporal_out_dim = cnn_num_filters * len(cnn_kernel_sizes) * 2
139
+ self.msa_cnn = MultiScaleAttentionCNN(hidden_size=hidden_size, num_filters=cnn_num_filters,
140
+ kernel_sizes=cnn_kernel_sizes, dropout=cnn_dropout)
141
+ self.msa_out_dim = self.msa_cnn.output_size
142
+
143
+ def gumbel_sigmoid_sample(self, logits):
144
+ noise = -torch.log(-torch.log(torch.rand_like(logits) + 1e-9) + 1e-9)
145
+ y = logits + noise
146
+ return torch.sigmoid(y / self.gumbel_temp)
147
+
148
+ def forward(self, input_ids, attention_mask, additional_input_ids, additional_attention_mask,
149
+ return_attentions=False):
150
+ hatebert_out = self.hatebert_model(input_ids=input_ids, attention_mask=attention_mask,
151
+ output_attentions=return_attentions, return_dict=True)
152
+ hatebert_emb = hatebert_out.last_hidden_state
153
+ cls_emb = hatebert_emb[:, 0, :]
154
+
155
+ with torch.no_grad():
156
+ add_out = self.additional_model(input_ids=additional_input_ids,
157
+ attention_mask=additional_attention_mask,
158
+ return_dict=True)
159
+ rationale_emb = add_out.last_hidden_state
160
+
161
+ selector_logits = self.selector(hatebert_emb).squeeze(-1)
162
+ rationale_probs = self.gumbel_sigmoid_sample(selector_logits)
163
+ rationale_probs = rationale_probs * attention_mask.float().to(rationale_probs.device)
164
+
165
+ masked_hidden = hatebert_emb * rationale_probs.unsqueeze(-1)
166
+ denom = rationale_probs.sum(1).unsqueeze(-1).clamp_min(1e-6)
167
+ pooled_rationale = masked_hidden.sum(1) / denom
168
+
169
+ temporal_features = self.temporal_cnn(hatebert_emb, attention_mask)
170
+ rationale_features = self.msa_cnn(rationale_emb, additional_attention_mask)
171
+
172
+ concat_emb = torch.cat((cls_emb, temporal_features, rationale_features, pooled_rationale), dim=1)
173
+ logits = self.projection_mlp(concat_emb)
174
+
175
+ attns = hatebert_out.attentions if (return_attentions and hasattr(hatebert_out, "attentions")) else None
176
+ return logits, rationale_probs, selector_logits, attns
177
+
178
+ def load_model_from_hf(model_type="altered"):
179
+ """
180
+ Load model from Hugging Face Hub
181
+
182
+ Args:
183
+ model_type: Either "altered" or "base" to choose which model to load
184
+ """
185
+
186
+ repo_id = "seffyehl/BetterShield"
187
+
188
+ # Choose model and config files based on model_type
189
+ if model_type.lower() == "altered":
190
+ model_filename = "AlteredShield.pth"
191
+ config_filename = "alter_config.json"
192
+ elif model_type.lower() == "base":
193
+ model_filename = "BaseShield.pth"
194
+ config_filename = "base_config.json"
195
+ else:
196
+ raise ValueError(f"model_type must be 'altered' or 'base', got '{model_type}'")
197
+
198
+ # Download files
199
+ model_path = hf_hub_download(
200
+ repo_id=repo_id,
201
+ filename=model_filename
202
+ )
203
+
204
+ config_path = hf_hub_download(
205
+ repo_id=repo_id,
206
+ filename=config_filename
207
+ )
208
+
209
+ # Load config
210
+ with open(config_path, 'r') as f:
211
+ config = json.load(f)
212
+
213
+ # Load checkpoint
214
+ checkpoint = torch.load(model_path, map_location='cpu')
215
+
216
+ # Handle nested config structure (base model uses model_config, altered uses flat structure)
217
+ if 'model_config' in config:
218
+ model_config = config['model_config']
219
+ training_config = config.get('training_config', {})
220
+ else:
221
+ model_config = config
222
+ training_config = config
223
+
224
+ # Initialize base models
225
+ hatebert_model = AutoModel.from_pretrained(model_config['hatebert_model'])
226
+ rationale_model = AutoModel.from_pretrained(model_config['rationale_model'])
227
+
228
+ tokenizer_hatebert = AutoTokenizer.from_pretrained(model_config['hatebert_model'])
229
+ tokenizer_rationale = AutoTokenizer.from_pretrained(model_config['rationale_model'])
230
+
231
+ # Rebuild architecture based on model type
232
+ H = hatebert_model.config.hidden_size
233
+ max_length = training_config.get('max_length', 128)
234
+
235
+ if model_type.lower() == "base":
236
+ # Base Shield: Simple concatenation model
237
+ # Input: 768 (HateBERT CLS) + 768 (Rationale BERT CLS) = 1536
238
+ proj_input_dim = H * 2 # 1536
239
+ # The saved model uses 512, not what's in projection_config
240
+ adapter_dim = 512 # hardcoded to match saved weights
241
+ projection_mlp = ProjectionMLP(input_size=proj_input_dim, hidden_size=adapter_dim,
242
+ num_labels=2, dropout=0.0)
243
+
244
+ model = BaseShield(
245
+ hatebert_model=hatebert_model,
246
+ additional_model=rationale_model,
247
+ projection_mlp=projection_mlp,
248
+ hidden_size=H,
249
+ freeze_additional_model=True
250
+ )
251
+ else:
252
+ # Altered Shield: Complex model with CNN and attention
253
+ cnn_num_filters = model_config.get('cnn_num_filters', 128)
254
+ # Use extended kernel sizes to match saved model
255
+ cnn_kernel_sizes = (2, 3, 4, 5, 6, 7)
256
+ adapter_dim = model_config.get('adapter_dim', 128)
257
+ cnn_dropout = model_config.get('cnn_dropout', 0.3)
258
+
259
+ # Calculate dimensions
260
+ # TemporalCNN: num_filters * len(kernel_sizes) * 2 (max + mean pooling)
261
+ temporal_out_dim = cnn_num_filters * len(cnn_kernel_sizes) * 2
262
+ # MultiScaleAttentionCNN: num_filters * len(kernel_sizes)
263
+ msa_out_dim = cnn_num_filters * len(cnn_kernel_sizes)
264
+ # Total: CLS (768) + TemporalCNN + MSA + pooled_rationale (768)
265
+ proj_input_dim = H + temporal_out_dim + msa_out_dim + H
266
+ projection_mlp = ProjectionMLP(input_size=proj_input_dim, hidden_size=adapter_dim,
267
+ num_labels=2, dropout=0.0)
268
+
269
+ model = ConcatModelWithRationale(
270
+ hatebert_model=hatebert_model,
271
+ additional_model=rationale_model,
272
+ projection_mlp=projection_mlp,
273
+ hidden_size=H,
274
+ freeze_additional_model=True,
275
+ cnn_num_filters=cnn_num_filters,
276
+ cnn_kernel_sizes=cnn_kernel_sizes,
277
+ cnn_dropout=cnn_dropout
278
+ )
279
+
280
+ model.load_state_dict(checkpoint['model_state_dict'])
281
+ model.eval()
282
+
283
+ device = 'cuda' if torch.cuda.is_available() else 'cpu'
284
+ model = model.to(device)
285
+
286
+ # Create a unified config dict with max_length at top level for compatibility
287
+ unified_config = config.copy()
288
+ if 'max_length' not in unified_config and 'training_config' in config:
289
+ unified_config['max_length'] = training_config.get('max_length', 128)
290
+
291
+ return model, tokenizer_hatebert, tokenizer_rationale, unified_config, device
292
+
293
+ def predict_text(text, rationale, model, tokenizer_hatebert, tokenizer_rationale,
294
+ device='cpu', max_length=128):
295
+ """
296
+ Predict hate speech for a given text and rationale
297
+
298
+ Args:
299
+ text: Input text to classify
300
+ rationale: Rationale/explanation text
301
+ model: Loaded model
302
+ tokenizer_hatebert: HateBERT tokenizer
303
+ tokenizer_rationale: Rationale model tokenizer
304
+ device: 'cpu' or 'cuda'
305
+ max_length: Maximum sequence length
306
+
307
+ Returns:
308
+ prediction: 0 or 1
309
+ probability: Confidence score
310
+ rationale_scores: Token-level rationale scores
311
+ """
312
+ model.eval()
313
+
314
+ # Tokenize inputs
315
+ inputs_main = tokenizer_hatebert(
316
+ text,
317
+ max_length=max_length,
318
+ padding='max_length',
319
+ truncation=True,
320
+ return_tensors='pt'
321
+ )
322
+
323
+ inputs_rationale = tokenizer_rationale(
324
+ rationale if rationale else text, # Use text if no rationale provided
325
+ max_length=max_length,
326
+ padding='max_length',
327
+ truncation=True,
328
+ return_tensors='pt'
329
+ )
330
+
331
+ # Move to device
332
+ input_ids = inputs_main['input_ids'].to(device)
333
+ attention_mask = inputs_main['attention_mask'].to(device)
334
+ add_input_ids = inputs_rationale['input_ids'].to(device)
335
+ add_attention_mask = inputs_rationale['attention_mask'].to(device)
336
+
337
+ # Inference
338
+ with torch.no_grad():
339
+ logits, rationale_probs, selector_logits, _ = model(
340
+ input_ids,
341
+ attention_mask,
342
+ add_input_ids,
343
+ add_attention_mask
344
+ )
345
+
346
+ # Get probabilities
347
+ probs = torch.softmax(logits, dim=1)
348
+ prediction = logits.argmax(dim=1).item()
349
+ confidence = probs[0, prediction].item()
350
+
351
+ return {
352
+ 'prediction': prediction,
353
+ 'confidence': confidence,
354
+ 'probabilities': probs[0].cpu().numpy(),
355
+ 'rationale_scores': rationale_probs[0].cpu().numpy(),
356
+ 'tokens': tokenizer_hatebert.convert_ids_to_tokens(input_ids[0])
357
+ }
358
+
359
+ def predict_hatespeech(text, rationale, model, tokenizer_hatebert, tokenizer_rationale, config, device):
360
+ """
361
+ Predict hate speech for given text
362
+
363
+ Args:
364
+ text: Input text to classify
365
+ rationale: Optional rationale text
366
+ model: Loaded model
367
+ tokenizer_hatebert: HateBERT tokenizer
368
+ tokenizer_rationale: Rationale tokenizer
369
+ config: Model configuration
370
+ device: Device to run on
371
+
372
+ Returns:
373
+ Dictionary with prediction results
374
+ """
375
+ # Get prediction
376
+ result = predict_text(
377
+ text=text,
378
+ rationale=rationale,
379
+ model=model,
380
+ tokenizer_hatebert=tokenizer_hatebert,
381
+ tokenizer_rationale=tokenizer_rationale,
382
+ device=device,
383
+ max_length=config.get('max_length', 128)
384
+ )
385
+
386
+ return result
pyproject.toml CHANGED
@@ -5,8 +5,20 @@ description = "Add your description here"
5
  readme = "README.md"
6
  requires-python = ">=3.13"
7
  dependencies = [
 
 
8
  "nltk>=3.9.2",
 
 
9
  "pandas>=2.3.3",
 
 
 
 
10
  "scikit-learn>=1.8.0",
11
  "streamlit>=1.52.1",
 
 
 
 
12
  ]
 
5
  readme = "README.md"
6
  requires-python = ">=3.13"
7
  dependencies = [
8
+ "filelock>=3.12.0",
9
+ "huggingface-hub>=0.34.0,<1.0",
10
  "nltk>=3.9.2",
11
+ "numpy>=1.24.0",
12
+ "packaging>=23.0",
13
  "pandas>=2.3.3",
14
+ "plotly>=5.14.0",
15
+ "regex>=2023.5.0",
16
+ "requests>=2.31.0",
17
+ "safetensors>=0.3.0",
18
  "scikit-learn>=1.8.0",
19
  "streamlit>=1.52.1",
20
+ "tokenizers>=0.13.0",
21
+ "torch>=2.9.1",
22
+ "tqdm>=4.65.0",
23
+ "transformers>=4.30.0",
24
  ]
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit>=1.28.0
2
+ torch>=2.0.0
3
+ transformers>=4.30.0
4
+ huggingface-hub>=0.34.0,<1.0
5
+ plotly>=5.14.0
6
+ pandas>=2.0.0
7
+ numpy>=1.24.0
8
+ tokenizers>=0.13.0
9
+ safetensors>=0.3.0
10
+ filelock>=3.12.0
11
+ requests>=2.31.0
12
+ tqdm>=4.65.0
13
+ regex>=2023.5.0
14
+ packaging>=23.0
run_app.ps1 ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Run Streamlit App Script
2
+ Write-Host "🛡️ Starting Hate Speech Detection App..." -ForegroundColor Cyan
3
+ Write-Host ""
4
+
5
+ # Check if streamlit is installed
6
+ try {
7
+ $streamlitVersion = streamlit --version 2>&1
8
+ Write-Host "✓ Streamlit found: $streamlitVersion" -ForegroundColor Green
9
+ } catch {
10
+ Write-Host "✗ Streamlit not found. Installing requirements..." -ForegroundColor Yellow
11
+ pip install -r requirements.txt
12
+ }
13
+
14
+ Write-Host ""
15
+ Write-Host "Starting application..." -ForegroundColor Cyan
16
+ Write-Host "Press Ctrl+C to stop the server" -ForegroundColor Yellow
17
+ Write-Host ""
18
+
19
+ # Run the Streamlit app
20
+ streamlit run app.py
test_base_model.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """Test script to check if Base Shield model loads."""
3
+
4
+ from hatespeech_model import load_model_from_hf
5
+ import torch
6
+
7
+ print("Testing Base Shield model load...")
8
+ print("=" * 60)
9
+
10
+ try:
11
+ print("\n1. Loading Base Shield model...")
12
+ base_model, base_tokenizer, _, config, device = load_model_from_hf("base")
13
+ print("✅ Base Shield loaded successfully!")
14
+ print(f" Model type: {type(base_model).__name__}")
15
+ print(f" Device: {device}")
16
+
17
+ # Test forward pass with dummy input
18
+ test_input = torch.randint(0, 1000, (1, 50)).to(device)
19
+ test_attn_mask = torch.ones(1, 50).to(device)
20
+
21
+ print("\n2. Testing forward pass...")
22
+ with torch.no_grad():
23
+ logits, rationale_probs, selector_logits, attns = base_model(
24
+ input_ids=test_input,
25
+ attention_mask=test_attn_mask,
26
+ additional_input_ids=test_input,
27
+ additional_attention_mask=test_attn_mask
28
+ )
29
+ print(f"✅ Forward pass successful!")
30
+ print(f" Logits shape: {logits.shape}")
31
+ print(f" Output range: [{logits.min():.4f}, {logits.max():.4f}]")
32
+
33
+ print("\n" + "=" * 60)
34
+ print("✅ All tests passed!")
35
+
36
+ except Exception as e:
37
+ print(f"\n❌ Error: {e}")
38
+ import traceback
39
+ traceback.print_exc()
40
+ print("\n" + "=" * 60)
41
+ print("❌ Tests failed")
test_imports.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test script to check imports and identify version issues"""
2
+ import sys
3
+
4
+ print("Python version:", sys.version)
5
+ print("\n" + "="*50)
6
+ print("Testing imports...")
7
+ print("="*50)
8
+
9
+ try:
10
+ import torch
11
+ print(f"✓ torch: {torch.__version__}")
12
+ except Exception as e:
13
+ print(f"✗ torch: {e}")
14
+
15
+ try:
16
+ import transformers
17
+ print(f"✓ transformers: {transformers.__version__}")
18
+ except Exception as e:
19
+ print(f"✗ transformers: {e}")
20
+
21
+ try:
22
+ import huggingface_hub
23
+ print(f"✓ huggingface_hub: {huggingface_hub.__version__}")
24
+ except Exception as e:
25
+ print(f"✗ huggingface_hub: {e}")
26
+
27
+ try:
28
+ import streamlit
29
+ print(f"✓ streamlit: {streamlit.__version__}")
30
+ except Exception as e:
31
+ print(f"✗ streamlit: {e}")
32
+
33
+ try:
34
+ import plotly
35
+ print(f"✓ plotly: {plotly.__version__}")
36
+ except Exception as e:
37
+ print(f"✗ plotly: {e}")
38
+
39
+ try:
40
+ import pandas
41
+ print(f"✓ pandas: {pandas.__version__}")
42
+ except Exception as e:
43
+ print(f"✗ pandas: {e}")
44
+
45
+ try:
46
+ import numpy
47
+ print(f"✓ numpy: {numpy.__version__}")
48
+ except Exception as e:
49
+ print(f"✗ numpy: {e}")
50
+
51
+ print("\n" + "="*50)
52
+ print("Checking transformers dependencies...")
53
+ print("="*50)
54
+
55
+ try:
56
+ from transformers import AutoModel, AutoTokenizer
57
+ print("✓ Successfully imported AutoModel and AutoTokenizer")
58
+ except Exception as e:
59
+ print(f"✗ Error importing from transformers: {e}")
60
+ import traceback
61
+ traceback.print_exc()
test_model_load.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """Test script to check if model loads without state_dict errors."""
3
+
4
+ from hatespeech_model import load_model_from_hf
5
+
6
+ print("Testing model load...")
7
+ print("=" * 60)
8
+
9
+ try:
10
+ print("\n1. Loading Altered Shield model...")
11
+ altered_model, altered_tokenizer, _, _, _ = load_model_from_hf("altered")
12
+ print("✅ Altered Shield loaded successfully!")
13
+ print(f" Model type: {type(altered_model).__name__}")
14
+
15
+ # Test forward pass with dummy input
16
+ import torch
17
+ test_input = torch.randint(0, 1000, (1, 50))
18
+ test_attn_mask = torch.ones(1, 50)
19
+
20
+ print("\n2. Testing forward pass...")
21
+ with torch.no_grad():
22
+ logits, rationale_probs, selector_logits, attns = altered_model(
23
+ input_ids=test_input,
24
+ attention_mask=test_attn_mask,
25
+ additional_input_ids=test_input,
26
+ additional_attention_mask=test_attn_mask
27
+ )
28
+ print(f"✅ Forward pass successful!")
29
+ print(f" Logits shape: {logits.shape}")
30
+ print(f" Output range: [{logits.min():.4f}, {logits.max():.4f}]")
31
+
32
+ print("\n" + "=" * 60)
33
+ print("✅ All tests passed!")
34
+
35
+ except Exception as e:
36
+ print(f"\n❌ Error: {e}")
37
+ import traceback
38
+ traceback.print_exc()
39
+ print("\n" + "=" * 60)
40
+ print("❌ Tests failed")
uv.lock CHANGED
@@ -18,6 +18,27 @@ wheels = [
18
  { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410, upload-time = "2025-11-12T08:59:09.804Z" },
19
  ]
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  [[package]]
22
  name = "attrs"
23
  version = "25.4.0"
@@ -27,6 +48,19 @@ wheels = [
27
  { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
28
  ]
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  [[package]]
31
  name = "blinker"
32
  version = "1.9.0"
@@ -116,6 +150,33 @@ wheels = [
116
  { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
117
  ]
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  [[package]]
120
  name = "gitdb"
121
  version = "4.0.12"
@@ -140,6 +201,143 @@ wheels = [
140
  { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" },
141
  ]
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  [[package]]
144
  name = "idna"
145
  version = "3.11"
@@ -249,6 +447,15 @@ wheels = [
249
  { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
250
  ]
251
 
 
 
 
 
 
 
 
 
 
252
  [[package]]
253
  name = "narwhals"
254
  version = "2.13.0"
@@ -258,6 +465,15 @@ wheels = [
258
  { url = "https://files.pythonhosted.org/packages/87/0d/1861d1599571974b15b025e12b142d8e6b42ad66c8a07a89cb0fc21f1e03/narwhals-2.13.0-py3-none-any.whl", hash = "sha256:9b795523c179ca78204e3be53726da374168f906e38de2ff174c2363baaaf481", size = 426407, upload-time = "2025-12-01T13:54:03.861Z" },
259
  ]
260
 
 
 
 
 
 
 
 
 
 
261
  [[package]]
262
  name = "nltk"
263
  version = "3.9.2"
@@ -325,6 +541,140 @@ wheels = [
325
  { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
326
  ]
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  [[package]]
329
  name = "packaging"
330
  version = "25.0"
@@ -432,23 +782,64 @@ wheels = [
432
  { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" },
433
  ]
434
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  [[package]]
436
  name = "proto"
437
  version = "0.1.0"
438
  source = { virtual = "." }
439
  dependencies = [
 
 
 
 
440
  { name = "nltk" },
 
 
441
  { name = "pandas" },
 
 
 
 
442
  { name = "scikit-learn" },
443
  { name = "streamlit" },
 
 
 
 
444
  ]
445
 
446
  [package.metadata]
447
  requires-dist = [
 
 
 
 
448
  { name = "nltk", specifier = ">=3.9.2" },
 
 
449
  { name = "pandas", specifier = ">=2.3.3" },
 
 
 
 
450
  { name = "scikit-learn", specifier = ">=1.8.0" },
451
  { name = "streamlit", specifier = ">=1.52.1" },
 
 
 
 
452
  ]
453
 
454
  [[package]]
@@ -502,6 +893,95 @@ wheels = [
502
  { url = "https://files.pythonhosted.org/packages/7b/03/f335d6c52b4a4761bcc83499789a1e2e16d9d201a58c327a9b5cc9a41bd9/pyarrow-22.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0c34fe18094686194f204a3b1787a27456897d8a2d62caf84b61e8dfbc0252ae", size = 29185594, upload-time = "2025-10-24T10:09:53.111Z" },
503
  ]
504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  [[package]]
506
  name = "pydeck"
507
  version = "0.9.1"
@@ -536,6 +1016,42 @@ wheels = [
536
  { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
537
  ]
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  [[package]]
540
  name = "referencing"
541
  version = "0.37.0"
@@ -694,6 +1210,40 @@ wheels = [
694
  { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" },
695
  ]
696
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
697
  [[package]]
698
  name = "scikit-learn"
699
  version = "1.8.0"
@@ -783,6 +1333,15 @@ wheels = [
783
  { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" },
784
  ]
785
 
 
 
 
 
 
 
 
 
 
786
  [[package]]
787
  name = "six"
788
  version = "1.17.0"
@@ -801,6 +1360,24 @@ wheels = [
801
  { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
802
  ]
803
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804
  [[package]]
805
  name = "streamlit"
806
  version = "1.52.1"
@@ -830,6 +1407,18 @@ wheels = [
830
  { url = "https://files.pythonhosted.org/packages/d0/d4/cdafd4cc940937410f465ca7a77dd34237182c2ddece624e08db959496f8/streamlit-1.52.1-py3-none-any.whl", hash = "sha256:97fee2c3421d350fd65548e45a20f506ec1b651d78f95ecacbc0c2f9f838081c", size = 9024748, upload-time = "2025-12-05T18:55:39.713Z" },
831
  ]
832
 
 
 
 
 
 
 
 
 
 
 
 
 
833
  [[package]]
834
  name = "tenacity"
835
  version = "9.1.2"
@@ -848,6 +1437,32 @@ wheels = [
848
  { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" },
849
  ]
850
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
  [[package]]
852
  name = "toml"
853
  version = "0.10.2"
@@ -857,6 +1472,54 @@ wheels = [
857
  { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
858
  ]
859
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
860
  [[package]]
861
  name = "tornado"
862
  version = "6.5.3"
@@ -888,6 +1551,38 @@ wheels = [
888
  { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
889
  ]
890
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
891
  [[package]]
892
  name = "typing-extensions"
893
  version = "4.15.0"
@@ -897,6 +1592,18 @@ wheels = [
897
  { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
898
  ]
899
 
 
 
 
 
 
 
 
 
 
 
 
 
900
  [[package]]
901
  name = "tzdata"
902
  version = "2025.3"
@@ -932,3 +1639,23 @@ wheels = [
932
  { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
933
  { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
934
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410, upload-time = "2025-11-12T08:59:09.804Z" },
19
  ]
20
 
21
+ [[package]]
22
+ name = "annotated-types"
23
+ version = "0.7.0"
24
+ source = { registry = "https://pypi.org/simple" }
25
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
26
+ wheels = [
27
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
28
+ ]
29
+
30
+ [[package]]
31
+ name = "anyio"
32
+ version = "4.12.0"
33
+ source = { registry = "https://pypi.org/simple" }
34
+ dependencies = [
35
+ { name = "idna" },
36
+ ]
37
+ sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266, upload-time = "2025-11-28T23:37:38.911Z" }
38
+ wheels = [
39
+ { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" },
40
+ ]
41
+
42
  [[package]]
43
  name = "attrs"
44
  version = "25.4.0"
 
48
  { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
49
  ]
50
 
51
+ [[package]]
52
+ name = "beautifulsoup4"
53
+ version = "4.14.3"
54
+ source = { registry = "https://pypi.org/simple" }
55
+ dependencies = [
56
+ { name = "soupsieve" },
57
+ { name = "typing-extensions" },
58
+ ]
59
+ sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" }
60
+ wheels = [
61
+ { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" },
62
+ ]
63
+
64
  [[package]]
65
  name = "blinker"
66
  version = "1.9.0"
 
150
  { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
151
  ]
152
 
153
+ [[package]]
154
+ name = "distro"
155
+ version = "1.9.0"
156
+ source = { registry = "https://pypi.org/simple" }
157
+ sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" }
158
+ wheels = [
159
+ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
160
+ ]
161
+
162
+ [[package]]
163
+ name = "filelock"
164
+ version = "3.20.3"
165
+ source = { registry = "https://pypi.org/simple" }
166
+ sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" }
167
+ wheels = [
168
+ { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" },
169
+ ]
170
+
171
+ [[package]]
172
+ name = "fsspec"
173
+ version = "2026.1.0"
174
+ source = { registry = "https://pypi.org/simple" }
175
+ sdist = { url = "https://files.pythonhosted.org/packages/d5/7d/5df2650c57d47c57232af5ef4b4fdbff182070421e405e0d62c6cdbfaa87/fsspec-2026.1.0.tar.gz", hash = "sha256:e987cb0496a0d81bba3a9d1cee62922fb395e7d4c3b575e57f547953334fe07b", size = 310496, upload-time = "2026-01-09T15:21:35.562Z" }
176
+ wheels = [
177
+ { url = "https://files.pythonhosted.org/packages/01/c9/97cc5aae1648dcb851958a3ddf73ccd7dbe5650d95203ecb4d7720b4cdbf/fsspec-2026.1.0-py3-none-any.whl", hash = "sha256:cb76aa913c2285a3b49bdd5fc55b1d7c708d7208126b60f2eb8194fe1b4cbdcc", size = 201838, upload-time = "2026-01-09T15:21:34.041Z" },
178
+ ]
179
+
180
  [[package]]
181
  name = "gitdb"
182
  version = "4.0.12"
 
201
  { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" },
202
  ]
203
 
204
+ [[package]]
205
+ name = "google"
206
+ version = "3.0.0"
207
+ source = { registry = "https://pypi.org/simple" }
208
+ dependencies = [
209
+ { name = "beautifulsoup4" },
210
+ ]
211
+ sdist = { url = "https://files.pythonhosted.org/packages/89/97/b49c69893cddea912c7a660a4b6102c6b02cd268f8c7162dd70b7c16f753/google-3.0.0.tar.gz", hash = "sha256:143530122ee5130509ad5e989f0512f7cb218b2d4eddbafbad40fd10e8d8ccbe", size = 44978, upload-time = "2020-07-11T14:50:45.678Z" }
212
+ wheels = [
213
+ { url = "https://files.pythonhosted.org/packages/ac/35/17c9141c4ae21e9a29a43acdfd848e3e468a810517f862cad07977bf8fe9/google-3.0.0-py2.py3-none-any.whl", hash = "sha256:889cf695f84e4ae2c55fbc0cfdaf4c1e729417fa52ab1db0485202ba173e4935", size = 45258, upload-time = "2020-07-11T14:49:58.287Z" },
214
+ ]
215
+
216
+ [[package]]
217
+ name = "google-auth"
218
+ version = "2.45.0"
219
+ source = { registry = "https://pypi.org/simple" }
220
+ dependencies = [
221
+ { name = "cachetools" },
222
+ { name = "pyasn1-modules" },
223
+ { name = "rsa" },
224
+ ]
225
+ sdist = { url = "https://files.pythonhosted.org/packages/e5/00/3c794502a8b892c404b2dea5b3650eb21bfc7069612fbfd15c7f17c1cb0d/google_auth-2.45.0.tar.gz", hash = "sha256:90d3f41b6b72ea72dd9811e765699ee491ab24139f34ebf1ca2b9cc0c38708f3", size = 320708, upload-time = "2025-12-15T22:58:42.889Z" }
226
+ wheels = [
227
+ { url = "https://files.pythonhosted.org/packages/c6/97/451d55e05487a5cd6279a01a7e34921858b16f7dc8aa38a2c684743cd2b3/google_auth-2.45.0-py2.py3-none-any.whl", hash = "sha256:82344e86dc00410ef5382d99be677c6043d72e502b625aa4f4afa0bdacca0f36", size = 233312, upload-time = "2025-12-15T22:58:40.777Z" },
228
+ ]
229
+
230
+ [package.optional-dependencies]
231
+ requests = [
232
+ { name = "requests" },
233
+ ]
234
+
235
+ [[package]]
236
+ name = "google-genai"
237
+ version = "1.56.0"
238
+ source = { registry = "https://pypi.org/simple" }
239
+ dependencies = [
240
+ { name = "anyio" },
241
+ { name = "distro" },
242
+ { name = "google-auth", extra = ["requests"] },
243
+ { name = "httpx" },
244
+ { name = "pydantic" },
245
+ { name = "requests" },
246
+ { name = "sniffio" },
247
+ { name = "tenacity" },
248
+ { name = "typing-extensions" },
249
+ { name = "websockets" },
250
+ ]
251
+ sdist = { url = "https://files.pythonhosted.org/packages/70/ad/d3ac5a102135bd3f1e4b1475ca65d2bd4bcc22eb2e9348ac40fe3fadb1d6/google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f", size = 340451, upload-time = "2025-12-17T12:35:05.412Z" }
252
+ wheels = [
253
+ { url = "https://files.pythonhosted.org/packages/84/93/94bc7a89ef4e7ed3666add55cd859d1483a22737251df659bf1aa46e9405/google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052", size = 426563, upload-time = "2025-12-17T12:35:03.717Z" },
254
+ ]
255
+
256
+ [[package]]
257
+ name = "h11"
258
+ version = "0.16.0"
259
+ source = { registry = "https://pypi.org/simple" }
260
+ sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
261
+ wheels = [
262
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
263
+ ]
264
+
265
+ [[package]]
266
+ name = "hf-xet"
267
+ version = "1.2.0"
268
+ source = { registry = "https://pypi.org/simple" }
269
+ sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" }
270
+ wheels = [
271
+ { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" },
272
+ { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" },
273
+ { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" },
274
+ { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" },
275
+ { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" },
276
+ { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" },
277
+ { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" },
278
+ { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" },
279
+ { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" },
280
+ { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" },
281
+ { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" },
282
+ { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" },
283
+ { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" },
284
+ { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" },
285
+ { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" },
286
+ { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" },
287
+ { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" },
288
+ { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" },
289
+ { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" },
290
+ { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" },
291
+ { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" },
292
+ ]
293
+
294
+ [[package]]
295
+ name = "httpcore"
296
+ version = "1.0.9"
297
+ source = { registry = "https://pypi.org/simple" }
298
+ dependencies = [
299
+ { name = "certifi" },
300
+ { name = "h11" },
301
+ ]
302
+ sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
303
+ wheels = [
304
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
305
+ ]
306
+
307
+ [[package]]
308
+ name = "httpx"
309
+ version = "0.28.1"
310
+ source = { registry = "https://pypi.org/simple" }
311
+ dependencies = [
312
+ { name = "anyio" },
313
+ { name = "certifi" },
314
+ { name = "httpcore" },
315
+ { name = "idna" },
316
+ ]
317
+ sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
318
+ wheels = [
319
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
320
+ ]
321
+
322
+ [[package]]
323
+ name = "huggingface-hub"
324
+ version = "0.36.0"
325
+ source = { registry = "https://pypi.org/simple" }
326
+ dependencies = [
327
+ { name = "filelock" },
328
+ { name = "fsspec" },
329
+ { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
330
+ { name = "packaging" },
331
+ { name = "pyyaml" },
332
+ { name = "requests" },
333
+ { name = "tqdm" },
334
+ { name = "typing-extensions" },
335
+ ]
336
+ sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" }
337
+ wheels = [
338
+ { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" },
339
+ ]
340
+
341
  [[package]]
342
  name = "idna"
343
  version = "3.11"
 
447
  { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
448
  ]
449
 
450
+ [[package]]
451
+ name = "mpmath"
452
+ version = "1.3.0"
453
+ source = { registry = "https://pypi.org/simple" }
454
+ sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
455
+ wheels = [
456
+ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
457
+ ]
458
+
459
  [[package]]
460
  name = "narwhals"
461
  version = "2.13.0"
 
465
  { url = "https://files.pythonhosted.org/packages/87/0d/1861d1599571974b15b025e12b142d8e6b42ad66c8a07a89cb0fc21f1e03/narwhals-2.13.0-py3-none-any.whl", hash = "sha256:9b795523c179ca78204e3be53726da374168f906e38de2ff174c2363baaaf481", size = 426407, upload-time = "2025-12-01T13:54:03.861Z" },
466
  ]
467
 
468
+ [[package]]
469
+ name = "networkx"
470
+ version = "3.6.1"
471
+ source = { registry = "https://pypi.org/simple" }
472
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
473
+ wheels = [
474
+ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
475
+ ]
476
+
477
  [[package]]
478
  name = "nltk"
479
  version = "3.9.2"
 
541
  { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
542
  ]
543
 
544
+ [[package]]
545
+ name = "nvidia-cublas-cu12"
546
+ version = "12.8.4.1"
547
+ source = { registry = "https://pypi.org/simple" }
548
+ wheels = [
549
+ { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" },
550
+ ]
551
+
552
+ [[package]]
553
+ name = "nvidia-cuda-cupti-cu12"
554
+ version = "12.8.90"
555
+ source = { registry = "https://pypi.org/simple" }
556
+ wheels = [
557
+ { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" },
558
+ ]
559
+
560
+ [[package]]
561
+ name = "nvidia-cuda-nvrtc-cu12"
562
+ version = "12.8.93"
563
+ source = { registry = "https://pypi.org/simple" }
564
+ wheels = [
565
+ { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" },
566
+ ]
567
+
568
+ [[package]]
569
+ name = "nvidia-cuda-runtime-cu12"
570
+ version = "12.8.90"
571
+ source = { registry = "https://pypi.org/simple" }
572
+ wheels = [
573
+ { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" },
574
+ ]
575
+
576
+ [[package]]
577
+ name = "nvidia-cudnn-cu12"
578
+ version = "9.10.2.21"
579
+ source = { registry = "https://pypi.org/simple" }
580
+ dependencies = [
581
+ { name = "nvidia-cublas-cu12" },
582
+ ]
583
+ wheels = [
584
+ { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" },
585
+ ]
586
+
587
+ [[package]]
588
+ name = "nvidia-cufft-cu12"
589
+ version = "11.3.3.83"
590
+ source = { registry = "https://pypi.org/simple" }
591
+ dependencies = [
592
+ { name = "nvidia-nvjitlink-cu12" },
593
+ ]
594
+ wheels = [
595
+ { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" },
596
+ ]
597
+
598
+ [[package]]
599
+ name = "nvidia-cufile-cu12"
600
+ version = "1.13.1.3"
601
+ source = { registry = "https://pypi.org/simple" }
602
+ wheels = [
603
+ { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" },
604
+ ]
605
+
606
+ [[package]]
607
+ name = "nvidia-curand-cu12"
608
+ version = "10.3.9.90"
609
+ source = { registry = "https://pypi.org/simple" }
610
+ wheels = [
611
+ { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" },
612
+ ]
613
+
614
+ [[package]]
615
+ name = "nvidia-cusolver-cu12"
616
+ version = "11.7.3.90"
617
+ source = { registry = "https://pypi.org/simple" }
618
+ dependencies = [
619
+ { name = "nvidia-cublas-cu12" },
620
+ { name = "nvidia-cusparse-cu12" },
621
+ { name = "nvidia-nvjitlink-cu12" },
622
+ ]
623
+ wheels = [
624
+ { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" },
625
+ ]
626
+
627
+ [[package]]
628
+ name = "nvidia-cusparse-cu12"
629
+ version = "12.5.8.93"
630
+ source = { registry = "https://pypi.org/simple" }
631
+ dependencies = [
632
+ { name = "nvidia-nvjitlink-cu12" },
633
+ ]
634
+ wheels = [
635
+ { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" },
636
+ ]
637
+
638
+ [[package]]
639
+ name = "nvidia-cusparselt-cu12"
640
+ version = "0.7.1"
641
+ source = { registry = "https://pypi.org/simple" }
642
+ wheels = [
643
+ { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" },
644
+ ]
645
+
646
+ [[package]]
647
+ name = "nvidia-nccl-cu12"
648
+ version = "2.27.5"
649
+ source = { registry = "https://pypi.org/simple" }
650
+ wheels = [
651
+ { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" },
652
+ ]
653
+
654
+ [[package]]
655
+ name = "nvidia-nvjitlink-cu12"
656
+ version = "12.8.93"
657
+ source = { registry = "https://pypi.org/simple" }
658
+ wheels = [
659
+ { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" },
660
+ ]
661
+
662
+ [[package]]
663
+ name = "nvidia-nvshmem-cu12"
664
+ version = "3.3.20"
665
+ source = { registry = "https://pypi.org/simple" }
666
+ wheels = [
667
+ { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" },
668
+ ]
669
+
670
+ [[package]]
671
+ name = "nvidia-nvtx-cu12"
672
+ version = "12.8.90"
673
+ source = { registry = "https://pypi.org/simple" }
674
+ wheels = [
675
+ { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" },
676
+ ]
677
+
678
  [[package]]
679
  name = "packaging"
680
  version = "25.0"
 
782
  { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" },
783
  ]
784
 
785
+ [[package]]
786
+ name = "plotly"
787
+ version = "6.5.2"
788
+ source = { registry = "https://pypi.org/simple" }
789
+ dependencies = [
790
+ { name = "narwhals" },
791
+ { name = "packaging" },
792
+ ]
793
+ sdist = { url = "https://files.pythonhosted.org/packages/e3/4f/8a10a9b9f5192cb6fdef62f1d77fa7d834190b2c50c0cd256bd62879212b/plotly-6.5.2.tar.gz", hash = "sha256:7478555be0198562d1435dee4c308268187553cc15516a2f4dd034453699e393", size = 7015695, upload-time = "2026-01-14T21:26:51.222Z" }
794
+ wheels = [
795
+ { url = "https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl", hash = "sha256:91757653bd9c550eeea2fa2404dba6b85d1e366d54804c340b2c874e5a7eb4a4", size = 9895973, upload-time = "2026-01-14T21:26:47.135Z" },
796
+ ]
797
+
798
  [[package]]
799
  name = "proto"
800
  version = "0.1.0"
801
  source = { virtual = "." }
802
  dependencies = [
803
+ { name = "filelock" },
804
+ { name = "google" },
805
+ { name = "google-genai" },
806
+ { name = "huggingface-hub" },
807
  { name = "nltk" },
808
+ { name = "numpy" },
809
+ { name = "packaging" },
810
  { name = "pandas" },
811
+ { name = "plotly" },
812
+ { name = "regex" },
813
+ { name = "requests" },
814
+ { name = "safetensors" },
815
  { name = "scikit-learn" },
816
  { name = "streamlit" },
817
+ { name = "tokenizers" },
818
+ { name = "torch" },
819
+ { name = "tqdm" },
820
+ { name = "transformers" },
821
  ]
822
 
823
  [package.metadata]
824
  requires-dist = [
825
+ { name = "filelock", specifier = ">=3.12.0" },
826
+ { name = "google", specifier = ">=3.0.0" },
827
+ { name = "google-genai", specifier = ">=1.56.0" },
828
+ { name = "huggingface-hub", specifier = ">=0.34.0,<1.0" },
829
  { name = "nltk", specifier = ">=3.9.2" },
830
+ { name = "numpy", specifier = ">=1.24.0" },
831
+ { name = "packaging", specifier = ">=23.0" },
832
  { name = "pandas", specifier = ">=2.3.3" },
833
+ { name = "plotly", specifier = ">=5.14.0" },
834
+ { name = "regex", specifier = ">=2023.5.0" },
835
+ { name = "requests", specifier = ">=2.31.0" },
836
+ { name = "safetensors", specifier = ">=0.3.0" },
837
  { name = "scikit-learn", specifier = ">=1.8.0" },
838
  { name = "streamlit", specifier = ">=1.52.1" },
839
+ { name = "tokenizers", specifier = ">=0.13.0" },
840
+ { name = "torch", specifier = ">=2.9.1" },
841
+ { name = "tqdm", specifier = ">=4.65.0" },
842
+ { name = "transformers", specifier = ">=4.30.0" },
843
  ]
844
 
845
  [[package]]
 
893
  { url = "https://files.pythonhosted.org/packages/7b/03/f335d6c52b4a4761bcc83499789a1e2e16d9d201a58c327a9b5cc9a41bd9/pyarrow-22.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0c34fe18094686194f204a3b1787a27456897d8a2d62caf84b61e8dfbc0252ae", size = 29185594, upload-time = "2025-10-24T10:09:53.111Z" },
894
  ]
895
 
896
+ [[package]]
897
+ name = "pyasn1"
898
+ version = "0.6.1"
899
+ source = { registry = "https://pypi.org/simple" }
900
+ sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" }
901
+ wheels = [
902
+ { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" },
903
+ ]
904
+
905
+ [[package]]
906
+ name = "pyasn1-modules"
907
+ version = "0.4.2"
908
+ source = { registry = "https://pypi.org/simple" }
909
+ dependencies = [
910
+ { name = "pyasn1" },
911
+ ]
912
+ sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" }
913
+ wheels = [
914
+ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
915
+ ]
916
+
917
+ [[package]]
918
+ name = "pydantic"
919
+ version = "2.12.5"
920
+ source = { registry = "https://pypi.org/simple" }
921
+ dependencies = [
922
+ { name = "annotated-types" },
923
+ { name = "pydantic-core" },
924
+ { name = "typing-extensions" },
925
+ { name = "typing-inspection" },
926
+ ]
927
+ sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
928
+ wheels = [
929
+ { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
930
+ ]
931
+
932
+ [[package]]
933
+ name = "pydantic-core"
934
+ version = "2.41.5"
935
+ source = { registry = "https://pypi.org/simple" }
936
+ dependencies = [
937
+ { name = "typing-extensions" },
938
+ ]
939
+ sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
940
+ wheels = [
941
+ { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
942
+ { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
943
+ { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
944
+ { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
945
+ { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
946
+ { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
947
+ { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
948
+ { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
949
+ { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
950
+ { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
951
+ { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
952
+ { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
953
+ { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
954
+ { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
955
+ { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
956
+ { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
957
+ { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
958
+ { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
959
+ { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
960
+ { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
961
+ { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
962
+ { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
963
+ { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
964
+ { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
965
+ { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
966
+ { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
967
+ { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
968
+ { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
969
+ { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
970
+ { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
971
+ { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
972
+ { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
973
+ { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
974
+ { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
975
+ { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
976
+ { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
977
+ { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
978
+ { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
979
+ { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
980
+ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
981
+ { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
982
+ { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
983
+ ]
984
+
985
  [[package]]
986
  name = "pydeck"
987
  version = "0.9.1"
 
1016
  { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
1017
  ]
1018
 
1019
+ [[package]]
1020
+ name = "pyyaml"
1021
+ version = "6.0.3"
1022
+ source = { registry = "https://pypi.org/simple" }
1023
+ sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
1024
+ wheels = [
1025
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
1026
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
1027
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
1028
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
1029
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
1030
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
1031
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
1032
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
1033
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
1034
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
1035
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
1036
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
1037
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
1038
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
1039
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
1040
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
1041
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
1042
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
1043
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
1044
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
1045
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
1046
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
1047
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
1048
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
1049
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
1050
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
1051
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
1052
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
1053
+ ]
1054
+
1055
  [[package]]
1056
  name = "referencing"
1057
  version = "0.37.0"
 
1210
  { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" },
1211
  ]
1212
 
1213
+ [[package]]
1214
+ name = "rsa"
1215
+ version = "4.9.1"
1216
+ source = { registry = "https://pypi.org/simple" }
1217
+ dependencies = [
1218
+ { name = "pyasn1" },
1219
+ ]
1220
+ sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
1221
+ wheels = [
1222
+ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
1223
+ ]
1224
+
1225
+ [[package]]
1226
+ name = "safetensors"
1227
+ version = "0.7.0"
1228
+ source = { registry = "https://pypi.org/simple" }
1229
+ sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" }
1230
+ wheels = [
1231
+ { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" },
1232
+ { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" },
1233
+ { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" },
1234
+ { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" },
1235
+ { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" },
1236
+ { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" },
1237
+ { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" },
1238
+ { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" },
1239
+ { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" },
1240
+ { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" },
1241
+ { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" },
1242
+ { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" },
1243
+ { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" },
1244
+ { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" },
1245
+ ]
1246
+
1247
  [[package]]
1248
  name = "scikit-learn"
1249
  version = "1.8.0"
 
1333
  { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" },
1334
  ]
1335
 
1336
+ [[package]]
1337
+ name = "setuptools"
1338
+ version = "80.9.0"
1339
+ source = { registry = "https://pypi.org/simple" }
1340
+ sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
1341
+ wheels = [
1342
+ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
1343
+ ]
1344
+
1345
  [[package]]
1346
  name = "six"
1347
  version = "1.17.0"
 
1360
  { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" },
1361
  ]
1362
 
1363
+ [[package]]
1364
+ name = "sniffio"
1365
+ version = "1.3.1"
1366
+ source = { registry = "https://pypi.org/simple" }
1367
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
1368
+ wheels = [
1369
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
1370
+ ]
1371
+
1372
+ [[package]]
1373
+ name = "soupsieve"
1374
+ version = "2.8.1"
1375
+ source = { registry = "https://pypi.org/simple" }
1376
+ sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" }
1377
+ wheels = [
1378
+ { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" },
1379
+ ]
1380
+
1381
  [[package]]
1382
  name = "streamlit"
1383
  version = "1.52.1"
 
1407
  { url = "https://files.pythonhosted.org/packages/d0/d4/cdafd4cc940937410f465ca7a77dd34237182c2ddece624e08db959496f8/streamlit-1.52.1-py3-none-any.whl", hash = "sha256:97fee2c3421d350fd65548e45a20f506ec1b651d78f95ecacbc0c2f9f838081c", size = 9024748, upload-time = "2025-12-05T18:55:39.713Z" },
1408
  ]
1409
 
1410
+ [[package]]
1411
+ name = "sympy"
1412
+ version = "1.14.0"
1413
+ source = { registry = "https://pypi.org/simple" }
1414
+ dependencies = [
1415
+ { name = "mpmath" },
1416
+ ]
1417
+ sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
1418
+ wheels = [
1419
+ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
1420
+ ]
1421
+
1422
  [[package]]
1423
  name = "tenacity"
1424
  version = "9.1.2"
 
1437
  { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" },
1438
  ]
1439
 
1440
+ [[package]]
1441
+ name = "tokenizers"
1442
+ version = "0.22.2"
1443
+ source = { registry = "https://pypi.org/simple" }
1444
+ dependencies = [
1445
+ { name = "huggingface-hub" },
1446
+ ]
1447
+ sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" }
1448
+ wheels = [
1449
+ { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" },
1450
+ { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" },
1451
+ { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" },
1452
+ { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" },
1453
+ { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" },
1454
+ { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" },
1455
+ { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" },
1456
+ { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" },
1457
+ { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" },
1458
+ { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" },
1459
+ { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" },
1460
+ { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" },
1461
+ { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" },
1462
+ { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" },
1463
+ { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" },
1464
+ ]
1465
+
1466
  [[package]]
1467
  name = "toml"
1468
  version = "0.10.2"
 
1472
  { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
1473
  ]
1474
 
1475
+ [[package]]
1476
+ name = "torch"
1477
+ version = "2.9.1"
1478
+ source = { registry = "https://pypi.org/simple" }
1479
+ dependencies = [
1480
+ { name = "filelock" },
1481
+ { name = "fsspec" },
1482
+ { name = "jinja2" },
1483
+ { name = "networkx" },
1484
+ { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1485
+ { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1486
+ { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1487
+ { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1488
+ { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1489
+ { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1490
+ { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1491
+ { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1492
+ { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1493
+ { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1494
+ { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1495
+ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1496
+ { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1497
+ { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1498
+ { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1499
+ { name = "setuptools" },
1500
+ { name = "sympy" },
1501
+ { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
1502
+ { name = "typing-extensions" },
1503
+ ]
1504
+ wheels = [
1505
+ { url = "https://files.pythonhosted.org/packages/20/60/8fc5e828d050bddfab469b3fe78e5ab9a7e53dda9c3bdc6a43d17ce99e63/torch-2.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c29455d2b910b98738131990394da3e50eea8291dfeb4b12de71ecf1fdeb21cb", size = 104135743, upload-time = "2025-11-12T15:21:34.936Z" },
1506
+ { url = "https://files.pythonhosted.org/packages/f2/b7/6d3f80e6918213babddb2a37b46dbb14c15b14c5f473e347869a51f40e1f/torch-2.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:524de44cd13931208ba2c4bde9ec7741fd4ae6bfd06409a604fc32f6520c2bc9", size = 899749493, upload-time = "2025-11-12T15:24:36.356Z" },
1507
+ { url = "https://files.pythonhosted.org/packages/a6/47/c7843d69d6de8938c1cbb1eba426b1d48ddf375f101473d3e31a5fc52b74/torch-2.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:545844cc16b3f91e08ce3b40e9c2d77012dd33a48d505aed34b7740ed627a1b2", size = 110944162, upload-time = "2025-11-12T15:21:53.151Z" },
1508
+ { url = "https://files.pythonhosted.org/packages/28/0e/2a37247957e72c12151b33a01e4df651d9d155dd74d8cfcbfad15a79b44a/torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e", size = 74830751, upload-time = "2025-11-12T15:21:43.792Z" },
1509
+ { url = "https://files.pythonhosted.org/packages/4b/f7/7a18745edcd7b9ca2381aa03353647bca8aace91683c4975f19ac233809d/torch-2.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:30a3e170a84894f3652434b56d59a64a2c11366b0ed5776fab33c2439396bf9a", size = 104142929, upload-time = "2025-11-12T15:21:48.319Z" },
1510
+ { url = "https://files.pythonhosted.org/packages/f4/dd/f1c0d879f2863ef209e18823a988dc7a1bf40470750e3ebe927efdb9407f/torch-2.9.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8301a7b431e51764629208d0edaa4f9e4c33e6df0f2f90b90e261d623df6a4e2", size = 899748978, upload-time = "2025-11-12T15:23:04.568Z" },
1511
+ { url = "https://files.pythonhosted.org/packages/1f/9f/6986b83a53b4d043e36f3f898b798ab51f7f20fdf1a9b01a2720f445043d/torch-2.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2e1c42c0ae92bf803a4b2409fdfed85e30f9027a66887f5e7dcdbc014c7531db", size = 111176995, upload-time = "2025-11-12T15:22:01.618Z" },
1512
+ { url = "https://files.pythonhosted.org/packages/40/60/71c698b466dd01e65d0e9514b5405faae200c52a76901baf6906856f17e4/torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587", size = 74480347, upload-time = "2025-11-12T15:21:57.648Z" },
1513
+ { url = "https://files.pythonhosted.org/packages/48/50/c4b5112546d0d13cc9eaa1c732b823d676a9f49ae8b6f97772f795874a03/torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a", size = 74433245, upload-time = "2025-11-12T15:22:39.027Z" },
1514
+ { url = "https://files.pythonhosted.org/packages/81/c9/2628f408f0518b3bae49c95f5af3728b6ab498c8624ab1e03a43dd53d650/torch-2.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:19d144d6b3e29921f1fc70503e9f2fc572cde6a5115c0c0de2f7ca8b1483e8b6", size = 104134804, upload-time = "2025-11-12T15:22:35.222Z" },
1515
+ { url = "https://files.pythonhosted.org/packages/28/fc/5bc91d6d831ae41bf6e9e6da6468f25330522e92347c9156eb3f1cb95956/torch-2.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c432d04376f6d9767a9852ea0def7b47a7bbc8e7af3b16ac9cf9ce02b12851c9", size = 899747132, upload-time = "2025-11-12T15:23:36.068Z" },
1516
+ { url = "https://files.pythonhosted.org/packages/63/5d/e8d4e009e52b6b2cf1684bde2a6be157b96fb873732542fb2a9a99e85a83/torch-2.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:d187566a2cdc726fc80138c3cdb260970fab1c27e99f85452721f7759bbd554d", size = 110934845, upload-time = "2025-11-12T15:22:48.367Z" },
1517
+ { url = "https://files.pythonhosted.org/packages/bd/b2/2d15a52516b2ea3f414643b8de68fa4cb220d3877ac8b1028c83dc8ca1c4/torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c", size = 74823558, upload-time = "2025-11-12T15:22:43.392Z" },
1518
+ { url = "https://files.pythonhosted.org/packages/86/5c/5b2e5d84f5b9850cd1e71af07524d8cbb74cba19379800f1f9f7c997fc70/torch-2.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0a2bd769944991c74acf0c4ef23603b9c777fdf7637f115605a4b2d8023110c7", size = 104145788, upload-time = "2025-11-12T15:23:52.109Z" },
1519
+ { url = "https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:07c8a9660bc9414c39cac530ac83b1fb1b679d7155824144a40a54f4a47bfa73", size = 899735500, upload-time = "2025-11-12T15:24:08.788Z" },
1520
+ { url = "https://files.pythonhosted.org/packages/db/2b/f7818f6ec88758dfd21da46b6cd46af9d1b3433e53ddbb19ad1e0da17f9b/torch-2.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c88d3299ddeb2b35dcc31753305612db485ab6f1823e37fb29451c8b2732b87e", size = 111163659, upload-time = "2025-11-12T15:23:20.009Z" },
1521
+ ]
1522
+
1523
  [[package]]
1524
  name = "tornado"
1525
  version = "6.5.3"
 
1551
  { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
1552
  ]
1553
 
1554
+ [[package]]
1555
+ name = "transformers"
1556
+ version = "4.57.6"
1557
+ source = { registry = "https://pypi.org/simple" }
1558
+ dependencies = [
1559
+ { name = "filelock" },
1560
+ { name = "huggingface-hub" },
1561
+ { name = "numpy" },
1562
+ { name = "packaging" },
1563
+ { name = "pyyaml" },
1564
+ { name = "regex" },
1565
+ { name = "requests" },
1566
+ { name = "safetensors" },
1567
+ { name = "tokenizers" },
1568
+ { name = "tqdm" },
1569
+ ]
1570
+ sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" }
1571
+ wheels = [
1572
+ { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" },
1573
+ ]
1574
+
1575
+ [[package]]
1576
+ name = "triton"
1577
+ version = "3.5.1"
1578
+ source = { registry = "https://pypi.org/simple" }
1579
+ wheels = [
1580
+ { url = "https://files.pythonhosted.org/packages/27/46/8c3bbb5b0a19313f50edcaa363b599e5a1a5ac9683ead82b9b80fe497c8d/triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba", size = 170470410, upload-time = "2025-11-11T17:41:06.319Z" },
1581
+ { url = "https://files.pythonhosted.org/packages/37/92/e97fcc6b2c27cdb87ce5ee063d77f8f26f19f06916aa680464c8104ef0f6/triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8", size = 170579924, upload-time = "2025-11-11T17:41:12.455Z" },
1582
+ { url = "https://files.pythonhosted.org/packages/a4/e6/c595c35e5c50c4bc56a7bac96493dad321e9e29b953b526bbbe20f9911d0/triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60", size = 170480488, upload-time = "2025-11-11T17:41:18.222Z" },
1583
+ { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192, upload-time = "2025-11-11T17:41:23.963Z" },
1584
+ ]
1585
+
1586
  [[package]]
1587
  name = "typing-extensions"
1588
  version = "4.15.0"
 
1592
  { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
1593
  ]
1594
 
1595
+ [[package]]
1596
+ name = "typing-inspection"
1597
+ version = "0.4.2"
1598
+ source = { registry = "https://pypi.org/simple" }
1599
+ dependencies = [
1600
+ { name = "typing-extensions" },
1601
+ ]
1602
+ sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
1603
+ wheels = [
1604
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
1605
+ ]
1606
+
1607
  [[package]]
1608
  name = "tzdata"
1609
  version = "2025.3"
 
1639
  { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
1640
  { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
1641
  ]
1642
+
1643
+ [[package]]
1644
+ name = "websockets"
1645
+ version = "15.0.1"
1646
+ source = { registry = "https://pypi.org/simple" }
1647
+ sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
1648
+ wheels = [
1649
+ { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
1650
+ { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
1651
+ { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
1652
+ { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
1653
+ { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
1654
+ { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
1655
+ { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
1656
+ { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
1657
+ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
1658
+ { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
1659
+ { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
1660
+ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
1661
+ ]