BableSlide_1.0 / app.py
Marek4321's picture
Update app.py
f875b20 verified
import os
import json
from pptx import Presentation
import gradio as gr
from openai import OpenAI
import queue
from datetime import datetime
import time
# Configuration for different API providers
API_PROVIDERS = {
"DeepSeek": "https://api.deepseek.com",
"ChatGPT": "https://api.openai.com/v1",
"Mistral": "https://api.mistral.ai/v1"
}
# List of supported languages
LANGUAGES = {
"Arabic": "ar",
"Chinese (Simplified)": "zh",
"Chinese (Traditional)": "zh-TW",
"Dutch": "nl",
"English": "en",
"French": "fr",
"German": "de",
"Greek": "el",
"Hindi": "hi",
"Indonesian": "id",
"Italian": "it",
"Japanese": "ja",
"Korean": "ko",
"Polish": "pl",
"Portuguese": "pt",
"Russian": "ru",
"Spanish": "es",
"Swedish": "sv",
"Thai": "th",
"Turkish": "tr",
"Vietnamese": "vi"
}
class TranslatorApp:
def __init__(self):
self.log_queue = queue.Queue()
self.processing = False
self.process_thread = None
def load_config(self):
try:
with open('config.json', 'r') as f:
return json.load(f)
except:
return {}
def save_config(self, api_provider, api_key, source_lang, target_lang):
config = {
'api_provider': api_provider,
'api_key': api_key,
'source_lang': source_lang,
'target_lang': target_lang
}
with open('config.json', 'w') as f:
json.dump(config, f)
def translate_text(self, text, source_lang, target_lang, api_provider, api_key):
if not api_key:
raise ValueError("API key is required")
translation_methods = {
"DeepSeek": self.translate_with_deepseek,
"ChatGPT": self.translate_with_chatgpt,
"Mistral": self.translate_with_mistral
}
translate_method = translation_methods.get(api_provider)
if not translate_method:
raise ValueError(f"Unsupported API provider: {api_provider}")
return translate_method(text, source_lang, target_lang, api_key)
def translate_with_deepseek(self, text, source_lang, target_lang, api_key):
client = OpenAI(api_key=api_key, base_url=API_PROVIDERS["DeepSeek"])
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": f"Translate from {source_lang} to {target_lang}:"},
{"role": "user", "content": text},
]
)
return response.choices[0].message.content
def translate_with_chatgpt(self, text, source_lang, target_lang, api_key):
client = OpenAI(api_key=api_key)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Translate from {source_lang} to {target_lang}:"},
{"role": "user", "content": text},
]
)
return response.choices[0].message.content
def translate_with_mistral(self, text, source_lang, target_lang, api_key):
client = OpenAI(api_key=api_key, base_url=API_PROVIDERS["Mistral"])
response = client.chat.completions.create(
model="mistral-tiny",
messages=[
{"role": "system", "content": f"Translate from {source_lang} to {target_lang}:"},
{"role": "user", "content": text},
]
)
return response.choices[0].message.content
def generate_review(self, translated_text, source_lang, api_provider, api_key):
try:
self.log("Generating review...")
client = OpenAI(api_key=api_key, base_url=API_PROVIDERS[api_provider])
system_prompt = f"""Generate a comprehensive review in {source_lang} covering:
1. Main themes and key points
2. Translation quality assessment
3. Coherence and flow
4. Technical terminology accuracy
5. Recommendations for improvement"""
model = {
"DeepSeek": "deepseek-chat",
"ChatGPT": "gpt-4o",
"Mistral": "mistral-tiny"
}.get(api_provider, "gpt-4o")
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": translated_text},
]
)
return response.choices[0].message.content
except Exception as e:
self.log(f"Error generating review: {str(e)}")
return "Failed to generate review."
def log(self, message):
self.log_queue.put(message)
def process_pptx(self, file_path, source_lang, target_lang, api_provider, api_key, progress=gr.Progress()):
try:
prs = Presentation(file_path)
total_slides = len(prs.slides)
all_translated_text = ""
start_time = time.time()
for i, slide in enumerate(prs.slides):
if not self.processing:
self.log("Process interrupted by user")
return
self.log(f"Processing slide {i+1}/{total_slides}")
for shape in slide.shapes:
if hasattr(shape, "text") and shape.text.strip():
translated_text = self.translate_text(shape.text, source_lang, target_lang, api_provider, api_key)
shape.text = translated_text
all_translated_text += translated_text + "\n"
# Update progress
progress((i + 1) / total_slides, desc=f"Processing slide {i + 1}/{total_slides}")
if self.processing:
output_path = os.path.join(os.path.dirname(file_path), f"translated_{os.path.basename(file_path)}")
prs.save(output_path)
self.log(f"Saved translated file: {output_path}")
# Generate and save review
review = self.generate_review(all_translated_text, source_lang, api_provider, api_key)
review_path = output_path.replace(".pptx", "_review.txt")
with open(review_path, "w", encoding="utf-8") as f:
f.write(review)
self.log(f"Generated and saved review: {review_path}")
return output_path, review_path
except Exception as e:
self.log(f"Error during processing: {str(e)}")
raise e
def run(self, file, api_provider, api_key, source_lang, target_lang):
self.processing = True
self.save_config(api_provider, api_key, source_lang, target_lang)
try:
output_path, review_path = self.process_pptx(file.name, source_lang, target_lang, api_provider, api_key)
return [
f"File has been translated and saved as:\n{output_path}\nReview saved as:\n{review_path}",
output_path,
review_path
]
except Exception as e:
return [f"An error occurred during processing: {str(e)}", None, None]
finally:
self.processing = False
# Custom CSS for styling
custom_css = """
/* Style for the Translate button */
button {
background-color: orange !important;
color: white !important;
border: none !important;
}
/* Style for the Upload PowerPoint file input */
.upload-area {
border: 2px solid orange !important;
padding: 10px !important;
border-radius: 5px !important;
}
/* Adjust height of download file components */
.download-box {
height: 70px !important;
}
"""
def create_interface():
app = TranslatorApp()
with gr.Blocks(css=custom_css) as interface:
gr.Markdown("# BabelSlide by Heuristica")
gr.Markdown("Translate PowerPoint presentations using various AI models.")
with gr.Row():
file_input = gr.File(label="Upload PowerPoint File", elem_classes="upload-area")
api_provider = gr.Dropdown(label="API Provider", choices=list(API_PROVIDERS.keys()))
api_key = gr.Textbox(label="API Key", type="password")
source_lang = gr.Dropdown(label="Source Language", choices=list(LANGUAGES.keys()))
target_lang = gr.Dropdown(label="Target Language", choices=list(LANGUAGES.keys()))
progress_bar = gr.Progress()
output_text = gr.Textbox(label="Output", interactive=False)
output_file = gr.File(label="Download Translated PowerPoint", elem_classes="download-box")
output_review = gr.File(label="Download Review", elem_classes="download-box")
run_button = gr.Button("Translate")
run_button.click(
fn=app.run,
inputs=[file_input, api_provider, api_key, source_lang, target_lang],
outputs=[output_text, output_file, output_review]
)
return interface
if __name__ == "__main__":
interface = create_interface()
interface.launch()