|
api="lms"; |
|
ai_host="http://127.0.0.1:7879"; |
|
auth=""; |
|
model="translategemma-4b-it"; |
|
stderr_thinking=0; |
|
uri="/"; |
|
text_path="."; |
|
thinking_path=""; |
|
error_path=""; |
|
temperature=1; |
|
context_length=40000; |
|
|
|
|
|
THINKING_COLOR=""; |
|
RESET_COLOR=""; |
|
ERROR_COLOR=""; |
|
|
|
if [ -n "$(tput colors 2>/dev/null)" ] && [ "$(tput colors)" -ge 256 ]; then |
|
THINKING_COLOR="$(tput setaf 250)"; |
|
ERROR_COLOR="$(tput setaf 1)"; |
|
RESET_COLOR="$(tput sgr0)"; |
|
fi |
|
|
|
error() { echo "$ERROR_COLOR""Error:$RESET_COLOR $@" 1>&2; exit 1; } |
|
|
|
usage() { echo -e "Usage: $0 [options] <lang_from> <lang_to> <text...>\n\nAvailable params:\n -e <string> - AI API host (Current: $ai_host)\n -k <string> - API authorization key\n -a <openai/anthropic/lms> - which API the script should use (Current: $api)\n -r - print reasoning process to stderr if there's any (Current: $stderr_thinking)\n -m <string> - name of LLM to use (Current: $model)\n -t <number> - randomness level of model's output from 0 to 1 (Current: $temperature)\n -l <number> - model's context length (Current: $context_length)\n\nExample:\n - $0 -e "https://api.openai.com" -a openai -m "gpt-5.4-nano" English Russian Hello, how are you doing this fine morning?"; exit 0; } |
|
|
|
while [[ $# -gt 0 ]]; do |
|
case "$1" in |
|
-?) |
|
case "${1#-}" in |
|
e) |
|
ai_host="$2"; |
|
shift 2; |
|
;; |
|
k) |
|
auth="$2"; |
|
shift 2; |
|
;; |
|
a) |
|
api="$2"; |
|
shift 2; |
|
;; |
|
r) |
|
stderr_thinking=1; |
|
shift 1; |
|
;; |
|
m) |
|
model="$2"; |
|
shift 2; |
|
;; |
|
t) |
|
temperature="$2"; |
|
shift 2; |
|
;; |
|
l) |
|
context_length="$2"; |
|
shift 2; |
|
;; |
|
*) |
|
usage; |
|
;; |
|
esac |
|
;; |
|
*) |
|
break; |
|
;; |
|
esac |
|
done |
|
|
|
if [ $# -lt 3 ]; then |
|
usage; |
|
fi |
|
|
|
source_language="$1"; |
|
target_language="$2"; |
|
shift 2; |
|
text="$@"; |
|
|
|
system_prompt="You are a professional $source_language to $target_language translator. Your goal is to accurately convey the meaning and nuances of the original $source_language text while adhering to $target_language grammar, vocabulary, and cultural sensitivities.\nProduce only the $target_language translation, without any additional explanations or commentary.\nThe output text you about to produce should have exactly the same meaning as user's text, but in $target_language instead of $source_language." |
|
|
|
if [ "$api" == "openai" ]; then |
|
uri="v1/chat/completions"; |
|
text_path=".choices[0].message.content"; |
|
thinking_path=".choices[0].message.reasoning_content"; |
|
error_path=".error.message"; |
|
elif [ "$api" == "anthropic" ]; then |
|
uri="v1/messages"; |
|
text_path=".content[] | select(.type == \"text\") .text"; |
|
error_path=".error.message"; |
|
elif [ "$api" == "lms" ]; then |
|
uri="api/v1/chat"; |
|
text_path=".output[] | select(.type == \"message\") .content"; |
|
thinking_path=".output[] | select(.type == \"reasoning\") .content"; |
|
error_path=".error.message"; |
|
else |
|
error "Invalid API specified"; |
|
fi |
|
|
|
curl_args=("-s" "-X" "POST" "$ai_host/$uri" -d @- "-H" "Content-Type: application/json"); |
|
|
|
if [ -n "$auth" ]; then |
|
if [ "$api" == "anthropic" ]; then |
|
curl_args+=("-H" "x-api-key: $auth"); |
|
else |
|
curl_args+=("-H" "Authorization: Bearer $auth"); |
|
fi |
|
fi |
|
|
|
json_template=$(grep -Pzo '(?<=### '$api'_start\n)[\s\S]*?(?=\n### '$api'_end)' $0 | tr -d '\0' | sed -e 's/^#//'); |
|
json_input=$(jq --null-input --arg AIMODEL "$model" --arg SYS_PROMPT "$system_prompt" --arg PROMPT "$text" --arg TEMP "$temperature" --arg CONTLEN "$context_length" "$json_template"); |
|
json_output=$(printf '%s' "$json_input" | curl "${curl_args[@]}"); |
|
|
|
if [ -n "$error_path" ]; then |
|
errror_message=$(printf '%s' "$json_output" | jq -r "$error_path // \"\"" 2>/dev/null); |
|
if [ -n "$errror_message" ]; then |
|
error "$errror_message"; |
|
fi |
|
fi |
|
|
|
if [ $stderr_thinking -ne 0 ] && [ "$thinking_path" != "" ]; then |
|
thinking_result=$(printf '%s' "$json_output" | jq -r "$thinking_path // \"\"" 2>/dev/null); |
|
if [ "$thinking_result" != "" ]; then |
|
printf "$THINKING_COLOR$thinking_result$RESET_COLOR" 1>&2; |
|
fi |
|
fi |
|
|
|
if ! printf '%s' "$json_output" | jq -re "$text_path // \"\""; then |
|
error "$json_output"; |
|
fi |
|
|
|
### openai_start |
|
#{ |
|
# "model": $AIMODEL, |
|
# "messages": [ |
|
# { |
|
# "role": "system", |
|
# "content": $SYS_PROMPT, |
|
# }, |
|
# { |
|
# "role": "user", |
|
# "content": [ |
|
# { |
|
# "type": "text", |
|
# "text": $PROMPT |
|
# } |
|
# ] |
|
# } |
|
# ], |
|
# "temperature": $TEMP|tonumber, |
|
# "max_tokens": $CONTLEN|tonumber |
|
#} |
|
### openai_end |
|
|
|
### lms_start |
|
#{ |
|
# "model": $AIMODEL, |
|
# "system_prompt": $SYS_PROMPT, |
|
# "input": $PROMPT, |
|
# "context_length": $CONTLEN|tonumber, |
|
# "temperature": $TEMP|tonumber |
|
#} |
|
### lms_end |
|
|
|
### anthropic_start |
|
#{ |
|
# "model": $AIMODEL, |
|
# "system": $SYS_PROMPT, |
|
# "messages": [ |
|
# { |
|
# "role": "user", |
|
# "content": $PROMPT |
|
# } |
|
# ], |
|
# "max_tokens": $CONTLEN|tonumber, |
|
# "temperature": $TEMP|tonumber |
|
#} |
|
### anthropic_end |