Spaces:
Sleeping
Sleeping
""" | |
Streamlit frontend for Multi-Lingual Product Catalog Translator | |
Provides user-friendly interface for sellers to translate and edit product listings | |
""" | |
import streamlit as st | |
import requests | |
import json | |
import pandas as pd | |
from datetime import datetime | |
import time | |
from typing import Dict, List, Optional | |
# Configure Streamlit page | |
st.set_page_config( | |
page_title="Multi-Lingual Catalog Translator", | |
page_icon="π", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# Configuration | |
API_BASE_URL = "http://localhost:8001" | |
# Language mappings | |
SUPPORTED_LANGUAGES = { | |
"en": "English", | |
"hi": "Hindi", | |
"bn": "Bengali", | |
"gu": "Gujarati", | |
"kn": "Kannada", | |
"ml": "Malayalam", | |
"mr": "Marathi", | |
"or": "Odia", | |
"pa": "Punjabi", | |
"ta": "Tamil", | |
"te": "Telugu", | |
"ur": "Urdu", | |
"as": "Assamese", | |
"ne": "Nepali", | |
"sa": "Sanskrit" | |
} | |
def make_api_request(endpoint: str, method: str = "GET", data: dict = None) -> dict: | |
"""Make API request to backend""" | |
try: | |
url = f"{API_BASE_URL}{endpoint}" | |
if method == "GET": | |
response = requests.get(url) | |
elif method == "POST": | |
response = requests.post(url, json=data) | |
else: | |
raise ValueError(f"Unsupported method: {method}") | |
response.raise_for_status() | |
return response.json() | |
except requests.exceptions.ConnectionError: | |
st.error("β Could not connect to the backend API. Please ensure the FastAPI server is running on localhost:8001") | |
return {} | |
except requests.exceptions.RequestException as e: | |
st.error(f"β API Error: {str(e)}") | |
return {} | |
except Exception as e: | |
st.error(f"β Unexpected error: {str(e)}") | |
return {} | |
def check_api_health(): | |
"""Check if API is healthy""" | |
try: | |
response = make_api_request("/") | |
return bool(response) | |
except: | |
return False | |
def main(): | |
"""Main Streamlit application""" | |
# Header | |
st.title("π Multi-Lingual Product Catalog Translator") | |
st.markdown("### Powered by IndicTrans2 by AI4Bharat") | |
st.markdown("Translate your product listings into multiple Indian languages instantly!") | |
# Check API health | |
if not check_api_health(): | |
st.error("π΄ Backend API is not available. Please start the FastAPI server first.") | |
st.code("cd backend && python main.py", language="bash") | |
return | |
else: | |
st.success("π’ Backend API is connected!") | |
# Sidebar for navigation | |
st.sidebar.title("Navigation") | |
page = st.sidebar.radio( | |
"Choose a page:", | |
["π Translate Product", "π Translation History", "π Analytics", "βοΈ Settings"] | |
) | |
if page == "π Translate Product": | |
translate_product_page() | |
elif page == "π Translation History": | |
translation_history_page() | |
elif page == "π Analytics": | |
analytics_page() | |
elif page == "βοΈ Settings": | |
settings_page() | |
def translate_product_page(): | |
"""Main product translation page""" | |
st.header("π Translate Product Listing") | |
# Create two columns for input and output | |
col1, col2 = st.columns([1, 1]) | |
with col1: | |
st.subheader("π₯ Input") | |
# Product details input | |
with st.form("product_form"): | |
product_title = st.text_input( | |
"Product Title *", | |
placeholder="Enter your product title...", | |
help="The main title of your product" | |
) | |
product_description = st.text_area( | |
"Product Description *", | |
placeholder="Enter detailed product description...", | |
height=150, | |
help="Detailed description of your product" | |
) | |
product_category = st.text_input( | |
"Category (Optional)", | |
placeholder="e.g., Electronics, Clothing, Books...", | |
help="Product category for better context" | |
) | |
# Language selection | |
st.markdown("---") | |
st.subheader("π Language Settings") | |
source_lang = st.selectbox( | |
"Source Language", | |
options=["auto-detect"] + list(SUPPORTED_LANGUAGES.keys()), | |
format_func=lambda x: "π Auto-detect" if x == "auto-detect" else f"{SUPPORTED_LANGUAGES.get(x, x)} ({x})", | |
help="Select the language of your input text, or use auto-detect" | |
) | |
target_languages = st.multiselect( | |
"Target Languages *", | |
options=list(SUPPORTED_LANGUAGES.keys()), | |
default=["en", "hi"], | |
format_func=lambda x: f"{SUPPORTED_LANGUAGES.get(x, x)} ({x})", | |
help="Select one or more languages to translate to" | |
) | |
submit_button = st.form_submit_button("π Translate", type="primary") | |
with col2: | |
st.subheader("π€ Output") | |
if submit_button: | |
if not product_title or not product_description: | |
st.error("Please fill in the required fields (Product Title and Description)") | |
return | |
if not target_languages: | |
st.error("Please select at least one target language") | |
return | |
# Process translations | |
with st.spinner("π Translating your product listing..."): | |
translations = process_translations( | |
product_title, | |
product_description, | |
product_category, | |
source_lang, | |
target_languages | |
) | |
if translations: | |
display_translations(translations, product_title, product_description, product_category) | |
def process_translations(title: str, description: str, category: str, source_lang: str, target_languages: List[str]) -> Dict: | |
"""Process translations for product fields""" | |
translations = {} | |
# Detect source language if auto-detect is selected | |
if source_lang == "auto-detect": | |
detection_result = make_api_request("/detect-language", "POST", {"text": title}) | |
if detection_result: | |
source_lang = detection_result.get("language", "en") | |
st.info(f"π Detected source language: {SUPPORTED_LANGUAGES.get(source_lang, source_lang)}") | |
# Translate to each target language | |
for target_lang in target_languages: | |
if target_lang == source_lang: | |
# Skip if source and target are the same | |
continue | |
translations[target_lang] = {} | |
# Translate title | |
title_result = make_api_request("/translate", "POST", { | |
"text": title, | |
"source_language": source_lang, | |
"target_language": target_lang | |
}) | |
if title_result: | |
translations[target_lang]["title"] = title_result | |
# Translate description | |
description_result = make_api_request("/translate", "POST", { | |
"text": description, | |
"source_language": source_lang, | |
"target_language": target_lang | |
}) | |
if description_result: | |
translations[target_lang]["description"] = description_result | |
# Translate category if provided | |
if category: | |
category_result = make_api_request("/translate", "POST", { | |
"text": category, | |
"source_language": source_lang, | |
"target_language": target_lang | |
}) | |
if category_result: | |
translations[target_lang]["category"] = category_result | |
return translations | |
def display_translations(translations: Dict, original_title: str, original_description: str, original_category: str): | |
"""Display translation results with editing capability""" | |
for target_lang, results in translations.items(): | |
lang_name = SUPPORTED_LANGUAGES.get(target_lang, target_lang) | |
with st.expander(f"π {lang_name} Translation", expanded=True): | |
# Title translation | |
if "title" in results: | |
st.markdown("**π Title:**") | |
translated_title = results["title"]["translated_text"] | |
translation_id = results["title"]["translation_id"] | |
# Editable text area for corrections | |
corrected_title = st.text_area( | |
f"Edit {lang_name} title:", | |
value=translated_title, | |
key=f"title_{target_lang}_{translation_id}", | |
height=50 | |
) | |
# Show confidence score | |
confidence = results["title"].get("confidence", 0) | |
st.caption(f"Confidence: {confidence:.2%}") | |
# Submit correction if text was edited | |
if corrected_title != translated_title: | |
if st.button(f"πΎ Save Title Correction", key=f"save_title_{translation_id}"): | |
submit_correction(translation_id, corrected_title, "Title correction") | |
# Description translation | |
if "description" in results: | |
st.markdown("**π Description:**") | |
translated_description = results["description"]["translated_text"] | |
translation_id = results["description"]["translation_id"] | |
corrected_description = st.text_area( | |
f"Edit {lang_name} description:", | |
value=translated_description, | |
key=f"description_{target_lang}_{translation_id}", | |
height=100 | |
) | |
confidence = results["description"].get("confidence", 0) | |
st.caption(f"Confidence: {confidence:.2%}") | |
if corrected_description != translated_description: | |
if st.button(f"πΎ Save Description Correction", key=f"save_desc_{translation_id}"): | |
submit_correction(translation_id, corrected_description, "Description correction") | |
# Category translation | |
if "category" in results: | |
st.markdown("**π·οΈ Category:**") | |
translated_category = results["category"]["translated_text"] | |
translation_id = results["category"]["translation_id"] | |
corrected_category = st.text_input( | |
f"Edit {lang_name} category:", | |
value=translated_category, | |
key=f"category_{target_lang}_{translation_id}" | |
) | |
confidence = results["category"].get("confidence", 0) | |
st.caption(f"Confidence: {confidence:.2%}") | |
if corrected_category != translated_category: | |
if st.button(f"πΎ Save Category Correction", key=f"save_cat_{translation_id}"): | |
submit_correction(translation_id, corrected_category, "Category correction") | |
st.markdown("---") | |
def submit_correction(translation_id: int, corrected_text: str, feedback: str): | |
"""Submit correction to the backend""" | |
result = make_api_request("/submit-correction", "POST", { | |
"translation_id": translation_id, | |
"corrected_text": corrected_text, | |
"feedback": feedback | |
}) | |
if result and result.get("status") == "success": | |
st.success("β Correction saved successfully!") | |
st.balloons() | |
else: | |
st.error("β Failed to save correction") | |
def translation_history_page(): | |
"""Translation history page""" | |
st.header("π Translation History") | |
# Fetch translation history | |
history = make_api_request("/history?limit=100") | |
if not history: | |
st.info("No translation history available yet.") | |
return | |
# Convert to DataFrame for better display | |
df_data = [] | |
for record in history: | |
df_data.append({ | |
"ID": record["id"], | |
"Original Text": record["original_text"][:50] + "..." if len(record["original_text"]) > 50 else record["original_text"], | |
"Translated Text": record["translated_text"][:50] + "..." if len(record["translated_text"]) > 50 else record["translated_text"], | |
"Source β Target": f"{record['source_language']} β {record['target_language']}", | |
"Confidence": f"{record['model_confidence']:.2%}", | |
"Created": record["created_at"][:19], | |
"Corrected": "β " if record["corrected_text"] else "β" | |
}) | |
df = pd.DataFrame(df_data) | |
# Display filters | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
source_filter = st.selectbox( | |
"Filter by Source Language", | |
options=["All"] + list(SUPPORTED_LANGUAGES.keys()), | |
format_func=lambda x: "All Languages" if x == "All" else f"{SUPPORTED_LANGUAGES.get(x, x)} ({x})" | |
) | |
with col2: | |
target_filter = st.selectbox( | |
"Filter by Target Language", | |
options=["All"] + list(SUPPORTED_LANGUAGES.keys()), | |
format_func=lambda x: "All Languages" if x == "All" else f"{SUPPORTED_LANGUAGES.get(x, x)} ({x})" | |
) | |
with col3: | |
correction_filter = st.selectbox( | |
"Filter by Correction Status", | |
options=["All", "Corrected", "Not Corrected"] | |
) | |
# Apply filters (simplified for display) | |
filtered_df = df.copy() | |
st.dataframe(filtered_df, use_container_width=True) | |
# Download option | |
csv = filtered_df.to_csv(index=False) | |
st.download_button( | |
"π₯ Download CSV", | |
csv, | |
"translation_history.csv", | |
"text/csv", | |
key='download-csv' | |
) | |
def analytics_page(): | |
"""Analytics and statistics page""" | |
st.header("π Analytics & Statistics") | |
# Fetch statistics from API (mock for now) | |
col1, col2, col3, col4 = st.columns(4) | |
with col1: | |
st.metric("Total Translations", "1,234", "+12%") | |
with col2: | |
st.metric("Corrections Submitted", "89", "+5%") | |
with col3: | |
st.metric("Languages Supported", len(SUPPORTED_LANGUAGES)) | |
with col4: | |
st.metric("Avg. Confidence", "92.5%", "+2.1%") | |
# Language pair popularity chart | |
st.subheader("π Popular Language Pairs") | |
# Mock data for demonstration | |
language_pairs_data = { | |
"Language Pair": ["Hindi β English", "Tamil β English", "Bengali β Hindi", "English β Hindi", "Gujarati β English"], | |
"Translation Count": [450, 280, 220, 180, 140] | |
} | |
df_pairs = pd.DataFrame(language_pairs_data) | |
st.bar_chart(df_pairs.set_index("Language Pair")) | |
# Daily translation trend | |
st.subheader("π Daily Translation Trend") | |
# Mock time series data | |
dates = pd.date_range(start="2025-01-18", end="2025-01-25", freq="D") | |
translations_per_day = [45, 52, 38, 61, 47, 55, 49, 58] | |
df_trend = pd.DataFrame({ | |
"Date": dates, | |
"Translations": translations_per_day | |
}) | |
st.line_chart(df_trend.set_index("Date")) | |
def settings_page(): | |
"""Settings and configuration page""" | |
st.header("βοΈ Settings") | |
# API Configuration | |
st.subheader("π§ API Configuration") | |
with st.form("api_settings"): | |
api_url = st.text_input("Backend API URL", value=API_BASE_URL) | |
st.markdown("**Model Settings:**") | |
model_type = st.selectbox( | |
"Translation Model", | |
options=["IndicTrans2-1B", "IndicTrans2-Distilled", "Mock (Development)"], | |
index=2 | |
) | |
confidence_threshold = st.slider( | |
"Minimum Confidence Threshold", | |
min_value=0.0, | |
max_value=1.0, | |
value=0.7, | |
step=0.05, | |
help="Translations below this confidence will be flagged for review" | |
) | |
if st.form_submit_button("πΎ Save Settings"): | |
st.success("β Settings saved successfully!") | |
# About section | |
st.subheader("βΉοΈ About") | |
st.markdown(""" | |
**Multi-Lingual Product Catalog Translator** is powered by: | |
- **IndicTrans2** by AI4Bharat - State-of-the-art neural machine translation for Indian languages | |
- **FastAPI** - High-performance web framework for the backend API | |
- **Streamlit** - Interactive web interface for user-friendly translation experience | |
- **SQLite** - Lightweight database for storing translations and corrections | |
This tool helps e-commerce sellers translate their product listings into multiple Indian languages, | |
enabling them to reach a broader customer base across different linguistic regions. | |
**Features:** | |
- β Automatic language detection | |
- β Support for 15+ Indian languages | |
- β Manual correction interface | |
- β Translation history and analytics | |
- β Batch translation capability | |
- β Feedback loop for continuous improvement | |
""") | |
# System info | |
with st.expander("π System Information"): | |
st.code(f""" | |
API Status: {'π’ Connected' if check_api_health() else 'π΄ Disconnected'} | |
Frontend: Streamlit {st.__version__} | |
Supported Languages: {len(SUPPORTED_LANGUAGES)} | |
""", language="text") | |
if __name__ == "__main__": | |
main() | |