multimodalart HF Staff commited on
Commit
8ca247c
·
verified ·
1 Parent(s): 99f75d6

Upload /tmp/hugging-demos-build-model_17slever17_translate-gemma-4-sub-e4b-uly2snze/app.py with huggingface_hub

Browse files
tmp/hugging-demos-build-model_17slever17_translate-gemma-4-sub-e4b-uly2snze/app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces # MUST come before any torch/CUDA-touching import
2
+ import torch
3
+ import gradio as gr
4
+
5
+ from transformers import AutoModelForImageTextToText, AutoTokenizer
6
+
7
+ MODEL_ID = "17slever17/translate-gemma-4-sub-e4b"
8
+
9
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
10
+ model = AutoModelForImageTextToText.from_pretrained(
11
+ MODEL_ID,
12
+ torch_dtype=torch.bfloat16,
13
+ ).to("cuda")
14
+ model.eval()
15
+
16
+ SUPPORTED_LANGUAGES = [
17
+ "English", "Russian", "Spanish", "German", "Japanese",
18
+ "French", "Portuguese", "Chinese", "Dutch", "Italian", "Korean",
19
+ ]
20
+
21
+ STYLES = ["neutral", "friendly", "official"]
22
+
23
+
24
+ def _build_system_message(source_lang: str, target_lang: str, rules: str, style: str) -> str:
25
+ """Build the system message exactly as specified in the model card."""
26
+ parts = [f"TASK: Translate {source_lang} subtitles into {target_lang}."]
27
+ if rules.strip():
28
+ parts.append(f"RULES: {rules.strip()}")
29
+ parts.append(f"STYLE: {style}.")
30
+ parts.append(
31
+ "Translate only CURRENT_SOURCE. PREVIOUS_SOURCE and PREVIOUS_TRANSLATION are context only. "
32
+ "Preserve meaning, tone, slang, profanity, uncertainty, repetitions and incomplete speech. "
33
+ "Return only the final translation without labels or commentary."
34
+ )
35
+ return "\n".join(parts)
36
+
37
+
38
+ def _build_user_message(prev_source: str, prev_translation: str, current_source: str) -> str:
39
+ """Build the user message following the model card's format."""
40
+ blocks = []
41
+ if prev_source.strip():
42
+ blocks.append(f"[PREVIOUS_SOURCE]\n{prev_source.strip()}")
43
+ if prev_translation.strip():
44
+ blocks.append(f"[PREVIOUS_TRANSLATION]\n{prev_translation.strip()}")
45
+ blocks.append(f"[CURRENT_SOURCE]\n{current_source.strip()}")
46
+ return "\n\n".join(blocks)
47
+
48
+
49
+ @spaces.GPU(duration=60)
50
+ def translate(
51
+ current_source: str,
52
+ source_language: str = "English",
53
+ target_language: str = "Russian",
54
+ previous_source: str = "",
55
+ previous_translation: str = "",
56
+ rules: str = "",
57
+ style: str = "friendly",
58
+ ) -> str:
59
+ """Translate a subtitle line using context-aware Gemma 4 Sub model.
60
+
61
+ Args:
62
+ current_source: The subtitle segment to translate.
63
+ source_language: Language of the source text.
64
+ target_language: Language to translate into.
65
+ previous_source: Previous source-language subtitles for context (optional).
66
+ previous_translation: Previous translated subtitles for context (optional).
67
+ rules: Additional rules (speaker name, gender, terminology, etc.) (optional).
68
+ style: Translation style — neutral, friendly, or official.
69
+ """
70
+ if not current_source.strip():
71
+ return "Please enter a subtitle line to translate."
72
+
73
+ system_msg = _build_system_message(source_language, target_language, rules, style)
74
+ user_msg = _build_user_message(previous_source, previous_translation, current_source)
75
+
76
+ messages = [
77
+ {"role": "system", "content": system_msg},
78
+ {"role": "user", "content": user_msg},
79
+ ]
80
+
81
+ inputs = tokenizer.apply_chat_template(
82
+ messages,
83
+ add_generation_prompt=True,
84
+ return_tensors="pt",
85
+ return_dict=True,
86
+ ).to("cuda")
87
+
88
+ with torch.inference_mode():
89
+ output = model.generate(
90
+ **inputs,
91
+ max_new_tokens=256,
92
+ do_sample=False,
93
+ )
94
+
95
+ generated_tokens = output[0, inputs["input_ids"].shape[1]:]
96
+ translation = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
97
+ return translation
98
+
99
+
100
+ CSS = """
101
+ #col-container { max-width: 900px; margin: 0 auto; }
102
+ .dark .gradio-container { color: var(--body-text-color); }
103
+ """
104
+
105
+ with gr.Blocks() as demo:
106
+ gr.Markdown(
107
+ "# 🌐 Translate Gemma 4 Sub — Context-Aware Subtitle Translation\n"
108
+ "A multilingual Gemma 4 fine-tune specialized for subtitle translation. "
109
+ "Provide previous source and translation context for natural, coherent translations."
110
+ )
111
+
112
+ with gr.Column(elem_id="col-container"):
113
+ with gr.Row():
114
+ source_language = gr.Dropdown(
115
+ label="Source Language",
116
+ choices=SUPPORTED_LANGUAGES,
117
+ value="English",
118
+ )
119
+ target_language = gr.Dropdown(
120
+ label="Target Language",
121
+ choices=SUPPORTED_LANGUAGES,
122
+ value="Russian",
123
+ )
124
+ style = gr.Dropdown(
125
+ label="Style",
126
+ choices=STYLES,
127
+ value="friendly",
128
+ )
129
+
130
+ current_source = gr.Textbox(
131
+ label="Current Source (to translate)",
132
+ placeholder="Yeah, well... I changed my mind.",
133
+ lines=2,
134
+ )
135
+
136
+ with gr.Accordion("Context & Rules (optional)", open=False):
137
+ previous_source = gr.Textbox(
138
+ label="Previous Source (context only)",
139
+ placeholder="I thought you said you weren't coming.",
140
+ lines=2,
141
+ )
142
+ previous_translation = gr.Textbox(
143
+ label="Previous Translation (context only)",
144
+ placeholder="Я думала, ты сказала, что не придёшь.",
145
+ lines=2,
146
+ )
147
+ rules = gr.Textbox(
148
+ label="Rules (speaker name, gender, terminology, etc.)",
149
+ placeholder="speaker gender: female",
150
+ lines=2,
151
+ )
152
+
153
+ run_btn = gr.Button("Translate", variant="primary")
154
+ output = gr.Textbox(
155
+ label="Translation",
156
+ lines=3,
157
+ interactive=False,
158
+ )
159
+
160
+ run_btn.click(
161
+ fn=translate,
162
+ inputs=[
163
+ current_source, source_language, target_language,
164
+ previous_source, previous_translation, rules, style,
165
+ ],
166
+ outputs=output,
167
+ api_name="translate",
168
+ )
169
+
170
+ gr.Examples(
171
+ examples=[
172
+ ["Yeah, well... I changed my mind.", "English", "Russian", "friendly"],
173
+ ["I thought you said you weren't coming.", "English", "Spanish", "neutral"],
174
+ ["Wait, hold on a second...", "English", "Japanese", "friendly"],
175
+ ["That's not what I meant at all.", "English", "German", "official"],
176
+ ["Could you repeat that, please?", "English", "French", "official"],
177
+ ],
178
+ inputs=[current_source, source_language, target_language, style],
179
+ outputs=output,
180
+ fn=translate,
181
+ cache_examples=True,
182
+ cache_mode="lazy",
183
+ )
184
+
185
+ if __name__ == "__main__":
186
+ demo.launch(theme=gr.themes.Citrus(), css=CSS, mcp_server=True)