Jak na ChatGPT API pro překlad z a do češtiny. Můžete tím snadno nahradit DeepL 💎
Výsledný skript (je na konci tipu) je ale použitelný i na cokoliv dalšího se zvoleným workflow. Dlouhé a podrobné čtení o tom jak na to. A stále zkouším nové věci, tedy "placený" obsah. Tak trochu.
Tento příspěvek je bonus pro platící odběratele newsletteru 365tipů. Extra obsah můžete mít za 5 USD měsíčně, 50 USD ročně. Za 14 dní od vydání se tento tip odemkne.
Zachtělo se mi přestat platit za DeepL a místo toho překládat ty krátké štěky do newsletterů s pomocí ChatGPT. Ale nutná podmínka byla překlad s klávesovou zkratkou. Na což DeepL měla aplikaci, ale tu si já psát nechci (a ani neumím).
Náhrada je přitom poměrně snadná - ChatGPT. Jenže to v běžné podobě (aplikace nebo web) neumí horkou klávesu (jen vyvolání aplikace jako takové), musíte zkopírovat text do ChatGPT, nechat přeložit, zkopírovat zpět kam patří.
Efektivnější to je když si pořídíte ChatGPT API (platí se za objemy a odděleně od vašeho případného běžného účtu) a trochu to zkombinujete s věcmi jako RayCast (snadná klávesová zkratka, ale jde to i přímo v MacOS) a skriptem v Pythonu. Ten můžete ostatně použít i ve Windows či Linuxu, jen si tam něčím jiný vyřešit klávesovou zkratku, možností je víc (stejně tak jako v MacOS je možností víc).
Chytrý překlad skrz schránku
Na klávesovou zkratku mám pověšené vyvolání skriptu který
načte obsah schránky (clipboardu)
zavolá ChatGPT API a pokud je to česky, přeloží do angličtiny. Pokud není česky, přeloží do češtiny (což rozhodne ChatGPT)
výsledek vloží do schránky
pípne jednou když úspěch, pípne třikrát když došlo k chybě
Původně jsem chtěl aby stačilo jenom označit blok k překladu, stisknout a po návratu by to blok přepsalo. Což jde - skript může sám poslat Ctrl/Cmd+C (Copy) a při návratu Ctrl/Cmd+V (Paste). Ale na MacOS tohle poslání klávesy v Pythonu je dost hodně pomalé, takže nakonec to řeším čistě skrz schránku. Jde jen o úpravu mého worklow.
Poznámka: Workflow vlastně je … označit blok, Ctrl/Cmd+C, moje zkratka, Ctrl/Cmd+V. Což se dá později v něčem jako Karabiner Elements sloučit do jedné klávesové zkratky tak jako tak.
Na MacOS musíte mít nainstalovany Python (ten tam ale už je) a v něm případně doinstalované nějaké další funkčnosti, ale pro tenhle základ myslím že nic extra třeba nebylo. A také mít RayCast, ale skript můžete vyvolávat i jinak - Keyboard Maestro nebo uplně klasicky přes Automator/Shortcuts.
Výhoda řešení přes schránku je, že ten skript můžete spouštět i v Terminalu (protože vstup i výstup je ve schránce) - a bude se to sakra hodit při ladění, když to bude házet chyby. Přes RayCast ho totiž spustít “na pozadí” a nevidíte jestli nehází nějaké chyby.
Čistě prakticky není nutný Python - můžete to pustit v Node, nebo v terminalu (Bash), ale já už Python používám na víc věcí a umím ho.
Neumíte programovat? Nevadí
Ano, umím ho, ale nebyl moc důvod si to psát ručně. Pustil jsem ChatGPT a vysvětlil ji co chci, ona během dvou sekund vrátil funkční skript pro Python a požadovaný překlad.
Ještě jsem ji řekl ať doplní “error handling”, ted že chci aby to píplo při úspěchu a třikrát při neúspěchu.
Pak jsem s ní ještě chvíli řešil vhodný prompt, tak aby opravdu jenom překládal a uměl poznat co je na vstupu a byl zároveň co nejkratší (protože délka stojí peníze). Včetně testování na různých anglických i českých textech i srovnávání s DeepL. A ano, rozumíte tomu správně, ChatGPT umí skvělé navrhovat prompty pro sebe sama.
Součástí toho skriptu bude muset být API key, ale správně by tam být neměl - já ho sice přidal do proměnné (v ~/.zshrc), ale RayCast to spouští tak, že tohle vesele ignoruje. Takže než to doladím, tak je zatím prostě v tom skriptu. Ale to není ideální.
Chvíli jsem to pak testoval, včetně oné varianty že si to samo “mačká” Cop/Paste, ale to přidalo tak sekundu na běh a vadilo to. A také jakou verzi GPT použít, protože i od toho se odvíjí rychlost a (hlavně) cena (GPT 5 je prostě drahá. GPT 5 mini je levnější, GPT 4o ještě levnější). Je nutné najít rovnováhu mezi cenou a kvalitou výstupu. Ale DeepL měla záplavu much taky, takže když budou tady, nevadí to. Stejně je dobré to kontrolovat.
POZNÁMKA: Na to aby to samo umělo copy/paste je navíc nutné tomu povolit v Přístupnosti v Nastavení. Na MacOS je všechno neustále problém, protože Apple.
Pokud by v Pythonu chyběly nějaké balíčky, tak si je musíte přidat (pip3 install nebo přes python3 -m pip install). A právě tady se hodí, že ty skripty můžete spustit v terminalu a vidět chybové hlášky.
Až budete s tím Pythonem zápasit, tak si dejte velký pozor na to, aby v první řádce fakt byl skutečně a pořád “shebang”, tedy #!/usr/bin/env python3 - jednou se mi tam povedlo vytvořit omylem první řádku prázdnou a pak jsem se divil, proč to nefunguje.
Jak vytvořit spustitelný skript v Raycastu
Potřebujete “Create Script Command” kde vytvoříte prázdný soubor v k tomu určeném adresáři. Do toho pak vložíte vytvořený Python. A hodí se “Reload Script Directories”, který načte případně aktualizované popisky/údaje skriptů po aktualizaci. RayCast totiž načítá název a další informace o skriptu z hlavičky skriptu.
Já si pro ten účel vytvořil složku ~/MyRayCastScripts (MyRayCastScripts vytvořené v mé domovské složce)
POZNÁMKA: Není nutné ho označovat +x (spustitelný), protože ho spouští Python. To si určíte při vytváření v RayCastul.
Pak si ho najdete (podle názvu/title), pravým tlačítkem na Configure Script Command, to vám umožní nastavit hotkey, klávesovou zkratku..
Když něco nevíš, pokračuj v ChatGPT
ChatGPT je tak trochu kouzlo. Protože když třeba bude chtít později ten skript upravit, tak prostě jen spustíte chatgpt v původním chatu (nebo si založíte nový a dáte jí tam ten skript) a jen řeknete co chcete (upravit, přidat, změnit) a ona vám vrátí buď co máte změnit, nebo kompletní nový skript.
Stejně tak je dobré si tam ladit prompt - ideálně s příklady, pokud něco dělá špatně, tak ji ukážete příklady co se nepovedlo vs. co se povedlo.
Jen pozor, když se jí budete ptát na věcí ohledně RayCastu, tak vám často řekne něco, co tam vůbec není, nebo je to někde jinde - nemá úplně aktuální a ani přesné znalosti.
Já jsem nakonec ještě s ChatGPT řešil rychlost a došla k tomu, že je lepší to přepsat a místo requests pouze základní urllib a také navrhla použít gpt-4o-mini. Mini modely jsou rychlejší než plné (a navíc levnější).
Doladěný prompt pro chytrý překlad
Prompt měl pár iterací, první byl jen z angličtiny do češtiny, ale protože je ideální mít na jedné klávese chytrý překlad, tak se rozhodne odkud kam vlastně překládat:
SYSTEM_PROMPT = (
"Detect the language of the input. "
"If the text is in Czech, translate it into English. "
"If the text is not in Czech, translate it into Czech. "
"Always output only the translation, natural and accurate, preserving style and tone."
)
Výhoda ChatGPT přes API je, že je méně ukecaná a nepřidává tam kupy keců jako ta webová/aplikační, ale stejně může mít chuť to nějak rozšířit, proto je v promptu ta poslední věda s jasným “only the translation”. Můžete klidně mít ten prompt česky, ale tady jsem prostě použil jeho anglickou variantu. “Natural and accurate” žádá přirozený a přesný překlad, zatímco “preserve style and tone” žádá aby se držela toho jaký je původní text.
Tohle slouží opravdu hlavně pro překlady krátkých textů, dvě či tři věty, to co jde do newsletterů #tyden a 365tipů (či jiných newsletterů podobného proveden. Nic ale nebrání tam posílat delší texty - byť ty asi budu spíš řešit ve webové ChatGPT, protože tam se dá čekat, že budu chtít překlad udělat “znovu a lépe. V API nic takového nejde, není to chat, každé volání je zcela samostatné.
Jak nakonec vypada toCZ2.py
Takhle nakonec vypadá kompletní skript. Ještě rozšířený o výpis nějakých chybových stavů. A se špatně nastaveným @raycast.title (je to ten obousměrný překlad).
V zásadě to není jen překladový skript, tohle je prostě volání ChatGPT kde vstupem je clipboard a výstupem je clipboard. A bude to dělat to co definuje prompt, takže použitelné pro cokoliv dalšího.
Jsem si dost jist, že ten skript by se dal zjednodušit/optimalizovat, ale tady máte to co dala dohromady ChatGPT a funguje to. Za pár dnů od zprovoznění to už přeložilo desítky věcí do newsletterů. ChatGPT má navíc vlastní knihovnu pro volání, tady to volán na přímo přes http. Takže lepší a úhlednější skript možná až v nějakém příštím životě.
#!/usr/bin/env python3
# @raycast.schemaVersion 1
# @raycast.title Translate clipboard -> Czech (fast)
# @raycast.mode silent
# @raycast.packageName AI Tools
# @raycast.icon 🌐
import os, sys, json, subprocess, urllib.request, urllib.error
API_KEY = "sem_musíte_vloziž_váš_API_klíč" # dočasně natvrdo (nejrychlejší varianta)
MODEL = "gpt-4o-mini" # latence bývá o chlup lepší než u 5-mini
SYSTEM_PROMPT = (
"Detect the language of the input. "
"If the text is in Czech, translate it into English. "
"If the text is not in Czech, translate it into Czech. "
"Always output only the translation, natural and accurate, preserving style and tone."
)
def pbpaste() -> str:
return subprocess.check_output("pbpaste", text=True)
def beep(times=1):
subprocess.run(["osascript", "-e", f'beep {times}'])
def pbcopy(text: str) -> None:
subprocess.run("pbcopy", text=True, input=text, check=True)
def call_openai(text: str) -> str:
url = "https://api.openai.com/v1/chat/completions"
payload = {
"model": MODEL,
"temperature": 0,
"max_tokens": 200, # drž nízko kvůli rychlosti
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text}
]
}
req = urllib.request.Request(
url,
data=json.dumps(payload).encode("utf-8"),
method="POST",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
)
try:
with urllib.request.urlopen(req, timeout=60) as resp:
data = json.loads(resp.read().decode("utf-8"))
return data["choices"][0]["message"]["content"].strip()
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="ignore")
print(f"HTTP {e.code} ERROR:\n{body}")
beep(3)
sys.exit(1)
def main():
src = pbpaste().strip()
if not src:
print("ERROR: Clipboard is empty."); sys.exit(1)
out = call_openai(src)
pbcopy(out)
print(out)
beep(1)
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"ERROR: {e}")
beep(3)
sys.exit(1)