Spaces:
Configuration error
Configuration error
| from fasthtml.common import * | |
| from fasthtml.xtend import CheckboxX | |
| from translator import languages as VALID_LANGUAGES, translate_to_languages | |
| import tempfile | |
| from starlette.requests import Request | |
| from typing import List | |
| from starlette.responses import FileResponse, PlainTextResponse | |
| import os | |
| import mimetypes | |
| import zipfile | |
| import io | |
| css = Style(':root {--pico-font-size:90%,--pico-font-family: Pacifico, cursive;}') | |
| app = FastHTML(hdrs=(picolink, css)) | |
| TEMP_FILES = {} | |
| # Extract form generation to a separate function | |
| def generate_language_form(): | |
| return Form( | |
| Input(type='file', name='sbv_file', accept='.sbv', required=True), | |
| H3('Select languages for translation'), | |
| Fieldset( | |
| Legend("Languages"), | |
| Div( | |
| *[CheckboxX( | |
| label=lang, | |
| value=lang, | |
| id=f'lang_{lang}', | |
| name='languages' | |
| ) for lang in VALID_LANGUAGES], | |
| class_='grid' | |
| ) | |
| ), | |
| Button('Translate', class_="primary"), | |
| action="/upload", method='post', enctype='multipart/form-data' | |
| ) | |
| def home(): | |
| return Container( | |
| Article( | |
| H1("SBV File Translator"), | |
| P("Upload an SBV File and select languages for translation:"), | |
| generate_language_form(), | |
| ) | |
| ) | |
| # Extract file processing logic to a separate function | |
| def translate_and_process_sbv(content: bytes, filename: str, languages: List[str]) -> dict: | |
| """ | |
| Translate and process an SBV file for the given languages. | |
| Args: | |
| content (bytes): The content of the uploaded SBV file. | |
| filename (str): The name of the uploaded file. | |
| languages (List[str]): List of target languages for translation. | |
| Returns: | |
| dict: A dictionary containing translation results, file paths, and zip filename. | |
| """ | |
| try: | |
| temp_dir = tempfile.mkdtemp() | |
| input_file = os.path.join(temp_dir, filename) | |
| # Ensure the directory exists | |
| os.makedirs(os.path.dirname(input_file), exist_ok=True) | |
| with open(input_file, 'wb') as f: | |
| f.write(content) | |
| selected_languages = [lang for lang in languages if lang in VALID_LANGUAGES] | |
| output_dir = os.path.join(temp_dir, "translations") | |
| os.makedirs(output_dir, exist_ok=True) | |
| translate_to_languages(input_file, output_dir, selected_languages) | |
| return create_translation_files(temp_dir, output_dir, filename, selected_languages) | |
| except Exception as e: | |
| print(f"Error in translate_and_process_sbv: {str(e)}") | |
| raise # Re-raise the exception after logging | |
| # Extract translation file creation logic to a separate function | |
| def create_translation_files(temp_dir: str, output_dir: str, filename: str, languages: List[str]) -> dict: | |
| """ | |
| Create translation files and organize them for download. | |
| This function processes the translated SBV files, organizes them in a temporary directory, | |
| creates a zip file containing all translations, and prepares the data for the response. | |
| Args: | |
| temp_dir (str): Path to the temporary directory for storing files. | |
| output_dir (str): Path to the directory containing the translated SBV files. | |
| filename (str): Name of the original uploaded file. | |
| languages (List[str]): List of languages for which translations were created. | |
| Returns: | |
| dict: A dictionary containing: | |
| - 'translations': Dict of language codes to translated content. | |
| - 'file_paths': Dict of language codes to paths of individual translation files. | |
| - 'zip_filename': Name of the zip file containing all translations. | |
| """ | |
| translations = {} | |
| file_paths = {} | |
| base_filename = os.path.splitext(filename)[0] | |
| for lang in languages: | |
| translated_file = os.path.join(output_dir, f"{base_filename}_{lang}.sbv") | |
| with open(translated_file, 'r', encoding='utf-8') as f: | |
| translations[lang] = f.read() | |
| new_filename = f"{base_filename}_{lang}.sbv" | |
| new_path = os.path.join(temp_dir, new_filename) | |
| os.rename(translated_file, new_path) | |
| file_paths[lang] = new_path | |
| TEMP_FILES[new_filename] = new_path | |
| zip_filename = f"{base_filename}_{'_'.join(languages)}.zip" | |
| zip_path = os.path.join(temp_dir, zip_filename) | |
| with zipfile.ZipFile(zip_path, 'w') as zip_file: | |
| for lang, file_path in file_paths.items(): | |
| zip_file.write(file_path, os.path.basename(file_path)) | |
| TEMP_FILES[zip_filename] = zip_path | |
| return { | |
| 'translations': translations, | |
| 'file_paths': file_paths, | |
| 'zip_filename': zip_filename | |
| } | |
| async def upload_file(request: Request, sbv_file: UploadFile): | |
| content = await sbv_file.read() | |
| # Get form data | |
| form = await request.form() | |
| languages = form.getlist('languages') | |
| # Ensure languages is always a list | |
| if not languages: | |
| return PlainTextResponse("Please select at least one language for translation.", status_code=400) | |
| result = translate_and_process_sbv(content, sbv_file.filename, languages) | |
| return Container( | |
| Article( | |
| H1('Translations'), | |
| A("Download All Translations", | |
| href=f"/download/{result['zip_filename']}", | |
| download=True, | |
| class_="primary", | |
| role="button" | |
| ), | |
| *[Card( | |
| H3(f'{lang.capitalize()} Translation'), | |
| Pre( | |
| '\n'.join(result['translations'][lang].split('\n')[:9]) + '\n...', | |
| ), | |
| Footer( | |
| A(f"Download {lang.capitalize()} Translation", | |
| href=f"/download/{os.path.basename(result['file_paths'][lang])}", | |
| download=True, | |
| class_="secondary outline", | |
| role="button" | |
| ) | |
| ) | |
| ) for lang in result['translations']], | |
| class_="container-fluid" # Add this class for full-width content | |
| ) | |
| ) | |
| def get(filename: str): | |
| file_path = TEMP_FILES.get(filename) | |
| if file_path and os.path.exists(file_path): | |
| mime_type, _ = mimetypes.guess_type(file_path) | |
| return FileResponse( | |
| file_path, | |
| filename=filename, | |
| media_type=mime_type or "application/octet-stream", | |
| headers={ | |
| "Content-Disposition": f"attachment; filename={filename}", | |
| "X-Content-Type-Options": "nosniff", | |
| } | |
| ) | |
| else: | |
| return PlainTextResponse("File not found", status_code=404) | |
| serve() |