This commit is contained in:
commit
1afd6902e7
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Name": "fx",
|
||||
"Description": "create an fx component",
|
||||
"Package":""
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{{- $pkg := env "PWD" | base | coalesce Package -}}
|
||||
package {{$pkg}}
|
||||
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
|
||||
type {{title $pkg}} struct {
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
type Params struct {
|
||||
fx.In
|
||||
|
||||
Ctx context.Context
|
||||
Lc fx.Lifecycle
|
||||
Log *slog.Logger
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
fx.Out
|
||||
|
||||
Output *{{title $pkg}}
|
||||
}
|
||||
|
||||
func New(p Params) (r Result, err error) {
|
||||
o := &{{title $pkg}}{}
|
||||
o.log = p.Log
|
||||
|
||||
r.Output = o
|
||||
return
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Name": "river",
|
||||
"Description": "create an river component",
|
||||
"Package":""
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{{- $pkg := env "PWD" | base | coalesce Package -}}
|
||||
package {{$pkg}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path"
|
||||
"reflect"
|
||||
|
||||
"gfx.cafe/util/go/fxriver"
|
||||
"github.com/riverqueue/river"
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
|
||||
var (
|
||||
packageName = path.Base(reflect.TypeOf(Args{}).PkgPath())
|
||||
)
|
||||
|
||||
type Args struct {
|
||||
}
|
||||
|
||||
func (a *Args) Kind() string {
|
||||
return packageName + ".task"
|
||||
}
|
||||
|
||||
type Worker struct {
|
||||
river.WorkerDefaults[*Args]
|
||||
|
||||
log *slog.Logger
|
||||
}
|
||||
type Params struct {
|
||||
fx.In
|
||||
|
||||
Ctx context.Context
|
||||
Lc fx.Lifecycle
|
||||
Log *slog.Logger
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
fx.Out
|
||||
|
||||
Output fxriver.WorkConfigurer `group:"river_worker"`
|
||||
}
|
||||
|
||||
func New(p Params) (r Result, err error) {
|
||||
o := &Worker{}
|
||||
o.log = p.Log
|
||||
|
||||
r.Output = fxriver.Wrap(o)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Worker) Work(ctx context.Context, job *river.Job[*Args]) error {
|
||||
o.log.Info("Starting Job", "name", packageName, "args", job.Args)
|
||||
return fmt.Errorf("Job %s is not implemented", packageName)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
gamermode_off(){
|
||||
notify-send -t 1600 'disabled gamermode' --icon=video-display
|
||||
superctl start picom
|
||||
# picom -b --log-file /var/log/picom.log --log-level INFO
|
||||
}
|
||||
|
||||
gamermode_on(){
|
||||
notify-send -t 1600 'enabled gamermode' --icon=video-display
|
||||
superctl stop picom
|
||||
# killall picom;
|
||||
}
|
||||
|
||||
if [ `pgrep -x picom` ]; then
|
||||
gamermode_on
|
||||
else
|
||||
gamermode_off
|
||||
fi
|
||||
exit
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
git add -A
|
||||
if [ "$#" -eq 0 ]; then
|
||||
git commit -m "noot"
|
||||
else
|
||||
array=("$@")
|
||||
str="${array[@]}"
|
||||
git commit -m "$str"
|
||||
fi
|
||||
git push
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
|
||||
go install github.com/klauspost/asmfmt/cmd/asmfmt@latest
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
go install github.com/kisielk/errcheck@latest
|
||||
go install github.com/davidrjenni/reftools/cmd/fillstruct@master
|
||||
go install github.com/rogpeppe/godef@latest
|
||||
go install golang.org/x/tools/cmd/goimports@master
|
||||
go install github.com/mgechev/revive@latest
|
||||
go install golang.org/x/tools/gopls@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
go install github.com/fatih/gomodifytags@latest
|
||||
go install golang.org/x/tools/cmd/gorename@master
|
||||
go install github.com/jstemmer/gotags@master
|
||||
go install golang.org/x/tools/cmd/guru@master
|
||||
go install github.com/josharian/impl@main
|
||||
go install honnef.co/go/tools/cmd/keyify@master
|
||||
go install github.com/fatih/motion@latest
|
||||
go install github.com/koron/iferr@master
|
||||
go install golang.org/x/perf/cmd/benchstat@latest
|
||||
go install github.com/wader/bump/cmd/bump@latest
|
||||
go install mvdan.cc/gofumpt@latest
|
||||
go install github.com/abice/go-enum@latest
|
||||
go install golang.org/x/tools/cmd/gonew@latest
|
||||
go install github.com/cweill/gotests@latest
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
go install github.com/abenz1267/gomvp@latest
|
||||
go install github.com/tmc/json-to-struct@latest
|
||||
|
||||
mise reshim
|
|
@ -0,0 +1,128 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Get the procs sorted by the number of inotify watches
|
||||
# @author Carl-Erik Kopseng
|
||||
# @latest https://github.com/fatso83/dotfiles/blob/master/utils/scripts/inotify-consumers
|
||||
# Discussion leading up to answer: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
|
||||
#
|
||||
#
|
||||
########################################## Notice ##########################################
|
||||
### Since Fall 2022 you should prefer using the following C++ version ###
|
||||
### https://github.com/mikesart/inotify-info ###
|
||||
############################################################################################
|
||||
#
|
||||
#
|
||||
# The fastest version of this script is here: https://github.com/fatso83/dotfiles/commit/inotify-consumers-v1-fastest
|
||||
# Later PRs introduced significant slowdowns at the cost of better output, but it is insignificant on most machines
|
||||
# See this for details: https://github.com/fatso83/dotfiles/pull/10#issuecomment-1122374716
|
||||
|
||||
main(){
|
||||
printf "\n%${WLEN}s %${WLEN}s\n" "INOTIFY" "INSTANCES"
|
||||
printf "%${WLEN}s %${WLEN}s\n" "WATCHES" "PER "
|
||||
printf "%${WLEN}s %${WLEN}s %s\n" " COUNT " "PROCESS " "PID USER COMMAND"
|
||||
printf -- "------------------------------------------------------------\n"
|
||||
generateData
|
||||
}
|
||||
|
||||
usage(){
|
||||
cat << EOF
|
||||
Usage: $0 [--help|--limits]
|
||||
-l, --limits Will print the current related limits and how to change them
|
||||
-h, --help Show this help
|
||||
|
||||
FYI: Check out Michael Sartain's C++ take on this script. The resulting native executable
|
||||
is much faster, modern and feature rich. It can be found at
|
||||
https://github.com/mikesart/inotify-info
|
||||
|
||||
Requires building, but is well worth the few seconds :)
|
||||
EOF
|
||||
}
|
||||
|
||||
limits(){
|
||||
printf "\nCurrent limits\n-------------\n"
|
||||
sysctl fs.inotify.max_user_instances fs.inotify.max_user_watches
|
||||
|
||||
cat <<- EOF
|
||||
Changing settings permanently
|
||||
-----------------------------
|
||||
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
|
||||
sudo sysctl -p # re-read config
|
||||
EOF
|
||||
}
|
||||
|
||||
generateData() {
|
||||
local -i PROC
|
||||
local -i PID
|
||||
local -i CNT
|
||||
local -i INSTANCES
|
||||
local -i TOT
|
||||
local -i TOTINSTANCES
|
||||
# read process list into cache
|
||||
local PSLIST="$(ps ax -o pid,user=WIDE-COLUMN,command $COLSTRING)"
|
||||
local INOTIFY="$(find /proc/[0-9]*/fdinfo -type f 2>/dev/null | xargs grep ^inotify 2>/dev/null)"
|
||||
local INOTIFYCNT="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3 |uniq -c | sed -e 's/:.*//')"
|
||||
# unique instances per process is denoted by number of inotify FDs
|
||||
local INOTIFYINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3,5 | sed -e 's/:.*//'| uniq |awk '{print $1}' |uniq -c)"
|
||||
local INOTIFYUSERINSTANCES="$(echo "$INOTIFY" | cut -d "/" -s --output-delimiter=" " -f 3,5 | sed -e 's/:.*//' | uniq |
|
||||
while read PID FD; do echo $PID $FD $(grep -e "^ *${PID} " <<< "$PSLIST"|awk '{print $2}'); done | cut -d" " -f 3 | sort | uniq -c |sort -nr)"
|
||||
set -e
|
||||
|
||||
cat <<< "$INOTIFYCNT" |
|
||||
{
|
||||
while read -rs CNT PROC; do # count watches of processes found
|
||||
echo "${PROC},${CNT},$(echo "$INOTIFYINSTANCES" | grep " ${PROC}$" |awk '{print $1}')"
|
||||
done
|
||||
} |
|
||||
grep -v ",0," | # remove entires without watches
|
||||
sort -n -t "," -k 2,3 -r | # sort to begin with highest numbers
|
||||
{ # group commands so that $TOT is visible in the printf
|
||||
IFS=","
|
||||
while read -rs PID CNT INSTANCES; do # show watches and corresponding process info
|
||||
printf "%$(( WLEN - 2 ))d %$(( WLEN - 2 ))d %s\n" "$CNT" "$INSTANCES" "$(grep -e "^ *${PID} " <<< "$PSLIST")"
|
||||
TOT=$(( TOT + CNT ))
|
||||
TOTINSTANCES=$(( TOTINSTANCES + INSTANCES))
|
||||
done
|
||||
# These stats should be per-user as well, since inotify limits are per-user..
|
||||
printf "\n%$(( WLEN - 2 ))d %s\n" "$TOT" "WATCHES TOTAL COUNT"
|
||||
# the total across different users is somewhat meaningless, not printing for now.
|
||||
# printf "\n%$(( WLEN - 2 ))d %s\n" "$TOTINSTANCES" "TOTAL INSTANCES COUNT"
|
||||
}
|
||||
echo ""
|
||||
echo "INotify instances per user (e.g. limits specified by fs.inotify.max_user_instances): "
|
||||
echo ""
|
||||
(
|
||||
echo "INSTANCES USER"
|
||||
echo "----------- ------------------"
|
||||
echo "$INOTIFYUSERINSTANCES"
|
||||
) | column -t
|
||||
echo ""
|
||||
exit 0
|
||||
}
|
||||
|
||||
# get terminal width
|
||||
declare -i COLS=$(tput cols 2>/dev/null || echo 80)
|
||||
declare -i WLEN=10
|
||||
declare COLSTRING="--columns $(( COLS - WLEN ))" # get terminal width
|
||||
|
||||
if [ "$1" = "--limits" -o "$1" = "-l" ]; then
|
||||
limits
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" = "--help" -o "$1" = "-h" ]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# added this line and moved some declarations to allow for the full display instead of a truncated version
|
||||
if [ "$1" = "--full" -o "$1" = "-f" ]; then
|
||||
unset COLSTRING
|
||||
main
|
||||
fi
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
printf "\nUnknown parameter '$1'\n" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
main
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
target="$HOME/.local/bin"
|
||||
|
||||
echo "installing $2 to $1"
|
||||
|
||||
if test -f $2; then
|
||||
cp $2 "$target/$1"
|
||||
chmod +x "$target/$1"
|
||||
else
|
||||
echo "file $2 doesnt exist"
|
||||
fi
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
ssh_node() {
|
||||
node=$1
|
||||
if [ "$node" = "" ]; then
|
||||
node=$(kubectl get node -o name | sed 's/node\///' | tr '\n' ' ')
|
||||
node=${node::-1}
|
||||
|
||||
if [[ "$node" =~ " " ]]; then
|
||||
echo "Node name must be specified. Choose one of: [$node]"
|
||||
exit 1
|
||||
else
|
||||
echo "Single-node cluster detected. Defaulting to node $node"
|
||||
fi
|
||||
fi
|
||||
|
||||
pod=$(
|
||||
kubectl create -o name -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
generateName: ssh-node-
|
||||
labels:
|
||||
plugin: ssh-node
|
||||
spec:
|
||||
nodeName: $node
|
||||
containers:
|
||||
- name: ssh-node
|
||||
image: busybox
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["chroot", "/host"]
|
||||
tty: true
|
||||
stdin: true
|
||||
stdinOnce: true
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: host
|
||||
mountPath: /host
|
||||
volumes:
|
||||
- name: host
|
||||
hostPath:
|
||||
path: /
|
||||
hostNetwork: true
|
||||
hostIPC: true
|
||||
hostPID: true
|
||||
restartPolicy: Never
|
||||
EOF
|
||||
)
|
||||
|
||||
deletePod() {
|
||||
kubectl delete $pod --wait=false
|
||||
}
|
||||
trap deletePod EXIT
|
||||
|
||||
echo "Created $pod"
|
||||
echo "Waiting for container to start..."
|
||||
kubectl wait --for=condition=Ready $pod >/dev/null
|
||||
kubectl attach -it $pod -c ssh-node
|
||||
|
||||
}
|
||||
|
||||
ssh_pod() {
|
||||
# TODO: improve this
|
||||
if [ "$1" == "" ]; then
|
||||
echo "Pod name must be specified."
|
||||
exit 1
|
||||
fi
|
||||
kubectl exec -it "$@" bash || (
|
||||
echo "Running bash in pod failed; trying with sh"
|
||||
kubectl exec -it "$@" sh
|
||||
)
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
echo "Provider-agnostic way of opening a remote shell to a Kubernetes node."
|
||||
echo
|
||||
echo "Enables you to access a node even when it doesn't run an SSH server or"
|
||||
echo "when you don't have the required credentials. Also, the way you log in"
|
||||
echo "is always the same, regardless of what provides the Kubernetes cluster"
|
||||
echo "(e.g. Minikube, Kind, Docker Desktop, GKE, AKS, EKS, ...)"
|
||||
echo
|
||||
echo "You must have cluster-admin rights to use this plugin."
|
||||
echo
|
||||
echo "The primary focus of this plugin is to provide access to nodes, but it"
|
||||
echo "also provides a quick way of running a shell inside a pod."
|
||||
echo
|
||||
echo "Examples: "
|
||||
echo " # Open a shell to node of a single-node cluster (e.g. Docker Desktop)"
|
||||
echo " kubectl ssh node"
|
||||
echo
|
||||
echo " # Open a shell to node of a multi-node cluster (e.g. GKE)"
|
||||
echo " kubectl ssh node my-worker-node-1"
|
||||
echo
|
||||
echo " # Open a shell to a pod"
|
||||
echo " kubectl ssh pod my-pod"
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo " kubectl ssh node [nodeName]"
|
||||
echo " kubectl ssh pod [podName] [-n namespace] [-c container]"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ "$1" == "--help" ]; then
|
||||
print_usage
|
||||
fi
|
||||
|
||||
if [[ "$1" == node/* ]]; then
|
||||
ssh_node ${1:5}
|
||||
elif [ "$1" == "node" ]; then
|
||||
ssh_node $2
|
||||
elif [[ "$1" == pod/* ]]; then
|
||||
ssh_pod "$@"
|
||||
elif [ "$1" == "pod" ]; then
|
||||
shift
|
||||
ssh_pod "$@"
|
||||
else
|
||||
print_usage
|
||||
fi
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
first=$1
|
||||
shift
|
||||
|
||||
fly -c "fly.${first}.toml" $@
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
nordvpn login --callback "$1"
|
|
@ -0,0 +1,367 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# OpenAI CLI v2.2.2
|
||||
# Created by @janlay
|
||||
#
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# openai-cli accepts various exported environment variables:
|
||||
# OPENAI_API_KEY : OpenAI's API key
|
||||
# OPENAI_API_ENDPOINT : Custom API endpoint
|
||||
# OPENAI_MAX_TOKENS : Maximum number of tokens to use
|
||||
# OPENAI_CHAT_MODEL : ChatGPT model
|
||||
# OPENAI_DATA_DIR : Directory to store data
|
||||
OPENAI_API_ENDPOINT="${OPENAI_API_ENDPOINT:-https://api.openai.com}"
|
||||
OPENAI_API_KEY="${OPENAI_API_KEY:-sk-proj-Y9WpJ6RxNUgF0qqOrU8uT3BlbkFJgeRmt7zldRdiV1WrxC8G}"
|
||||
OPENAI_MAX_TOKENS="${OPENAI_MAX_TOKENS:-2000}"
|
||||
OPENAI_CHAT_MODEL="${OPENAI_CHAT_MODEL:-gpt-4-turbo}"
|
||||
declare _config_dir="${OPENAI_DATA_DIR:-$XDG_CONFIG_HOME}"
|
||||
OPENAI_DATA_DIR="${_config_dir:-$HOME/.openai}"
|
||||
|
||||
# defaults
|
||||
readonly _app_name=openai _app_version=2.2.2
|
||||
readonly default_api_version=1 default_api_name=chat/completions default_model="$OPENAI_CHAT_MODEL" default_topic=General
|
||||
|
||||
declare -i chat_mode=0 dry_run=0
|
||||
declare tokens_file="$OPENAI_DATA_DIR/total_tokens" api_version=$default_api_version api_name=$default_api_name topic=$default_topic
|
||||
declare dump_file dumped_file data_file temp_dir rest_args prompt_file prompt
|
||||
|
||||
trap cleanup EXIT
|
||||
cleanup() {
|
||||
if [ -d "$temp_dir" ]; then
|
||||
rm -rf -- "$temp_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
raise_error() {
|
||||
[ "$2" = 0 ] || echo -n "$_app_name: " >&2
|
||||
echo -e "$1" >&2
|
||||
exit "${2:-1}"
|
||||
}
|
||||
|
||||
load_conversation() {
|
||||
[ -f "$data_file" ] && cat "$data_file" || echo '{}'
|
||||
}
|
||||
|
||||
update_conversation() {
|
||||
local entry="$2" data
|
||||
[[ $entry == \{* ]] || entry=$(jq -n --arg content "$entry" '{$content}')
|
||||
entry=$(jq --arg role "$1" '. += {$role}' <<<"$entry")
|
||||
data=$(load_conversation)
|
||||
jq --argjson item "$entry" '.messages += [$item]' <<<"$data" >"$data_file"
|
||||
}
|
||||
|
||||
save_tokens() {
|
||||
local data num="$1"
|
||||
[ -f "$data_file" ] && {
|
||||
data=$(load_conversation)
|
||||
jq --argjson tokens "$num" '.total_tokens += $tokens' <<<"$data" >"$data_file"
|
||||
}
|
||||
|
||||
data=0
|
||||
[ -f "$tokens_file" ] && data=$(cat "$tokens_file")
|
||||
echo "$((data + num))" >"$tokens_file"
|
||||
}
|
||||
|
||||
read_prompt() {
|
||||
# read prompt from args first
|
||||
local word accepts_props=1 props='{}' real_prompt
|
||||
if [ ${#rest_args[@]} -gt 0 ]; then
|
||||
# read file $prompt_file word by word, and extract words starting with '+'
|
||||
for word in "${rest_args[@]}"; do
|
||||
if [ $accepts_props -eq 1 ] && [ "${word:0:1}" = '+' ]; then
|
||||
word="${word:1}"
|
||||
# determine value's type for jq
|
||||
local options=(--arg key "${word%%=*}") value="${word#*=}" arg=--arg
|
||||
[[ $value =~ ^[+-]?\ ?[0-9.]+$ || $value = true || $value = false || $value == [\[\{]* ]] && arg=--argjson
|
||||
options+=("$arg" value "$value")
|
||||
props=$(jq "${options[@]}" '.[$key] = $value' <<<"$props")
|
||||
else
|
||||
real_prompt="$real_prompt $word"
|
||||
accepts_props=0
|
||||
fi
|
||||
done
|
||||
[ -n "$props" ] && echo "$props" >"$temp_dir/props"
|
||||
fi
|
||||
|
||||
if [ -n "$real_prompt" ]; then
|
||||
[ -n "$prompt_file" ] && echo "* Prompt file \`$prompt_file' will be ignored as the prompt parameters are provided." >&2
|
||||
echo -n "${real_prompt:1}" >"$temp_dir/prompt"
|
||||
elif [ -n "$prompt_file" ]; then
|
||||
[ -f "$prompt_file" ] || raise_error "File not found: $prompt_file." 3
|
||||
[[ -s $prompt_file ]] || raise_error "Empty file: $prompt_file." 4
|
||||
fi
|
||||
}
|
||||
|
||||
openai_models() {
|
||||
call_api | jq
|
||||
}
|
||||
|
||||
openai_moderations() {
|
||||
local prop_file="$temp_dir/props" payload="{\"model\": \"text-moderation-latest\"}"
|
||||
|
||||
# overwrite default properties with user's
|
||||
read_prompt
|
||||
[ -f "$prop_file" ] && payload=$(jq -n --argjson payload "$payload" '$payload | . += input' <"$prop_file")
|
||||
|
||||
# append user's prompt to messages
|
||||
local payload_file="$temp_dir/payload" input_file="$temp_dir/prompt"
|
||||
[ -f "$input_file" ] || input_file="${prompt_file:-/dev/stdin}"
|
||||
jq -Rs -cn --argjson payload "$payload" '$payload | .input = input' "$input_file" >"$payload_file"
|
||||
|
||||
call_api | jq -c '.results[]'
|
||||
}
|
||||
|
||||
openai_images_generations() {
|
||||
local prop_file="$temp_dir/props" payload="{\"n\": 1, \"size\": \"1024x1024\"}"
|
||||
|
||||
# overwrite default properties with user's
|
||||
read_prompt
|
||||
[ -f "$prop_file" ] && payload=$(jq -n --argjson payload "$payload" '$payload | . += input | . += {response_format: "url"}' <"$prop_file")
|
||||
|
||||
# append user's prompt to messages
|
||||
local payload_file="$temp_dir/payload" input_file="$temp_dir/prompt"
|
||||
[ -f "$input_file" ] || input_file="${prompt_file:-/dev/stdin}"
|
||||
jq -Rs -cn --argjson payload "$payload" '$payload | .prompt = input' "$input_file" >"$payload_file"
|
||||
|
||||
call_api | jq -r '.data[].url'
|
||||
}
|
||||
|
||||
openai_embeddings() {
|
||||
local prop_file="$temp_dir/props" payload="{\"model\": \"text-embedding-ada-002\"}"
|
||||
|
||||
# overwrite default properties with user's
|
||||
read_prompt
|
||||
[ -f "$prop_file" ] && payload=$(jq -n --argjson payload "$payload" '$payload | . += input' <"$prop_file")
|
||||
|
||||
# append user's prompt to messages
|
||||
local payload_file="$temp_dir/payload" input_file="$temp_dir/prompt"
|
||||
[ -f "$input_file" ] || input_file="${prompt_file:-/dev/stdin}"
|
||||
jq -Rs -cn --argjson payload "$payload" '$payload | .input = input' "$input_file" >"$payload_file"
|
||||
|
||||
call_api | jq -c
|
||||
}
|
||||
|
||||
openai_chat_completions() {
|
||||
[ -n "$dumped_file" ] || {
|
||||
local prop_file="$temp_dir/props" payload="{\"model\": \"$default_model\", \"stream\": true, \"temperature\": 0.5, \"max_tokens\": $OPENAI_MAX_TOKENS}"
|
||||
|
||||
# overwrite default properties with user's
|
||||
read_prompt
|
||||
[ -f "$prop_file" ] && {
|
||||
payload=$(jq -n --argjson payload "$payload" '$payload | . += input | . += {messages: []}' <"$prop_file")
|
||||
}
|
||||
|
||||
local data
|
||||
data=$(load_conversation | jq .messages)
|
||||
[ "$topic" != "$default_topic" ] && {
|
||||
if [ $chat_mode -eq 1 ]; then
|
||||
# load all messages for chat mode
|
||||
payload=$(jq --argjson messages "$data" 'setpath(["messages"]; $messages)' <<<"$payload")
|
||||
else
|
||||
# load only first message for non-chat mode
|
||||
payload=$(jq --argjson messages "$data" 'setpath(["messages"]; [$messages[0]])' <<<"$payload")
|
||||
fi
|
||||
}
|
||||
# append user's prompt to messages
|
||||
local payload_file="$temp_dir/payload" input_file="$temp_dir/prompt"
|
||||
[ -f "$input_file" ] || input_file="${prompt_file:-/dev/stdin}"
|
||||
jq -Rs -cn --argjson payload "$payload" '$payload | .messages += [{role: "user", content: input}]' "$input_file" >"$payload_file"
|
||||
}
|
||||
|
||||
local chunk reason text role fn_name
|
||||
call_api | while read -r chunk; do
|
||||
[ -z "$chunk" ] && continue
|
||||
chunk=$(cut -d: -f2- <<<"$chunk" | jq '.choices[0]')
|
||||
reason=$(jq -r '.finish_reason // empty' <<<"$chunk")
|
||||
[[ $reason = stop || $reason = function_call ]] && break
|
||||
[ -n "$reason" ] && raise_error "API error: $reason" 10
|
||||
|
||||
# get role and function info from the first chunk
|
||||
[ -z "$role" ] && {
|
||||
role=$(jq -r '.delta.role // empty' <<<"$chunk")
|
||||
fn_name=$(jq -r '.delta.function_call.name // empty' <<<"$chunk")
|
||||
}
|
||||
|
||||
# workaround: https://stackoverflow.com/a/15184414
|
||||
chunk=$(
|
||||
jq -r '.delta | .function_call.arguments // .content // empty' <<<"$chunk"
|
||||
printf x
|
||||
)
|
||||
# ensure chunk is not empty
|
||||
[ ${#chunk} -ge 2 ] || continue
|
||||
|
||||
chunk="${chunk:0:${#chunk}-2}"
|
||||
text="$text$chunk"
|
||||
echo -n "$chunk"
|
||||
done
|
||||
|
||||
# append response to topic file for chat mode
|
||||
[ "$chat_mode" -eq 1 ] && {
|
||||
[ -n "$fn_name" ] && text=$(jq -n --arg name "$fn_name" --argjson arguments "${text:-\{\}}" '{function_call: {$name, $arguments}}')
|
||||
|
||||
update_conversation user "$prompt"
|
||||
update_conversation "$role" "$text"
|
||||
}
|
||||
echo
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2120
|
||||
call_api() {
|
||||
# return dumped file if specified
|
||||
[ -n "$dumped_file" ] && {
|
||||
cat "$dumped_file"
|
||||
return
|
||||
}
|
||||
|
||||
local url="$OPENAI_API_ENDPOINT/v$api_version/$api_name" auth="Bearer $OPENAI_API_KEY"
|
||||
|
||||
# dry-run mode
|
||||
[ "$dry_run" -eq 1 ] && {
|
||||
echo "Dry-run mode, no API calls made."
|
||||
echo -e "\nRequest URL:\n--------------\n$url"
|
||||
echo -en "\nAuthorization:\n--------------\n"
|
||||
sed -E 's/(sk-.{3}).{41}/\1****/' <<<"$auth"
|
||||
[ -n "$payload_file" ] && {
|
||||
echo -e "\nPayload:\n--------------"
|
||||
jq <"$payload_file"
|
||||
}
|
||||
exit 0
|
||||
} >&2
|
||||
|
||||
local args=("$url" --no-buffer -fsSL -H 'Content-Type: application/json' -H "Authorization: $auth")
|
||||
[ -n "$payload_file" ] && args+=(-d @"$payload_file")
|
||||
[ $# -gt 0 ] && args+=("$@")
|
||||
|
||||
[ -n "$dump_file" ] && args+=(-o "$dump_file")
|
||||
curl "${args[@]}"
|
||||
[ -z "$dump_file" ] || exit 0
|
||||
}
|
||||
|
||||
create_topic() {
|
||||
update_conversation system "${rest_args[*]}"
|
||||
raise_error "Topic '$topic' created with initial prompt '${rest_args[*]}'" 0
|
||||
}
|
||||
|
||||
usage() {
|
||||
raise_error "OpenAI Client v$_app_version
|
||||
|
||||
SYNOPSIS
|
||||
ABSTRACT
|
||||
$_app_name [-n] [-a api_name] [-v api_version] [-o dump_file] [INPUT...]
|
||||
$_app_name -i dumped_file
|
||||
|
||||
DEFAULT_API (v$default_api_version/$default_api_name)
|
||||
$_app_name [-c] [+property=value...] [@TOPIC] [-f file | prompt ...]
|
||||
prompt
|
||||
Prompt string for the request to OpenAI API. This can consist of multiple
|
||||
arguments, which are considered to be separated by spaces.
|
||||
-f file
|
||||
A file to be read as prompt. If file is - or neither this parameter nor a prompt
|
||||
is specified, read from standard input.
|
||||
-c
|
||||
Continues the topic, the default topic is '$default_topic'.
|
||||
property=value
|
||||
Overwrites default properties in payload. Prepend a plus sign '+' before property=value.
|
||||
eg: +model=gpt-3.5-turbo-0301, +stream=false
|
||||
|
||||
TOPICS
|
||||
Topic starts with an at sign '@'.
|
||||
To create new topic, use \`$_app_name @new_topic initial prompt'
|
||||
|
||||
OTHER APIS
|
||||
$_app_name -a models
|
||||
|
||||
GLOBAL OPTIONS
|
||||
Global options apply to all APIs.
|
||||
-v version
|
||||
API version, default is '$default_api_version'.
|
||||
-a name
|
||||
API name, default is '$default_api_name'.
|
||||
-n
|
||||
Dry-run mode, don't call API.
|
||||
-o filename
|
||||
Dumps API response to a file and exits.
|
||||
-i filename
|
||||
Uses specified dumped file instead of requesting API.
|
||||
Any request-related arguments and user input are ignored.
|
||||
|
||||
--
|
||||
Ignores rest of arguments, useful when unquoted prompt consists of '-'.
|
||||
|
||||
-h
|
||||
Shows this help" 0
|
||||
}
|
||||
|
||||
parse() {
|
||||
local opt
|
||||
while getopts 'v:a:f:i:o:cnh' opt; do
|
||||
case "$opt" in
|
||||
c)
|
||||
chat_mode=1
|
||||
;;
|
||||
v)
|
||||
api_version="$OPTARG"
|
||||
;;
|
||||
a)
|
||||
api_name="$OPTARG"
|
||||
;;
|
||||
f)
|
||||
prompt_file="$OPTARG"
|
||||
[ "$prompt_file" = - ] && prompt_file=
|
||||
;;
|
||||
n)
|
||||
dry_run=1
|
||||
;;
|
||||
i)
|
||||
dumped_file="$OPTARG"
|
||||
;;
|
||||
o)
|
||||
dump_file="$OPTARG"
|
||||
;;
|
||||
h | ?)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND - 1))"
|
||||
|
||||
# extract the leading topic
|
||||
[[ "$1" =~ ^@ ]] && {
|
||||
topic="${1#@}"
|
||||
shift
|
||||
}
|
||||
|
||||
[ $chat_mode -eq 0 ] || {
|
||||
[[ -n $topic && $topic != "$default_topic" ]] || raise_error 'Topic is required for chatting.' 2
|
||||
}
|
||||
|
||||
rest_args=("$@")
|
||||
}
|
||||
|
||||
check_bin() {
|
||||
command -v "$1" >/dev/null || raise_error "$1 not found. Use package manager (Homebrew, apt-get etc.) to install it." "${2:-1}"
|
||||
}
|
||||
|
||||
main() {
|
||||
parse "$@"
|
||||
check_bin jq 10
|
||||
|
||||
mkdir -p "$OPENAI_DATA_DIR"
|
||||
data_file="$OPENAI_DATA_DIR/$topic.json"
|
||||
temp_dir=$(mktemp -d)
|
||||
|
||||
if [[ $topic == "$default_topic" || -f "$data_file" ]]; then
|
||||
[ -z "$OPENAI_API_KEY" ] && raise_error 'OpenAI API key is required.' 11
|
||||
|
||||
local fn="openai_${api_name//\//_}"
|
||||
[ "$(type -t "$fn")" = function ] || raise_error "API '$api_name' is not available." 12
|
||||
"$fn"
|
||||
else
|
||||
[ ${#rest_args[@]} -gt 0 ] || raise_error "Prompt for new topic is required" 13
|
||||
create_topic
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Usage:
|
||||
# proton program.exe
|
||||
#
|
||||
# Example Env Vars:
|
||||
# PROTONPREFIX="$HOME/proton_316"
|
||||
# PROTONVERSION="Proton 3.16"
|
||||
|
||||
# Folder name of the Proton version found under "steamapps/common/".
|
||||
# proton_version="Proton - Experimental"
|
||||
proton_version="Proton 7.0"
|
||||
|
||||
# Path to installation directory of Steam.
|
||||
# Alternate path: "$HOME/.steam/steam"
|
||||
client_dir="$HOME/.steam/steam"
|
||||
|
||||
# Default data folder for Proton/WINE environment. Folder must exist.
|
||||
# If the environmental variable PROTONPREFIX is set, it will overwrite env_dir.
|
||||
mkdir -p "$HOME/.proton/$proton_version"
|
||||
env_dir="$HOME/.proton/$proton_version"
|
||||
WINEPREFIX=protontricks
|
||||
|
||||
# Proton modes to run
|
||||
# run = start target app
|
||||
# waitforexitandrun = wait for wineserver to shut down
|
||||
# getcompatpath = linux -> windows path
|
||||
# getnativepath = windows -> linux path
|
||||
mode=run
|
||||
|
||||
# ENVIRONMENTAL VARIABLES
|
||||
if [ -n "${PROTONPREFIX+1}" ]
|
||||
then
|
||||
env_dir=$PROTONPREFIX
|
||||
fi
|
||||
|
||||
if [ -n "${PROTONVERSION+1}" ]
|
||||
then
|
||||
proton_version=$PROTONVERSION
|
||||
fi
|
||||
|
||||
# EXECUTE
|
||||
export STEAM_COMPAT_CLIENT_INSTALL_PATH=$client_dir
|
||||
export STEAM_COMPAT_DATA_PATH=$env_dir
|
||||
"$client_dir/steamapps/common/$proton_version/proton" $mode $*
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
echo "use tool ruplacer instead"
|
||||
|
||||
echo "eget your-tools/ruplacer"
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/zsh
|
||||
|
||||
ROOT_PREFIX="${REPO_ROOT_DIR:-$HOME/repo}"
|
||||
GIT_USER="${REPO_GIT_USER:-git}"
|
||||
|
||||
clean_path()
|
||||
{
|
||||
stripped=$1
|
||||
prefix="http://"
|
||||
stripped="${stripped#"$prefix"}"
|
||||
prefix="https://"
|
||||
stripped="${stripped#"$prefix"}"
|
||||
prefix="git@"
|
||||
stripped="${stripped#"$prefix"}"
|
||||
suffix=".git"
|
||||
stripped="${stripped%"$suffix"}"
|
||||
stripped=$(echo "$stripped" | sed -e "s/:/\//1")
|
||||
echo $stripped
|
||||
}
|
||||
|
||||
show_help()
|
||||
{
|
||||
printf "Usage: repo <get|goto> <repo>\n"
|
||||
}
|
||||
|
||||
do_get()
|
||||
{
|
||||
cleaned=$(clean_path $1)
|
||||
output_path="$ROOT_PREFIX/$cleaned"
|
||||
mkdir -p $output_path
|
||||
if [ ! -d $output_path/.git ]; then
|
||||
repourl=$(echo "$GIT_USER@$cleaned" | sed -e "s/\//:/1")
|
||||
git clone $repourl $output_path
|
||||
fi
|
||||
cd $output_path
|
||||
}
|
||||
|
||||
do_goto()
|
||||
{
|
||||
cleaned=$(clean_path $1)
|
||||
output_path="$ROOT_PREFIX/$cleaned"
|
||||
cd $output_path
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
'get' )
|
||||
do_get $2
|
||||
do_goto $2
|
||||
;;
|
||||
'go' | "goto")
|
||||
do_goto $2
|
||||
;;
|
||||
'help' | "-h"| "-help" | "--help")
|
||||
show_help
|
||||
esac
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
bspad hide
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
OUTPUT_FILENAME="/home/a/shots/$(date '+%Y-%m-%d_%H:%M:%S').png"
|
||||
scrot --freeze -F $OUTPUT_FILENAME -s
|
||||
curl https://put.gay -H "authorization: $PASTE_TOKEN" --silent -F "file=@$OUTPUT_FILENAME;headers=\"bucket: shot\"" | xclip -selection clipboard
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
scrot --freeze '/home/a/shots/%F_%T_$wx$h.png' -s -e 'xclip -selection clipboard -t image/png -i $f'
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/local/bin/gentee
|
||||
|
||||
const : URL = "https://wttr.in/"
|
||||
const : URLV2 = "https://v2.wttr.in/"
|
||||
const : URLV3 = "https://v3.wttr.in/"
|
||||
const : MOONURL = "https://wttr.in/moon@"
|
||||
|
||||
func dirs() arr.str {
|
||||
arr.str res = {
|
||||
GetEnv("HOME")+"/.config/wttr/default-city.txt",
|
||||
GetEnv("HOME")+"/.wttr",
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func help() str {
|
||||
return Format(`
|
||||
Usage: wttr <region>
|
||||
-v2
|
||||
Use v2 (%s)
|
||||
-v3
|
||||
Use v3 (%s)
|
||||
-m
|
||||
display moon (%s)
|
||||
-c
|
||||
Use metric units
|
||||
-f
|
||||
Use imperial units
|
||||
-t -today
|
||||
Display today's weather
|
||||
`,
|
||||
URLV2,
|
||||
URLV3,
|
||||
MOONURL,
|
||||
)
|
||||
}
|
||||
|
||||
func request(str url) str {
|
||||
map empty
|
||||
map headers = {"User-Agent":"curl/7.87"}
|
||||
return HTTPRequest(url, "GET", empty, headers)
|
||||
}
|
||||
|
||||
run {
|
||||
if IsArg("h") || IsArg("help") {
|
||||
Println(help())
|
||||
return
|
||||
}
|
||||
str loc = Arg("")
|
||||
str url = URL
|
||||
for fl in dirs() {
|
||||
if ExistFile(fl): loc = TrimSpace(ReadFile(fl)); break;
|
||||
}
|
||||
if IsArg("v2"): url = URLV2
|
||||
if IsArg("v3"): url = URLV3
|
||||
if IsArg("m"): url = MOONURL
|
||||
switch Arg("")
|
||||
case "":
|
||||
default: loc = Arg("")
|
||||
switch loc
|
||||
case "": url = url + "?"
|
||||
default: url = url + loc +"?"
|
||||
if IsArg("c"): url = url + "&m"
|
||||
if IsArg("f"): url = url + "&u"
|
||||
if (IsArg("t")||IsArg("today")): url = url + "&1n"
|
||||
//Print(request(url))
|
||||
Run(`head`,"-n","-1", stdin: buf(request(url)))
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
yadm add -u :
|
||||
yadm commit -m "sync"
|
||||
yadm push
|
Loading…
Reference in New Issue