Download app.py from Sandroeth/cali: direct link, hf CLI and curl.
- Browser
- Download file 7.06 kB
-
https://huggingface.co/spaces/Sandroeth/cali/resolve/main/app.py
- Command line
-
hf download hf://spaces/Sandroeth/cali/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Sandroeth/cali/resolve/main/app.py
7.06 kB
| import spaces | |
| import re | |
| import time | |
| import gradio as gr | |
| import torch | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| REPOS = { | |
| "translate": ("Sandroeth/cali-id-en-translate", "472c3e80063867ef775fb41d058b9ffec13f44bd"), | |
| "base": ("Sandroeth/cali-0.1B", "c9de368e7e62184e2a70e76f4b3cedcfa170b73a"), | |
| } | |
| DEVICE = "cuda" if torch.cuda.is_available() else "cpu" | |
| MODELS = {} | |
| for key, (repo, revision) in REPOS.items(): | |
| tokenizer = AutoTokenizer.from_pretrained(repo, revision=revision, trust_remote_code=True) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| repo, revision=revision, trust_remote_code=True, dtype=torch.float32, | |
| ).to(DEVICE).eval() | |
| MODELS[key] = (tokenizer, model) | |
| print(f"Loaded {repo}@{revision} on {DEVICE}, dtype={model.dtype}", flush=True) | |
| def run_model(key: str, prompt: str, max_new_tokens: int, **options) -> tuple[str, str]: | |
| tokenizer, model = MODELS[key] | |
| inputs = tokenizer(prompt, return_tensors="pt", return_token_type_ids=False).to(DEVICE) | |
| input_length = inputs["input_ids"].shape[1] | |
| if input_length + max_new_tokens > model.config.seq_len: | |
| raise gr.Error("Text is too long. Shorten the input or reduce the output limit (1024 tokens total).") | |
| start = time.perf_counter() | |
| with torch.inference_mode(): | |
| output = model.generate( | |
| **inputs, max_new_tokens=max_new_tokens, use_cache=False, | |
| pad_token_id=tokenizer.eos_token_id, **options, | |
| ) | |
| generated = output[0][input_length:] | |
| text = tokenizer.decode(generated, skip_special_tokens=True).strip() | |
| elapsed = time.perf_counter() - start | |
| print(f"{key}: input={input_length}, output={len(generated)}, seconds={elapsed:.2f}", flush=True) | |
| return text, f"{input_length} input tokens · {len(generated)} output tokens · {elapsed:.2f} seconds" | |
| def translate(text: str, direction: str = "Indonesian → English", max_new_tokens: int = 64, | |
| first_sentence: bool = True) -> tuple[str, str]: | |
| """Translate a short sentence between Indonesian and English using CALI's trained prompt format.""" | |
| if not text or not text.strip(): | |
| raise gr.Error("Enter the text you want to translate.") | |
| if direction not in ("Indonesian → English", "English → Indonesian"): | |
| raise gr.Error("Invalid translation direction.") | |
| max_new_tokens = int(max_new_tokens) | |
| if not 16 <= max_new_tokens <= 256: | |
| raise gr.Error("Choose between 16 and 256 output tokens.") | |
| if len(text.split()) > 200: | |
| raise gr.Error("Use up to 200 words; this model is designed for short texts.") | |
| tag = "[id→en]" if direction == "Indonesian → English" else "[en→id]" | |
| result, stats = run_model("translate", f"{tag}\n{text.strip()}\n→", max_new_tokens, | |
| do_sample=False, repetition_penalty=1.5, no_repeat_ngram_size=3) | |
| if first_sentence: | |
| result = re.split(r"(?<=[.!?])\s+", result)[0] | |
| return result, stats | |
| def complete(prompt: str, max_new_tokens: int = 96, temperature: float = 0.7, | |
| top_p: float = 0.9) -> tuple[str, str]: | |
| """Continue an Indonesian or English text prompt with the experimental CALI base language model.""" | |
| if not prompt or not prompt.strip(): | |
| raise gr.Error("Enter a text prompt to continue.") | |
| max_new_tokens = int(max_new_tokens) | |
| if not 16 <= max_new_tokens <= 256 or not 0 <= temperature <= 1.5 or not 0.1 <= top_p <= 1: | |
| raise gr.Error("Generation settings are outside the supported range.") | |
| options = {"do_sample": temperature > 0, "repetition_penalty": 1.1} | |
| if temperature > 0: | |
| options.update(temperature=float(temperature), top_p=float(top_p)) | |
| return run_model("base", prompt, max_new_tokens, **options) | |
| with gr.Blocks(title="cali") as demo: | |
| gr.Markdown("# cali\nTwo lightweight models by **Sandroeth** for exploring Indonesian and English.") | |
| with gr.Tab("Translation"): | |
| gr.Markdown("### From one language to another\nBest for everyday sentences. Very short inputs (1–2 words), technical terms, and long passages may produce less accurate translations.") | |
| direction = gr.Radio(["Indonesian → English", "English → Indonesian"], value="Indonesian → English", label="Translation direction") | |
| with gr.Row(): | |
| source = gr.Textbox(label="Source text", lines=5, placeholder="Dia pergi ke pasar setiap pagi.", max_length=6000) | |
| translated = gr.Textbox(label="Translation", lines=5, interactive=False) | |
| with gr.Accordion("Settings", open=False): | |
| tokens = gr.Slider(16, 256, value=64, step=1, label="Maximum output tokens") | |
| first = gr.Checkbox(value=True, label="Return the first sentence only (matches the official example)") | |
| translate_button = gr.Button("Translate", variant="primary") | |
| translation_stats = gr.Textbox(label="Stats", interactive=False) | |
| translate_button.click(translate, [source, direction, tokens, first], [translated, translation_stats], api_name="translate") | |
| gr.Examples([ | |
| ["Dia pergi ke pasar setiap pagi.", "Indonesian → English"], | |
| ["Saya makan nasi.", "Indonesian → English"], | |
| ["The weather is very cold today.", "English → Indonesian"], | |
| ["She is happy.", "English → Indonesian"], | |
| ], inputs=[source, direction], outputs=[translated, translation_stats], fn=translate, | |
| cache_examples=True, cache_mode="lazy") | |
| with gr.Tab("Explore CALI"): | |
| gr.Markdown("### Continue a piece of text\nCALI-0.1B is an experimental base model. Start a sentence or paragraph and let it continue. Outputs may repeat or become inconsistent.") | |
| prompt = gr.Textbox(label="Prompt", lines=4, placeholder="Indonesia adalah negara yang") | |
| continuation = gr.Textbox(label="Generated continuation", lines=6, interactive=False) | |
| with gr.Accordion("Settings", open=False): | |
| base_tokens = gr.Slider(16, 256, value=96, step=1, label="Maximum output tokens") | |
| temperature = gr.Slider(0, 1.5, value=0.7, step=0.05, label="Temperature (0 = deterministic)") | |
| top_p = gr.Slider(0.1, 1, value=0.9, step=0.05, label="Top-p") | |
| generate_button = gr.Button("Generate continuation", variant="primary") | |
| base_stats = gr.Textbox(label="Stats", interactive=False) | |
| generate_button.click(complete, [prompt, base_tokens, temperature, top_p], [continuation, base_stats], api_name="complete") | |
| gr.Examples([["Indonesia adalah negara yang"], ["The sun rises in the"]], | |
| inputs=[prompt], outputs=[continuation, base_stats], fn=complete, | |
| cache_examples=True, cache_mode="lazy") | |
| gr.Markdown("Model: [CALI Translate](https://huggingface.co/Sandroeth/cali-id-en-translate) · [CALI-0.1B](https://huggingface.co/Sandroeth/cali-0.1B) · Apache 2.0 license") | |
| if __name__ == "__main__": | |
| demo.queue(max_size=20, default_concurrency_limit=1).launch(mcp_server=True) | |