Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -7,6 +7,7 @@ from typing import Tuple, Dict, Any, Optional
|
|
7 |
import tempfile
|
8 |
import io
|
9 |
import datetime
|
|
|
10 |
|
11 |
class FeedbackTransformer:
|
12 |
"""
|
@@ -258,6 +259,31 @@ class FeedbackTransformer:
|
|
258 |
|
259 |
return analysis_text
|
260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
def save_transformed_data(self, output_format='xlsx'):
|
262 |
"""
|
263 |
Save the transformed data and return the file path.
|
@@ -379,6 +405,7 @@ def process_file(file_obj, topic_prefix, sentiment_prefix, category_prefix,
|
|
379 |
text_column, recommendation_column, output_format, analyze_data, selected_columns):
|
380 |
"""
|
381 |
Main processing function for Gradio interface.
|
|
|
382 |
"""
|
383 |
try:
|
384 |
# Extract actual column names from display format
|
@@ -423,15 +450,58 @@ def process_file(file_obj, topic_prefix, sentiment_prefix, category_prefix,
|
|
423 |
if analyze_data:
|
424 |
analysis_result = transformer.analyze_data()
|
425 |
|
426 |
-
# Save transformed data
|
427 |
output_file = transformer.save_transformed_data(output_format)
|
428 |
-
|
|
|
|
|
|
|
|
|
429 |
|
430 |
-
return status_msg, analysis_result, output_file
|
431 |
|
432 |
except Exception as e:
|
433 |
error_msg = f"❌ Error: {str(e)}\n\n{traceback.format_exc()}"
|
434 |
-
return error_msg, "", None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
|
437 |
# Create Gradio interface
|
@@ -453,7 +523,7 @@ with gr.Blocks(title="Feedback Topic & Sentiment Transformer", css="""
|
|
453 |
2. Select which original columns to include in the output
|
454 |
3. Configure column prefixes (or use defaults)
|
455 |
4. Click "Transform Data" to process
|
456 |
-
5. Download the transformed file
|
457 |
""")
|
458 |
|
459 |
with gr.Row():
|
@@ -537,16 +607,30 @@ with gr.Blocks(title="Feedback Topic & Sentiment Transformer", css="""
|
|
537 |
label="Data Analysis"
|
538 |
)
|
539 |
|
540 |
-
# Download
|
541 |
with gr.Row():
|
542 |
with gr.Column():
|
543 |
gr.Markdown("### �� 5. Download Transformed File")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
output_file = gr.File(
|
545 |
-
label="
|
546 |
interactive=False,
|
547 |
visible=True
|
548 |
)
|
549 |
|
|
|
|
|
|
|
550 |
# Event handlers
|
551 |
input_file.change(
|
552 |
fn=get_column_selector,
|
@@ -567,7 +651,11 @@ with gr.Blocks(title="Feedback Topic & Sentiment Transformer", css="""
|
|
567 |
analyze_checkbox,
|
568 |
column_selector
|
569 |
],
|
570 |
-
outputs=[status_output, analysis_output, output_file]
|
|
|
|
|
|
|
|
|
571 |
)
|
572 |
|
573 |
# Examples section
|
@@ -589,7 +677,8 @@ with gr.Blocks(title="Feedback Topic & Sentiment Transformer", css="""
|
|
589 |
- Use the numbered column list to easily identify and select columns
|
590 |
- The text and recommendation column names in configuration are now for reference only
|
591 |
- To include them in output, select them using the column checkboxes
|
592 |
-
-
|
|
|
593 |
""")
|
594 |
|
595 |
# Launch the app
|
|
|
7 |
import tempfile
|
8 |
import io
|
9 |
import datetime
|
10 |
+
import base64
|
11 |
|
12 |
class FeedbackTransformer:
|
13 |
"""
|
|
|
259 |
|
260 |
return analysis_text
|
261 |
|
262 |
+
def get_download_data(self, output_format='xlsx'):
|
263 |
+
"""
|
264 |
+
Return the data as bytes for direct download (NEW METHOD).
|
265 |
+
"""
|
266 |
+
if self.transformed_data is None:
|
267 |
+
raise ValueError("No transformed data to save")
|
268 |
+
|
269 |
+
# Create filename with original filename prefix and timestamp
|
270 |
+
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
271 |
+
prefix = self.original_filename if self.original_filename else 'transformed_feedback'
|
272 |
+
|
273 |
+
if output_format == 'xlsx':
|
274 |
+
filename = f"{prefix}_transformed_{timestamp}.xlsx"
|
275 |
+
# Create bytes buffer
|
276 |
+
buffer = io.BytesIO()
|
277 |
+
self.transformed_data.to_excel(buffer, index=False)
|
278 |
+
buffer.seek(0)
|
279 |
+
return buffer.getvalue(), filename
|
280 |
+
else: # csv
|
281 |
+
filename = f"{prefix}_transformed_{timestamp}.csv"
|
282 |
+
# Create string buffer and encode to bytes
|
283 |
+
buffer = io.StringIO()
|
284 |
+
self.transformed_data.to_csv(buffer, index=False)
|
285 |
+
return buffer.getvalue().encode('utf-8'), filename
|
286 |
+
|
287 |
def save_transformed_data(self, output_format='xlsx'):
|
288 |
"""
|
289 |
Save the transformed data and return the file path.
|
|
|
405 |
text_column, recommendation_column, output_format, analyze_data, selected_columns):
|
406 |
"""
|
407 |
Main processing function for Gradio interface.
|
408 |
+
Returns both file path and download data for multiple download options.
|
409 |
"""
|
410 |
try:
|
411 |
# Extract actual column names from display format
|
|
|
450 |
if analyze_data:
|
451 |
analysis_result = transformer.analyze_data()
|
452 |
|
453 |
+
# Save transformed data (for regular file download)
|
454 |
output_file = transformer.save_transformed_data(output_format)
|
455 |
+
|
456 |
+
# Get download data (for direct download button)
|
457 |
+
download_data, filename = transformer.get_download_data(output_format)
|
458 |
+
|
459 |
+
status_msg += f"\n💾 File ready for download: {filename}\n"
|
460 |
|
461 |
+
return status_msg, analysis_result, output_file, (download_data, filename)
|
462 |
|
463 |
except Exception as e:
|
464 |
error_msg = f"❌ Error: {str(e)}\n\n{traceback.format_exc()}"
|
465 |
+
return error_msg, "", None, None
|
466 |
+
|
467 |
+
|
468 |
+
def create_download_link(download_data_tuple):
|
469 |
+
"""
|
470 |
+
Create a direct download link using data URI (NEW FUNCTION).
|
471 |
+
"""
|
472 |
+
if download_data_tuple is None:
|
473 |
+
return None
|
474 |
+
|
475 |
+
download_data, filename = download_data_tuple
|
476 |
+
|
477 |
+
# Encode data as base64
|
478 |
+
b64_data = base64.b64encode(download_data).decode()
|
479 |
+
|
480 |
+
# Determine MIME type
|
481 |
+
if filename.endswith('.xlsx'):
|
482 |
+
mime_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
483 |
+
else:
|
484 |
+
mime_type = 'text/csv'
|
485 |
+
|
486 |
+
# Create data URI
|
487 |
+
data_uri = f"data:{mime_type};base64,{b64_data}"
|
488 |
+
|
489 |
+
# Return HTML with download link
|
490 |
+
download_html = f"""
|
491 |
+
<div style="text-align: center; padding: 20px; border: 2px dashed #007bff; border-radius: 10px; background-color: #f8f9fa;">
|
492 |
+
<h3 style="color: #007bff; margin-bottom: 15px;">📥 Download Ready!</h3>
|
493 |
+
<a href="{data_uri}" download="{filename}"
|
494 |
+
style="display: inline-block; padding: 12px 24px; background-color: #007bff; color: white;
|
495 |
+
text-decoration: none; border-radius: 5px; font-weight: bold; font-size: 16px;">
|
496 |
+
📄 Download {filename}
|
497 |
+
</a>
|
498 |
+
<p style="margin-top: 15px; color: #6c757d; font-size: 14px;">
|
499 |
+
Click the button above to download your transformed data file.
|
500 |
+
</p>
|
501 |
+
</div>
|
502 |
+
"""
|
503 |
+
|
504 |
+
return download_html
|
505 |
|
506 |
|
507 |
# Create Gradio interface
|
|
|
523 |
2. Select which original columns to include in the output
|
524 |
3. Configure column prefixes (or use defaults)
|
525 |
4. Click "Transform Data" to process
|
526 |
+
5. Download the transformed file using the download button below
|
527 |
""")
|
528 |
|
529 |
with gr.Row():
|
|
|
607 |
label="Data Analysis"
|
608 |
)
|
609 |
|
610 |
+
# Download sections - Multiple options for better compatibility
|
611 |
with gr.Row():
|
612 |
with gr.Column():
|
613 |
gr.Markdown("### �� 5. Download Transformed File")
|
614 |
+
|
615 |
+
# Primary download method - Direct download link
|
616 |
+
download_link = gr.HTML(
|
617 |
+
label="Direct Download",
|
618 |
+
value="Process a file to generate download link",
|
619 |
+
visible=True
|
620 |
+
)
|
621 |
+
|
622 |
+
with gr.Column():
|
623 |
+
gr.Markdown("### 📥 Alternative Download")
|
624 |
+
# Fallback download method - Traditional file component
|
625 |
output_file = gr.File(
|
626 |
+
label="Fallback Download (if direct download doesn't work)",
|
627 |
interactive=False,
|
628 |
visible=True
|
629 |
)
|
630 |
|
631 |
+
# Hidden state to store download data
|
632 |
+
download_data_state = gr.State()
|
633 |
+
|
634 |
# Event handlers
|
635 |
input_file.change(
|
636 |
fn=get_column_selector,
|
|
|
651 |
analyze_checkbox,
|
652 |
column_selector
|
653 |
],
|
654 |
+
outputs=[status_output, analysis_output, output_file, download_data_state]
|
655 |
+
).then(
|
656 |
+
fn=create_download_link,
|
657 |
+
inputs=[download_data_state],
|
658 |
+
outputs=[download_link]
|
659 |
)
|
660 |
|
661 |
# Examples section
|
|
|
677 |
- Use the numbered column list to easily identify and select columns
|
678 |
- The text and recommendation column names in configuration are now for reference only
|
679 |
- To include them in output, select them using the column checkboxes
|
680 |
+
- **Two download options provided**: Try the direct download button first. If it doesn't work in your embedded environment, use the fallback download link.
|
681 |
+
- The direct download creates a clickable button that should work better in embedded applications
|
682 |
""")
|
683 |
|
684 |
# Launch the app
|