Last active
October 18, 2023 09:01
-
-
Save ctrlcctrlv/fae00f11a20951e06db7ed502fd29f4c to your computer and use it in GitHub Desktop.
gcloud_translate.bash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# gcloud_translate() Fred util | |
# ★ gcloud_translate [source_language] [target_language] | |
# | |
# @mainfunc cloud_translate | |
BANNER=$(cat<<'BANNER' | |
_ _ _ _ _ _ _ | |
__ _ ___| | ___ _ _ __| | | |_ _ __ __ _ _ __ ___| | __ _| |_ ___ | |__ __ _ ___| |__ | |
/ _` |/ __| |/ _ \| | | |/ _` | | __| '__/ _` | '_ \/ __| |/ _` | __/ _ \ | '_ \ / _` / __| '_ \ | |
| (_| | (__| | (_) | |_| | (_| | | |_| | | (_| | | | \__ \ | (_| | || __/_| |_) | (_| \__ \ | | | | |
\__, |\___|_|\___/ \__,_|\__,_|___\__|_| \__,_|_| |_|___/_|\__,_|\__\___(_)_.__/ \__,_|___/_| |_| | |
|___/ |_____| | |
BANNER | |
) | |
# | |
# Interactively translate text using Google Cloud Translate API. | |
# Requires gcloud, yq, jq, and perl. Optionally requires sqlite3, xsel, and wl-copy. | |
# A bit of a mess, but it works. | |
# | |
TRUECOLOR_DARK_RED=`tput setaf 52` | |
TRUECOLOR_DARK_GREEN=`tput setaf 22` | |
TRUECOLOR_DARK_YELLOW=`tput setaf 94` | |
TRUECOLOR_DARK_BLUE=`tput setaf 19` | |
TRUECOLOR_DARK_MAGENTA=`tput setaf 127` | |
TRUECOLOR_DARK_CYAN=`tput setaf 23` | |
TRUECOLOR_DARK_GRAY=`tput setaf 238` | |
BOLD=`tput bold` | |
ITALIC=`tput sitm` | |
UNDERLINE=`tput smul` | |
RESET=`tput sgr0` | |
_F_CONFIG_ROOT="$HOME/.config/futiles" | |
_F_GCLOUD_TRANSLATE_CONFIG_ROOT="$_F_CONFIG_ROOT/gcloud_translate" | |
_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES="$_F_GCLOUD_TRANSLATE_CONFIG_ROOT/languages.json" | |
_F_SHARE_ROOT="$HOME/.local/share/futiles" | |
_F_HISTORY_ROOT="$_F_SHARE_ROOT/gcloud_translate/history/" | |
FUTIL_DEBUG="${FUTIL_DEBUG:-}" | |
_F_GCLOUD_TRANSLATE_DEBUG="$FUTIL_DEBUG" | |
SQLITE3_HISTORY="$_F_HISTORY_ROOT/history.sqlite" | |
# This is a 12 hour timeout used for the read bash builtin which has this envvar hardcoded | |
TMOUT=$((60 * 60 * 60 * 12)) | |
declare -g -x TMOUT | |
export TMOUT | |
# Check if sourced | |
# @returns 0 if sourced | |
_f_gcloud_translate_sourced() { | |
[[ "${BASH_SOURCE[0]}" != "${0}" ]] | |
return $? | |
} | |
# @param $* = string to echo | |
# @returns 0 | |
# $* means all arguments in one string, $@ means all arguments as separate strings | |
_fgtecho() { | |
>&2 echo -e "${TRUECOLOR_DARK_GREEN}$*${RESET}" | |
} | |
# @param $1 = prompt | |
# @param $@ = read arg, SHIFTED | |
_fgtread() { | |
local prompt="$1" | |
shift | |
>&2 read "$@" -p "${TRUECOLOR_DARK_GREEN}$prompt${RESET}" | |
} | |
# Create history database | |
SQL_SCHEMA1=$(cat<<-'SQL' | |
CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY, source TEXT, target TEXT, text TEXT, translation TEXT, request_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, translation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, service_name TEXT NOT NULL, CONSTRAINT service_name CHECK (service_name IN ('gcloud', 'deepl', 'openai'))); | |
SQL | |
) | |
SQL_SCHEMA2=$(cat<<-'SQL' | |
CREATE TABLE IF NOT EXISTS history_meta (id INTEGER PRIMARY KEY, key TEXT, value TEXT, UNIQUE(key, value)); | |
CREATE TABLE IF NOT EXISTS history_hostnames (id INTEGER PRIMARY KEY, hostname TEXT, fk_history INTEGER, FOREIGN KEY(fk_history) REFERENCES history(id)); | |
CREATE TABLE IF NOT EXISTS history_usernames (id INTEGER PRIMARY KEY, username TEXT, fk_history INTEGER, FOREIGN KEY(fk_history) REFERENCES history(id)); | |
CREATE INDEX IF NOT EXISTS history_source_idx ON history (source); | |
CREATE INDEX IF NOT EXISTS history_target_idx ON history (target); | |
CREATE INDEX IF NOT EXISTS history_text_idx ON history (text); | |
CREATE INDEX IF NOT EXISTS history_translation_idx ON history (translation); | |
CREATE INDEX IF NOT EXISTS history_request_time_idx ON history (request_time); | |
CREATE INDEX IF NOT EXISTS history_translation_time_idx ON history (translation_time); | |
CREATE INDEX IF NOT EXISTS history_meta_key_idx ON history_meta (key); | |
CREATE INDEX IF NOT EXISTS history_meta_value_idx ON history_meta (value); | |
CREATE INDEX IF NOT EXISTS history_hostnames_hostname_idx ON history_hostnames (hostname); | |
CREATE INDEX IF NOT EXISTS history_usernames_username_idx ON history_usernames (username); | |
INSERT INTO history_meta (key, value) VALUES ('schema_version', '1'); | |
SQL | |
) | |
_f_gcloud_sql_initialize() { | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: Initializing SQL database" | |
SQL_SCHEMA=() | |
while read -r line; do | |
SQL_SCHEMA+=("$line") | |
done < <(echo "$SQL_SCHEMA1 $SQL_SCHEMA2") | |
[[ -f "$SQLITE3_HISTORY" ]] || ( | |
mkdir -p "$_F_HISTORY_ROOT" | |
for sql in "${SQL_SCHEMA[@]}"; do | |
sqlite3 "$SQLITE3_HISTORY" <<< "$sql" | |
_fgtecho "Executed SQL: $sql" | |
done | |
) | |
} | |
# @param $1 = query | |
# @param $@ = query args | |
# @returns return code of sqlite3 | |
# @returns OUTSQL = output of sqlite3 | |
# @returns PID = PID of sqlite3 | |
# @requires sqlite3 | |
# @requires perl | |
# @requires sqlite3.pl script | |
# | |
# Example: | |
# _f_gcloud_do_query "SELECT * FROM history WHERE id = ?;" 1 | |
_f_gcloud_do_query() { | |
# Quiet bash's job control messages | |
set +b 2>/dev/null | |
set +m 2>/dev/null | |
hash sqlite3 2>/dev/null || { _fgtecho "sqlite3 not found, please install sqlite3"; return 1; } | |
local query="$1" | |
shift | |
local _query_args=() | |
for arg in "$@"; do | |
_query_args+=("${arg}") | |
done | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: Query: $query" | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: Query args: ${_query_args[@]}" | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && \ | |
_fgtecho "Debug: Executing query:\n\t\t$query ${_query_args[@]}" | |
# We do this through a coproc so that we can read the output of sqlite3 in a non-blocking manner | |
# Use perl to replace ? with $1, $2, etc. because sqlite3 doesn't support ? in a heredoc | |
sqlpipe="$(mktemp -u)" | |
mkfifo "$sqlpipe" | |
coproc sqlite3.pl "$SQLITE3_HISTORY" "$query" "${_query_args[@]}" > "$sqlpipe" | |
PID=$COPROC_PID | |
OUTSQL="$(cat "$sqlpipe")" | |
wait $PID | |
rm -f "$sqlpipe" | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: Query output:\n\t\t$OUTSQL" | |
echo "$OUTSQL" | |
# Restore job control messages | |
set -b 2>/dev/null | |
set -m 2>/dev/null | |
} | |
# @returns 0 | |
# @requires sqlite3 | |
_f_gcloud_init_history() { | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: Initializing history database. $_F_HISTORY_ROOT $_F_GCLOUD_TRANSLATE_CONFIG_ROOT $SQLITE3_HISTORY $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES" | |
if [ ! -f "$SQLITE3_HISTORY" -o ! -d "$_F_HISTORY_ROOT" ]; then | |
_fgtecho "Creating history database..." | |
mkdir -p "$_F_HISTORY_ROOT" | |
_f_gcloud_sql_initialize | |
else | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] && _fgtecho "Debug: History database already exists" | |
fi | |
} | |
# @param $1 = id | |
# | |
# Delete history entry and all associated data | |
_f_gcloud_sql_cleanup_id() { | |
local id="$1" | |
[[ -z "$id" ]] && return 1 | |
local i=0 | |
_f_gcloud_do_query "DELETE FROM history WHERE id = ?;" "$id" | |
i=$((i+$?)) | |
_f_gcloud_do_query "DELETE FROM history_hostnames WHERE fk_history = ?;" "$id" | |
i=$((i+$?)) | |
_f_gcloud_do_query "DELETE FROM history_usernames WHERE fk_history = ?;" "$id" | |
i=$((i+$?)) | |
# Warn about possible data corruption | |
[[ $i -ne 3 ]] && _fgtecho "Warning: Possible data corruption" | |
} | |
# @param $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES = path to languages list | |
# @returns return code of `gcloud beta ml translate get-supported-languages` | |
_f_gcloud_translate_download_languages() { | |
hash yq 2>/dev/null || { _fgtecho "yq not found, please install yq"; return 1; } | |
[[ ! -d $_F_GCLOUD_TRANSLATE_CONFIG_ROOT ]] && mkdir -p $_F_GCLOUD_TRANSLATE_CONFIG_ROOT | |
(gcloud beta ml translate get-supported-languages --model general/nmt --zone=us-central1 | yq) > "$_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES" | |
return $? | |
} | |
# Check if languages list is more than one month old… | |
# Download new list if it is. | |
# @param $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES = path to languages list | |
_f_gcloud_translate_check_languages() { | |
if [[ -f $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES ]]; then | |
local _F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES_LAST_MODIFIED=$(stat -c %Y $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES) | |
local _F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES_LAST_MODIFIED_DIFF=$(( $(date +%s) - $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES_LAST_MODIFIED )) | |
[[ $_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES_LAST_MODIFIED_DIFF -gt 2592000 ]] && ( | |
_fgtecho "Languages list is more than one month old, downloading new list..." | |
_f_gcloud_translate_download_languages | |
) | |
else | |
_fgtecho "Languages list not found, downloading new list..." | |
_f_gcloud_translate_download_languages | |
fi | |
} | |
# @param $1 = language json string | |
# @returns 0 if language is valid | |
# @returns 1 if language is invalid | |
_f_check_language_validity() { | |
local langjsonstr="$1" | |
[[ -z "$langjsonstr" ]] && return 1 | |
jq --arg langjson "$langjsonstr" 'select(.language == $langjson)' < "$_F_GCLOUD_TRANSLATE_CONFIG_LANGUAGES" | |
return $? | |
} | |
# @param $langiso639 = language’s ISO 639 code, e.g. en-US | |
# @returns to stdout = language name | |
# Private function | |
__f_language_name_to_iso639() { | |
local langname="$(cat /usr/share/i18n/locales/"$langiso639" | perl -ne 'print $1 if /language\s+"(.+)"/')" | |
[[ -z "$langname" ]] && return 1 | |
echo "$langname" | |
} | |
# @param $1 = language name | |
# @returns to stdout = language’s ISO 639 code, e.g. en-US | |
_f_language_iso639_to_name() { | |
local langiso639="$1" | |
__f_language_name_to_iso639 "$langiso639" | |
[[ -z "$langiso639" ]] && return 1 | |
# Try name before _ | |
[[ -z "$langname" ]] && ( | |
langiso639_before_underscore="$(echo "$langiso639" | cut -d_ -f1)" | |
__f_language_name_to_iso639 "$langiso639_before_underscore" | |
) | |
} | |
# @param $OUTTEXT = output transated text, global | |
# @returns 0 | |
# @bypasses _fgtecho! | |
_f_gcloud_translate_print_translation() { | |
echo "${BOLD}""${OUTTEXT}""${RESET}" | |
} | |
# Uses `test -t 0` to determine if session is interactive, | |
# which works by using the fact that a non-interactive session | |
# will have stdin redirected from a file or pipe. :) | |
# | |
# May only work in GNU bash, wmmv (works on my machine™) | |
_f_gcloud_interactive() { | |
# Is session interactive? | |
declare -g -x FUTIL_INTERACTIVE | |
FUTIL_INTERACTIVE=$(test -t 0 ; echo $?) | |
return $FUTIL_INTERACTIVE | |
} | |
# @returns 0 if output is written to file | |
# @returns 1 if output is not written to file | |
# @returns 1 if no output text | |
# @requires wl-copy | |
# @requires xsel | |
# | |
# Output text to wl-copy, xsel, or file | |
_f_gcloud_output() { | |
# Prompt user for writing output to wl-copy | |
_fgtread "Write output where? [w(l-copy)/x(sel -b)/n(one)/f(ile)] " -n 1 -r | |
_fgtecho | |
case "$REPLY" in | |
w) | |
wl-copy <<< "$OUTTEXT" | |
;; | |
x) | |
xsel -b <<< "$OUTTEXT" | |
;; | |
f) | |
_fgtread "Write output to [t(emporary file)/s(pecified file)/n(one)]? " -n 1 -r | |
_fgtecho | |
case "$REPLY" in | |
t) | |
local OUTTXT="$(mktemp --suffix=.gcldtrns)" | |
_fgtecho "Output text will be stored in $OUTTXT" | |
echo "$OUTTEXT" > "$OUTTXT" | |
if ! _f_gcloud_interactive; then | |
echo "$OUTTXT" | |
fi | |
;; | |
s) | |
read -p "Write output to which file? " OUTTXT | |
echo "$OUTTEXT" > "$OUTTXT" | |
;; | |
*) | |
if _f_gcloud_interactive; then | |
_fgtecho "Invalid option, returning to main menu" | |
_f_gcloud_output | |
else | |
return 1 | |
fi | |
esac | |
;; | |
n) | |
;; | |
*) | |
if _f_gcloud_interactive; then | |
_fgtecho "Invalid option" | |
_f_gcloud_output | |
else | |
_f_gcloud_output <<< "f""t" # Write to file, temporary | |
fi | |
;; | |
esac | |
} | |
# @returns temp file name | |
# @returns 1 if no input text | |
# @returns 0 if input text | |
_f_gcloud_read_stdin() { | |
local INTXT="$(mktemp --suffix=.gcldtrns)" | |
_fgtecho "Input text will be stored in $INTXT …" | |
trap "rm -f $INTXT; return 1" SIGINT | |
[ -f /dev/fd/4 ] && exec 4>&- | |
exec 4<>"$INTXT"; | |
# Redirect stdin to temp file | |
_fgtecho "Enter text to translate, press Ctrl+D when done:" | |
read -d '' -r -e -u 0 CONTENT | |
wait $! | |
>&4 echo -e "$CONTENT"; | |
perl -e 'print "\n"' >&4; | |
perl -pe 's/[\r]/\n/g' <&4 >&2; | |
exec 4<&-; | |
stat -c '%s' "$INTXT" | grep -q '^0$' && { _fgtecho "No input text"; return 1; } | |
echo "$INTXT" # Return temp file name to caller | |
return 0 | |
} | |
# @param $1 = source language | |
# @param $2 = target language | |
# | |
# Interactively translate text using either Google Cloud Translate API, DeepL API, or OpenAI API. | |
# A bit of a mess, but it works. | |
# A history database is created in ~/.local/share/futiles/gcloud_translate/history.sqlite and is used to store all translations. | |
cloud_translate(){ | |
# Check if any arg == -h or --help | |
for arg in "$@"; do | |
[[ "$arg" == "-h" || "$arg" == "--help" ]] && { _fgt_help; return 0; } | |
done | |
# Quiet bash's job control messages | |
set +b 2>/dev/null | |
set +m 2>/dev/null | |
# Check if sourced | |
_f_gcloud_translate_sourced || return 1 | |
_f_gcloud_translate_check_languages | |
local langfrom="$1" | |
local langto="$2" | |
if [[ -z "$_FGT_CLOUD_SERVICE" ]]; then | |
{ _fgtecho "Usage: cloud_translate [source_language] [target_language]"; echo "$BANNER"; } | |
_fgtread "Cloud service not specified. Which cloud service? [(g)cloud/(dD)eepL/(cC)hatGPT by (oO)penAI]" -n 1 -r | |
_fgtecho | |
case "$REPLY" in | |
g|G) | |
_FGT_CLOUD_SERVICE="gcloud" | |
;; | |
d|D) | |
_FGT_CLOUD_SERVICE="deepl" | |
;; | |
o|O|c|C) | |
_FGT_CLOUD_SERVICE="openai" | |
;; | |
*) | |
_fgtecho "Invalid cloud service" | |
_f_gcloud_interactive && cloud_translate "$@" | |
;; | |
esac | |
fi | |
# Read text from stdin, put in temp file | |
local INTXT="$(_f_gcloud_read_stdin)" | |
trap "rm -f $INTXT" EXIT | |
[[ $? -ne 0 ]] && return 1 | |
# Check if language is valid | |
while ! (_f_check_language_validity "$langfrom"); do | |
_fgtecho "Invalid source language" | |
read -p "Source language…? " langfrom | |
done | |
while ! (_f_check_language_validity "$langto"); do | |
_fgtecho "Invalid target language" | |
read -p "Target language…? " langto | |
done | |
# Translate | |
if [[ "$_FGT_CLOUD_SERVICE" == "gcloud" ]]; then | |
_f_gcloud_translate_gcloud "$langfrom" "$langto" | |
elif [[ "$_FGT_CLOUD_SERVICE" == "deepl" ]]; then | |
_f_gcloud_translate_deepl "$langfrom" "$langto" | |
elif [[ "$_FGT_CLOUD_SERVICE" == "openai" ]]; then | |
_f_gcloud_translate_openai "$langfrom" "$langto" | |
else | |
_fgtecho "Invalid cloud service" | |
return 1 | |
fi <<< "$INTXT" | |
# Check if output is empty | |
[[ -z "$OUTTEXT" ]] && { _fgtecho "No output text"; return 1; } | |
_f_gcloud_translate_print_translation | |
# Output | |
_f_gcloud_output | |
_f_gcloud_init_history | |
# Correctly escape all texts to SQLite3 by using ? syntax and get last inserted row ID | |
sqli="INSERT INTO history (source, target, text, translation, service_name) VALUES (?, ?, ?, ?, ?);" | |
_f_gcloud_do_query "$sqli" "$langfrom" "$langto" "$(cat "$INTXT")" "$OUTTEXT" "$_FGT_CLOUD_SERVICE" | |
sqli="SELECT MAX(id) FROM history;" | |
local last_insert_rowid=() | |
while read -r line; do | |
last_insert_rowid+=("$line") | |
done < <(_f_gcloud_do_query "$sqli") | |
# Get hostname and username | |
local hostname="$(hostname)" | |
local username="$(whoami)" | |
# Insert hostname and username into history_hostnames and history_usernames | |
sqli="INSERT INTO history_hostnames (hostname, fk_history) VALUES (?, ?);" | |
_f_gcloud_do_query "$sqli" "$hostname" "${last_insert_rowid[0]}" | |
sqlu="INSERT INTO history_usernames (username, fk_history) VALUES (?, ?);" | |
_f_gcloud_do_query "$sqlu" "$username" "${last_insert_rowid[0]}" | |
# Cleanup | |
[[ -n "$_F_GCLOUD_TRANSLATE_DEBUG" ]] || rm -v -f "$INTXT" | |
} | |
_F_OPENAI_DEFAULT_TIMEOUT=5 | |
# @param $1 = source language | |
# @param $2 = target language | |
# @requires jq | |
# @requires curl | |
# | |
# Translate text using OpenAI API | |
_f_gcloud_translate_openai() { | |
# Check if OpenAI API key is set | |
[[ -z "$OPENAI_API_KEY" ]] && \ | |
{ _fgtecho "OPENAI_API_KEY is not set"; return 1; } | |
# Construct the prompt | |
local prompt="Translate the following text from $langfrom to $langto:\n\n$(cat "$INTXT")" | |
cat > "$INTXT" <<< "$prompt" | |
# Send the request to OpenAI API | |
OUTTREQ="$(curl -L -s -H "Content-Type: application/json" \ | |
-H "Authorization: Bearer $OPENAI_API_KEY" \ | |
-X POST \ | |
--data @<( | |
jq '{"model":"gpt-4", "messages": [{"role":"user","content":$prompt}]}' -s --rawfile prompt "$INTXT" <(echo) \ | |
) \ | |
https://api.openai.com/v1/chat/completions)" | |
OUTTEXT=$(jq -s -r '.[0].choices[0].message.content' <<< "$OUTTREQ") | |
} | |
# @param $1 = source language | |
# @param $2 = target language | |
# @requires yq | |
# @requires gcloud | |
# @requires perl | |
# | |
# Translate text using Google Cloud Translate API | |
_f_gcloud_translate_gcloud() { | |
read -r npipe < <(mktemp -u) | |
mkfifo "$npipe" | |
coproc \ | |
(gcloud alpha ml translate translate-text --source-language="$langfrom" --target-language="$langto" \ | |
--model general/nmt --zone=us-central1 --format=json --content-file="$INTXT" --mime-type=text/plain | \ | |
yq -r '.translations[].translatedText' | sed -e 's/[\r]/\n/g') >>"$npipe" & | |
PID=$COPROC_PID | |
OUTTEXT="$(cat "$npipe")" | |
wait $PID | |
rm -f "$npipe" | |
} | |
# @param $1 = source language | |
# @param $2 = target language | |
# @requires jq | |
# @requires curl | |
# @requires perl | |
# | |
# Translate text using DeepL API | |
_f_gcloud_translate_deepl() { | |
[[ -z "$DEEPL_AUTH_KEY" ]] && \ | |
[[ ! -f "$_F_GCLOUD_TRANSLATE_CONFIG_ROOT/deepl_auth_key" ]] && \ | |
{ _fgtecho "DEEPL_AUTH_KEY not set and $_F_GCLOUD_TRANSLATE_CONFIG_ROOT/deepl_auth_key not found"; return 1; } | |
DEEPL_AUTH_KEY="$(cat "$_F_GCLOUD_TRANSLATE_CONFIG_ROOT/deepl_auth_key")" | |
# Use DeepL Pro ? | |
[[ -f $_F_GCLOUD_TRANSLATE_CONFIG_ROOT/deepl_pro ]] && \ | |
DEEPL_PRO=1 || \ | |
DEEPL_PRO=0 | |
# DeepL API domains | |
if [[ $DEEPL_PRO -eq 1 ]]; then | |
DEEPL_API_DOMAIN="api.deepl.com" | |
else | |
DEEPL_API_DOMAIN="api-free.deepl.com" | |
fi | |
read -r npipe < <(mktemp -u) | |
mkfifo "$npipe" | |
# Text may be long so we must use curl's file-read feature | |
coproc \ | |
(curl -s -X POST --data-urlencode "auth_key=$DEEPL_AUTH_KEY" --data-urlencode "text@$INTXT" \ | |
--data-urlencode "source_lang=$langfrom" --data-urlencode "target_lang=$langto" \ | |
"https://$DEEPL_API_DOMAIN/v2/translate" | \ | |
jq -r '.translations[].text' | sed -e 's/[\r]/\n/g') >>"$npipe" & | |
PID=$COPROC_PID | |
OUTTEXT="$(cat "$npipe")" | |
wait $PID | |
rm -f "$npipe" | |
} | |
################################ | |
## Aliases to cloud_translate ## | |
################################ | |
_f_gcloud_translate() { | |
export _FGT_CLOUD_SERVICE="gcloud" | |
cloud_translate "$@" | |
_FGT_CLOUD_SERVICE="" | |
} | |
_f_deepl_translate() { | |
export _FGT_CLOUD_SERVICE="deepl" | |
cloud_translate "$@" | |
_FGT_CLOUD_SERVICE="" | |
} | |
_f_openai_translate() { | |
export _FGT_CLOUD_SERVICE="openai" | |
cloud_translate "$@" | |
_FGT_CLOUD_SERVICE="" | |
} | |
############################## | |
## Aliases, for convenience ## | |
############################## | |
gcloud_translate() { | |
_f_gcloud_translate "$@" | |
} | |
deepl_translate() { | |
_f_deepl_translate "$@" | |
} | |
openai_translate() { | |
_f_openai_translate "$@" | |
} | |
############################### | |
## More aliases, for funsies ## | |
############################### | |
GoogleTranslate() { | |
_f_gcloud_translate "$@" | |
} | |
DeepL() { | |
_f_deepl_translate "$@" | |
} | |
GPT4() { | |
_f_openai_translate "$@" | |
} | |
################################### | |
## Aliases, for backwards compat ## | |
################################### | |
gpt() { GPT4 "$@"; } | |
gpt3() { GPT4 "$@"; } | |
gpt4() { GPT4 "$@"; } | |
GPT3() { GPT4 "$@"; } | |
GPT() { GPT4 "$@"; } | |
ChatGPT() { GPT4 "$@"; } | |
Google() { GoogleTranslate "$@"; } | |
deepl() { DeepL "$@"; } | |
google() { GoogleTranslate "$@"; } | |
GT() { GoogleTranslate "$@"; } | |
################################### | |
## HELP ## | |
################################### | |
_fgt_help() { | |
>&2 echo "$BANNER" | |
>&2 cat<<HELP | |
cloud_translate() Fred util | |
★ cloud_translate [source_language] [target_language] | |
Interactively translate text using Google Cloud Translate API, DeepL API, or OpenAI API. | |
`tput smul`ENVIRONMENT VARIABLES`tput sgr0` | |
`tput bold`OPENAI_API_KEY`tput sgr0` | |
OpenAI API key. Required for OpenAI API. | |
`tput bold`DEEPL_AUTH_KEY`tput sgr0` | |
DeepL API key. Required for DeepL API. | |
`tput bold`FUTIL_DEBUG`tput sgr0` | |
Set to any value to enable debug mode. | |
`tput setaf 1 smul`Note: `tput sgr0` | |
Google Cloud Translate API does not require an API key, but will not | |
work if gcloud is not installed and configured and the user has not | |
enabled the Cloud Translation API. | |
`tput smul`OPTIONS`tput sgr0` | |
`tput bold`-h, --help`tput sgr0` | |
`tput smul`ARGUMENTS`tput sgr0` | |
`tput bold`source_language`tput sgr0` | |
Source language. If not specified, will be prompted for. | |
For OpenAI API, this is freeform text and should be the complete language name, e.g. English, French, etc. | |
For Google Cloud Translate API and DeepL API, this is the ISO 639-1 language code, e.g. en, fr, etc. | |
`tput bold`target_language`tput sgr0` | |
Target language. If not specified, will be prompted for. | |
`tput smul`ALIASES`tput sgr0` | |
`tput bold`gcloud_translate`tput sgr0` | |
`tput bold`GoogleTranslate`tput sgr0` | |
`tput bold`Google`tput sgr0` | |
Alias for cloud_translate using Google Cloud Translate API. | |
`tput bold`deepl_translate`tput sgr0` | |
`tput bold`DeepL`tput sgr0` | |
`tput bold`deepl`tput sgr0` | |
Alias for cloud_translate using DeepL API. | |
`tput bold`openai_translate`tput sgr0` | |
`tput bold`GPT4`tput sgr0` | |
`tput bold`GPT3`tput sgr0` `tput sitm`$TRUECOLOR_DARK_GRAY(deprecated; doesn't actually use GPT-3)`tput sgr0` | |
`tput bold`GPT`tput sgr0` | |
`tput bold`ChatGPT`tput sgr0` | |
Alias for cloud_translate using OpenAI API. | |
HELP | |
return 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You need also sqlite3.pl — https://gist.github.com/ctrlcctrlv/56b5ccad23813b1fe5e7466fe45a30d2