|
|
""" |
|
|
Gradio web interface demo for Aphra translation system. |
|
|
|
|
|
This module provides a user-friendly web interface for the Aphra translation |
|
|
system using Gradio, allowing users to configure models and translate text |
|
|
through a browser interface. |
|
|
""" |
|
|
import os |
|
|
import tempfile |
|
|
import gradio as gr |
|
|
import toml |
|
|
import requests |
|
|
import logging |
|
|
|
|
|
from aphra import translate |
|
|
|
|
|
OPENROUTER_MODELS_URL="https://openrouter.ai/api/v1/models" |
|
|
|
|
|
theme = gr.themes.Soft( |
|
|
primary_hue="rose", |
|
|
secondary_hue="pink", |
|
|
spacing_size="lg", |
|
|
) |
|
|
|
|
|
def fetch_openrouter_models(): |
|
|
""" |
|
|
Fetch available models from OpenRouter API. |
|
|
Returns a list of model IDs (names). |
|
|
""" |
|
|
try: |
|
|
response = requests.get(OPENROUTER_MODELS_URL, timeout=10) |
|
|
response.raise_for_status() |
|
|
data = response.json() |
|
|
|
|
|
|
|
|
models = [model['id'] for model in data.get('data', [])] |
|
|
return sorted(models) |
|
|
except requests.RequestException as e: |
|
|
logging.warning(f"Failed to fetch models from OpenRouter: {e}") |
|
|
|
|
|
return [ |
|
|
"anthropic/claude-sonnet-4", |
|
|
"perplexity/sonar" |
|
|
] |
|
|
|
|
|
def get_default_models(): |
|
|
"""Get default model selections for different roles.""" |
|
|
models = fetch_openrouter_models() |
|
|
|
|
|
|
|
|
writer_default = "anthropic/claude-sonnet-4" |
|
|
searcher_default = "perplexity/sonar" |
|
|
critic_default = "anthropic/claude-sonnet-4" |
|
|
|
|
|
|
|
|
if writer_default not in models and models: |
|
|
writer_default = models[0] |
|
|
if searcher_default not in models and models: |
|
|
searcher_default = models[0] |
|
|
if critic_default not in models and models: |
|
|
critic_default = models[0] |
|
|
|
|
|
return models, writer_default, searcher_default, critic_default |
|
|
|
|
|
def create_config_file(api_key, writer_model, searcher_model, critic_model): |
|
|
""" |
|
|
Create a temporary TOML configuration file for Aphra. |
|
|
|
|
|
Args: |
|
|
api_key: OpenRouter API key |
|
|
writer_model: Model to use for writing/translation |
|
|
searcher_model: Model to use for searching/research |
|
|
critic_model: Model to use for criticism/review |
|
|
|
|
|
Returns: |
|
|
str: Path to the temporary configuration file |
|
|
""" |
|
|
config = { |
|
|
"openrouter": {"api_key": api_key}, |
|
|
"short_article": { |
|
|
"writer": writer_model, |
|
|
"searcher": searcher_model, |
|
|
"critiquer": critic_model |
|
|
} |
|
|
} |
|
|
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.toml') as tmp: |
|
|
toml.dump(config, tmp) |
|
|
return tmp.name |
|
|
|
|
|
def process_input(file, text_input, api_key, writer_model, searcher_model, critic_model, source_lang, target_lang): |
|
|
""" |
|
|
Process translation input from either file or text input. |
|
|
|
|
|
Args: |
|
|
file: Uploaded file object (if any) |
|
|
text_input: Direct text input string |
|
|
api_key: OpenRouter API key |
|
|
writer_model: Model for writing/translation |
|
|
searcher_model: Model for searching/research |
|
|
critic_model: Model for criticism/review |
|
|
source_lang: Source language for translation |
|
|
target_lang: Target language for translation |
|
|
|
|
|
Returns: |
|
|
str: Translated text |
|
|
""" |
|
|
if file is not None: |
|
|
with open(file, 'r', encoding='utf-8') as file: |
|
|
text = file.read() |
|
|
else: |
|
|
text = text_input |
|
|
config_file = create_config_file(api_key, writer_model, searcher_model, critic_model) |
|
|
try: |
|
|
translation = translate( |
|
|
source_language=source_lang, |
|
|
target_language=target_lang, |
|
|
text=text, |
|
|
config_file=config_file, |
|
|
log_calls=False |
|
|
) |
|
|
finally: |
|
|
os.unlink(config_file) |
|
|
|
|
|
return translation |
|
|
|
|
|
def create_interface(): |
|
|
""" |
|
|
Create and configure the Gradio web interface. |
|
|
|
|
|
Returns: |
|
|
gr.Blocks: Configured Gradio interface |
|
|
""" |
|
|
|
|
|
models, writer_default, searcher_default, critic_default = get_default_models() |
|
|
|
|
|
with gr.Blocks(theme=theme) as demo: |
|
|
gr.Markdown("<font size=6.5><center>ππ¬ Aphra</center></font>") |
|
|
gr.Markdown( |
|
|
"""<div style="display: flex;align-items: center;justify-content: center"> |
|
|
[<a href="https://davidlms.github.io/aphra/">Project Page</a>] | [<a href="https://github.com/DavidLMS/aphra">Github</a>]</div> |
|
|
""" |
|
|
) |
|
|
gr.Markdown("ππ¬ Aphra is an open-source translation agent with a workflow architecture designed to enhance the quality of text translations by leveraging large language models (LLMs).") |
|
|
|
|
|
with gr.Row(): |
|
|
api_key = gr.Textbox(label="OpenRouter API Key", type="password") |
|
|
|
|
|
writer_model = gr.Dropdown( |
|
|
models, |
|
|
label="Writer Model", |
|
|
value=writer_default, |
|
|
allow_custom_value=True |
|
|
) |
|
|
searcher_model = gr.Dropdown( |
|
|
models, |
|
|
label="Searcher Model", |
|
|
value=searcher_default, |
|
|
allow_custom_value=True |
|
|
) |
|
|
critic_model = gr.Dropdown( |
|
|
models, |
|
|
label="Critic Model", |
|
|
value=critic_default, |
|
|
allow_custom_value=True |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
source_lang = gr.Dropdown( |
|
|
["Spanish", "English", "French", "German"], |
|
|
label="Source Language", |
|
|
value="Spanish", |
|
|
allow_custom_value=True |
|
|
) |
|
|
target_lang = gr.Dropdown( |
|
|
["English", "Spanish", "French", "German"], |
|
|
label="Target Language", |
|
|
value="English", |
|
|
allow_custom_value=True |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
file = gr.File(label="Upload .txt or .md file", file_types=[".txt", ".md"]) |
|
|
text_input = gr.Textbox(label="Or paste your text here", lines=5) |
|
|
|
|
|
translate_btn = gr.Button("Translate with ππ¬ Aphra") |
|
|
|
|
|
output = gr.Textbox(label="Translation by ππ¬ Aphra") |
|
|
|
|
|
translate_btn.click( |
|
|
process_input, |
|
|
inputs=[file, text_input, api_key, writer_model, searcher_model, critic_model, source_lang, target_lang], |
|
|
outputs=[output] |
|
|
) |
|
|
|
|
|
return demo |
|
|
|
|
|
if __name__ == "__main__": |
|
|
interface = create_interface() |
|
|
interface.launch() |
|
|
|