Rogaton Claude commited on
Commit
6865b40
·
1 Parent(s): 0c2152d

fix: Add API token input and improve file uploader

Browse files

**API Token Support:**
- Add password-protected input field for HuggingFace API token
- Display clear instructions with link to get token
- Check token presence before translation attempts
- Support both user-provided tokens and Space secrets
- Better error messages for missing/invalid tokens

**File Uploader Improvements:**
- Add 20MB file size limit with validation
- Improve error handling with descriptive messages
- Add file extension preservation for temp files
- Auto-cleanup of temporary files after loading
- Better success/warning messages

**UX Enhancements:**
- Clear visual sections with dividers
- Emoji indicators for status
- Direct links to HF token settings
- Informative help text

This resolves the "api_key required" error and improves file upload reliability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (1) hide show
  1. apertus_ui.py +82 -28
apertus_ui.py CHANGED
@@ -116,26 +116,66 @@ selected_lang = st.selectbox("Language / Langue / Idioma",
116
  # Sidebar for Coptic tools
117
  with st.sidebar:
118
  st.header("Coptic Tools")
119
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  # Lexicon file uploader
121
- lexicon_file = st.file_uploader("Upload Coptic Lexicon",
122
- type=['txt', 'tsv', 'csv', 'xml'],
123
- help="Supports: Text (TAB/pipe separated), XML (Crum format), CSV")
 
 
 
124
 
125
  # Load lexicon
126
  if lexicon_file:
127
- # Save uploaded file temporarily
128
- with open("temp_lexicon.txt", "wb") as f:
129
- f.write(lexicon_file.getbuffer())
130
- coptic_lexicon = load_coptic_lexicon("temp_lexicon.txt")
131
- st.success(f"Loaded {len(coptic_lexicon)} lexicon entries")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  else:
133
  # Try to load the comprehensive lexicon if available
134
  comprehensive_lexicon_path = "Comprehensive_Coptic_Lexicon-v1.2-2020.xml"
135
  if os.path.exists(comprehensive_lexicon_path):
136
  coptic_lexicon = load_coptic_lexicon(comprehensive_lexicon_path)
137
  if coptic_lexicon:
138
- st.info(f"Loaded Comprehensive Coptic Lexicon: {len(coptic_lexicon)} entries")
139
  else:
140
  coptic_lexicon = {}
141
  else:
@@ -231,20 +271,22 @@ with st.sidebar:
231
  # This is much faster and doesn't require GPU
232
  MODEL_NAME = "swiss-ai/Apertus-8B-Instruct-2509"
233
 
234
- @st.cache_resource
235
- def get_inference_client():
236
- """Initialize HuggingFace Inference API client"""
237
  try:
238
- # Get HF token from secrets or environment (optional for public models)
239
- hf_token = st.secrets.get("HF_TOKEN", None) if hasattr(st, 'secrets') else None
240
- client = InferenceClient(token=hf_token)
241
- st.success("✅ Connected to Apertus-8B via HuggingFace Inference API")
242
- return client
 
 
 
 
 
243
  except Exception as e:
244
- st.warning(f"⚠️ Using free-tier inference (may be slower): {e}")
245
- return InferenceClient() # No token = free tier
246
-
247
- inference_client = get_inference_client()
248
 
249
  # Chat interface
250
  if "messages" not in st.session_state:
@@ -257,10 +299,22 @@ for message in st.session_state.messages:
257
 
258
  # User input
259
  if prompt := st.chat_input("Type your message..."):
 
 
 
 
 
 
 
 
 
 
 
 
260
  # Add Coptic-specific prompt prefix if applicable
261
  if selected_lang in ['cop', 'cop-sa', 'cop-bo'] and 'analysis_type' in locals():
262
  full_prompt = f"{COPTIC_PROMPTS[analysis_type]} {prompt}"
263
-
264
  # Add lexicon context for lexicon lookup
265
  if analysis_type == 'lexicon_lookup' and coptic_lexicon:
266
  words_in_prompt = prompt.split()
@@ -268,17 +322,17 @@ if prompt := st.chat_input("Type your message..."):
268
  for word in words_in_prompt:
269
  if word in coptic_lexicon:
270
  lexicon_matches.append(f"{word} = {coptic_lexicon[word]}")
271
-
272
  if lexicon_matches:
273
  full_prompt += f"\n\nLexicon entries found: {'; '.join(lexicon_matches)}"
274
  else:
275
  full_prompt = prompt
276
-
277
  st.session_state.messages.append({"role": "user", "content": full_prompt})
278
-
279
  with st.chat_message("user"):
280
  st.markdown(full_prompt)
281
-
282
  # Generate response using HuggingFace Inference API
283
  with st.chat_message("assistant"):
284
  try:
@@ -309,4 +363,4 @@ if prompt := st.chat_input("Type your message..."):
309
 
310
  except Exception as e:
311
  st.error(f"❌ Error generating response: {str(e)}")
312
- st.info("💡 The model may be loading or temporarily unavailable. Please try again in a moment.")
 
116
  # Sidebar for Coptic tools
117
  with st.sidebar:
118
  st.header("Coptic Tools")
119
+
120
+ # HuggingFace API Token input
121
+ st.subheader("🔑 API Configuration")
122
+ hf_token_input = st.text_input(
123
+ "HuggingFace API Token",
124
+ type="password",
125
+ help="Required for Apertus-8B translation. Get your token at: https://huggingface.co/settings/tokens"
126
+ )
127
+ if hf_token_input:
128
+ st.success("✅ API token configured")
129
+ else:
130
+ st.warning("⚠️ Translation requires an API token")
131
+ st.markdown("[Get your free HF token →](https://huggingface.co/settings/tokens)")
132
+
133
+ st.divider()
134
+
135
  # Lexicon file uploader
136
+ st.subheader("📚 Lexicon Upload")
137
+ lexicon_file = st.file_uploader(
138
+ "Upload Coptic Lexicon (optional)",
139
+ type=['txt', 'tsv', 'csv', 'xml'],
140
+ help="Supports: Text (TAB/pipe separated), XML (TEI format), CSV\nNote: Comprehensive lexicon is pre-loaded"
141
+ )
142
 
143
  # Load lexicon
144
  if lexicon_file:
145
+ try:
146
+ # Check file size (max 20MB)
147
+ file_size = len(lexicon_file.getvalue())
148
+ if file_size > 20 * 1024 * 1024:
149
+ st.error(" File too large (max 20MB)")
150
+ coptic_lexicon = {}
151
+ else:
152
+ # Save uploaded file temporarily
153
+ temp_path = f"temp_lexicon.{lexicon_file.name.split('.')[-1]}"
154
+ with open(temp_path, "wb") as f:
155
+ f.write(lexicon_file.getbuffer())
156
+
157
+ coptic_lexicon = load_coptic_lexicon(temp_path)
158
+
159
+ if coptic_lexicon:
160
+ st.success(f"✅ Loaded {len(coptic_lexicon)} lexicon entries from {lexicon_file.name}")
161
+ else:
162
+ st.warning("⚠️ File uploaded but no valid entries found")
163
+ coptic_lexicon = {}
164
+
165
+ # Clean up temp file
166
+ if os.path.exists(temp_path):
167
+ os.remove(temp_path)
168
+ except Exception as e:
169
+ st.error(f"❌ Error loading file: {str(e)}")
170
+ st.info("💡 Supported formats: Plain text (TAB/pipe separated), XML (TEI), CSV")
171
+ coptic_lexicon = {}
172
  else:
173
  # Try to load the comprehensive lexicon if available
174
  comprehensive_lexicon_path = "Comprehensive_Coptic_Lexicon-v1.2-2020.xml"
175
  if os.path.exists(comprehensive_lexicon_path):
176
  coptic_lexicon = load_coptic_lexicon(comprehensive_lexicon_path)
177
  if coptic_lexicon:
178
+ st.info(f"📚 Loaded Comprehensive Coptic Lexicon: {len(coptic_lexicon)} entries")
179
  else:
180
  coptic_lexicon = {}
181
  else:
 
271
  # This is much faster and doesn't require GPU
272
  MODEL_NAME = "swiss-ai/Apertus-8B-Instruct-2509"
273
 
274
+ def get_inference_client(token=None):
275
+ """Initialize HuggingFace Inference API client with provided token"""
 
276
  try:
277
+ if token:
278
+ client = InferenceClient(token=token)
279
+ return client
280
+ else:
281
+ # Try to get token from Space secrets as fallback
282
+ if hasattr(st, 'secrets') and 'HF_TOKEN' in st.secrets:
283
+ client = InferenceClient(token=st.secrets['HF_TOKEN'])
284
+ return client
285
+ else:
286
+ return None
287
  except Exception as e:
288
+ st.error(f"Error initializing inference client: {e}")
289
+ return None
 
 
290
 
291
  # Chat interface
292
  if "messages" not in st.session_state:
 
299
 
300
  # User input
301
  if prompt := st.chat_input("Type your message..."):
302
+ # Check if API token is available
303
+ if not hf_token_input:
304
+ st.error("⚠️ Please enter your HuggingFace API token in the sidebar to use translation.")
305
+ st.stop()
306
+
307
+ # Initialize inference client with user token
308
+ inference_client = get_inference_client(hf_token_input)
309
+
310
+ if not inference_client:
311
+ st.error("❌ Failed to initialize inference client. Please check your API token.")
312
+ st.stop()
313
+
314
  # Add Coptic-specific prompt prefix if applicable
315
  if selected_lang in ['cop', 'cop-sa', 'cop-bo'] and 'analysis_type' in locals():
316
  full_prompt = f"{COPTIC_PROMPTS[analysis_type]} {prompt}"
317
+
318
  # Add lexicon context for lexicon lookup
319
  if analysis_type == 'lexicon_lookup' and coptic_lexicon:
320
  words_in_prompt = prompt.split()
 
322
  for word in words_in_prompt:
323
  if word in coptic_lexicon:
324
  lexicon_matches.append(f"{word} = {coptic_lexicon[word]}")
325
+
326
  if lexicon_matches:
327
  full_prompt += f"\n\nLexicon entries found: {'; '.join(lexicon_matches)}"
328
  else:
329
  full_prompt = prompt
330
+
331
  st.session_state.messages.append({"role": "user", "content": full_prompt})
332
+
333
  with st.chat_message("user"):
334
  st.markdown(full_prompt)
335
+
336
  # Generate response using HuggingFace Inference API
337
  with st.chat_message("assistant"):
338
  try:
 
363
 
364
  except Exception as e:
365
  st.error(f"❌ Error generating response: {str(e)}")
366
+ st.info("💡 Please verify your API token is valid and has not expired.")