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() |