diff --git a/.bruno/LocalAI Test Requests/Sound Generation/musicgen.bru b/.bruno/LocalAI Test Requests/Sound Generation/musicgen.bru new file mode 100644 index 0000000000000000000000000000000000000000..471756f53e07bb86b780915e3da6b15236f94c64 --- /dev/null +++ b/.bruno/LocalAI Test Requests/Sound Generation/musicgen.bru @@ -0,0 +1,23 @@ +meta { + name: musicgen + type: http + seq: 1 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/v1/sound-generation + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model_id": "facebook/musicgen-small", + "text": "Exciting 80s Newscast Interstitial", + "duration_seconds": 8 + } +} diff --git a/.bruno/LocalAI Test Requests/backend monitor/backend monitor.bru b/.bruno/LocalAI Test Requests/backend monitor/backend monitor.bru new file mode 100644 index 0000000000000000000000000000000000000000..51e3771ac57b3125b129c9b762279c778992f285 --- /dev/null +++ b/.bruno/LocalAI Test Requests/backend monitor/backend monitor.bru @@ -0,0 +1,17 @@ +meta { + name: backend monitor + type: http + seq: 4 +} + +get { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/backend/monitor + body: json + auth: none +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}" + } +} diff --git a/.bruno/LocalAI Test Requests/backend monitor/backend-shutdown.bru b/.bruno/LocalAI Test Requests/backend monitor/backend-shutdown.bru new file mode 100644 index 0000000000000000000000000000000000000000..f75f259a0194ddd3df0e6b6865c48d30f2088ad2 --- /dev/null +++ b/.bruno/LocalAI Test Requests/backend monitor/backend-shutdown.bru @@ -0,0 +1,21 @@ +meta { + name: backend-shutdown + type: http + seq: 3 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/backend/shutdown + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}" + } +} diff --git a/.bruno/LocalAI Test Requests/bruno.json b/.bruno/LocalAI Test Requests/bruno.json new file mode 100644 index 0000000000000000000000000000000000000000..9491e3a55b81568c07cb428e6946a1e3fd565aa9 --- /dev/null +++ b/.bruno/LocalAI Test Requests/bruno.json @@ -0,0 +1,5 @@ +{ + "version": "1", + "name": "LocalAI Test Requests", + "type": "collection" +} \ No newline at end of file diff --git a/.bruno/LocalAI Test Requests/environments/localhost.bru b/.bruno/LocalAI Test Requests/environments/localhost.bru new file mode 100644 index 0000000000000000000000000000000000000000..fb97edb2e3e87a626d1faba200838cecd2610c83 --- /dev/null +++ b/.bruno/LocalAI Test Requests/environments/localhost.bru @@ -0,0 +1,6 @@ +vars { + HOST: localhost + PORT: 8080 + DEFAULT_MODEL: gpt-3.5-turbo + PROTOCOL: http:// +} diff --git a/.bruno/LocalAI Test Requests/get models list.bru b/.bruno/LocalAI Test Requests/get models list.bru new file mode 100644 index 0000000000000000000000000000000000000000..4bf1628fc6d98fbbb41e4fd8800fdae22e3b4ed8 --- /dev/null +++ b/.bruno/LocalAI Test Requests/get models list.bru @@ -0,0 +1,11 @@ +meta { + name: get models list + type: http + seq: 2 +} + +get { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models + body: none + auth: none +} diff --git a/.bruno/LocalAI Test Requests/image generation/Generate image.bru b/.bruno/LocalAI Test Requests/image generation/Generate image.bru new file mode 100644 index 0000000000000000000000000000000000000000..37d350caab77d56ed3d4942a1e8c82017343d5bc --- /dev/null +++ b/.bruno/LocalAI Test Requests/image generation/Generate image.bru @@ -0,0 +1,25 @@ +meta { + name: Generate image + type: http + seq: 1 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/v1/images/generations + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "prompt": "|", + "model": "model-name", + "step": 51, + "size": "1024x1024", + "image": "" + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/-completions.bru b/.bruno/LocalAI Test Requests/llm text/-completions.bru new file mode 100644 index 0000000000000000000000000000000000000000..6e16a24458090a88e7b8201048797b452ed84be7 --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/-completions.bru @@ -0,0 +1,24 @@ +meta { + name: -completions + type: http + seq: 4 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/completions + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "prompt": "function downloadFile(string url, string outputPath) {", + "max_tokens": 256, + "temperature": 0.5 + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/-edits.bru b/.bruno/LocalAI Test Requests/llm text/-edits.bru new file mode 100644 index 0000000000000000000000000000000000000000..838afa27b987f8a813c7e639db3251a886157641 --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/-edits.bru @@ -0,0 +1,23 @@ +meta { + name: -edits + type: http + seq: 5 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/edits + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "input": "What day of the wek is it?", + "instruction": "Fix the spelling mistakes" + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/-embeddings.bru b/.bruno/LocalAI Test Requests/llm text/-embeddings.bru new file mode 100644 index 0000000000000000000000000000000000000000..a3045df255b24c87d7689520ab84911a0f778f85 --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/-embeddings.bru @@ -0,0 +1,22 @@ +meta { + name: -embeddings + type: http + seq: 6 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/embeddings + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "input": "A STRANGE GAME.\nTHE ONLY WINNING MOVE IS NOT TO PLAY.\n\nHOW ABOUT A NICE GAME OF CHESS?" + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/chat/chat completion -simple- 1 message-.bru b/.bruno/LocalAI Test Requests/llm text/chat/chat completion -simple- 1 message-.bru new file mode 100644 index 0000000000000000000000000000000000000000..fd08aeeeeab102124607a0458650cc1a2658557c --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/chat/chat completion -simple- 1 message-.bru @@ -0,0 +1,30 @@ +meta { + name: chat completion -simple- 1 message- + type: http + seq: 4 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/chat/completions + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "messages": [ + { + "role": "user", + "content": "How could one use friction to cook an egg?" + } + ], + "max_tokens": 256, + "temperature": 0.2, + "grammar": "" + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -long-.bru b/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -long-.bru new file mode 100644 index 0000000000000000000000000000000000000000..5d9a49a094ae109f9e415dd21edee03faa1af280 --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -long-.bru @@ -0,0 +1,29 @@ +meta { + name: chat-completions -long- + type: http + seq: 5 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/chat/completions + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "messages": [{"role": "system", "content": "You are a helpful, intelligent pirate assistant. Always answer as helpfully as possible, while being a pirate and using pirate language. If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information."}, + {"role": "user", "content": "How could one use electricity to cook an egg?"}, + {"role": "assistant", + "content": "Shiver me timbers! Using electricity to cook an egg? Well, matey, I reckon that be a right curious idea! *adjusts spectacles* Now, I ain't sure if this be possible, but I'll do me best to help ye out.\n\nFirst things first, ye gotta understand that electricity be a powerful force, and it can't just cook an egg on its own. Ye see, electricity be like a mighty wind that can make things happen, but it needs somethin' to work with. So, if ye want to use electricity to cook an egg, ye gotta find a way to harness that power and make it do the cookin'.\n\nNow, I know what ye might be thinkin': \"How do I harness the power of electricity to cook an egg?\" Well, matey, there be a few ways to do it. One way be to use a special device called an \"electric frying pan.\" This be a pan that has a built-in heating element that gets hot when ye plug it into a wall socket. When the element gets hot, ye can crack an egg into the pan and watch as it cook" + }, + {"role": "user", "content": "I don't have one of those, just a raw wire and plenty of power! How do we get it done?"}], + "max_tokens": 1024, + "temperature": 0.5 + } +} diff --git a/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -stream-.bru b/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -stream-.bru new file mode 100644 index 0000000000000000000000000000000000000000..cf0539fafcdc56fe9f195ab89acb73d3038a7c6d --- /dev/null +++ b/.bruno/LocalAI Test Requests/llm text/chat/chat-completions -stream-.bru @@ -0,0 +1,25 @@ +meta { + name: chat-completions -stream- + type: http + seq: 6 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/chat/completions + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "messages": [{"role": "user", "content": "Explain how I can set sail on the ocean using only power generated by seagulls?"}], + "max_tokens": 256, + "temperature": 0.9, + "stream": true + } +} diff --git a/.bruno/LocalAI Test Requests/model gallery/add model gallery.bru b/.bruno/LocalAI Test Requests/model gallery/add model gallery.bru new file mode 100644 index 0000000000000000000000000000000000000000..1463160f011600599759728d082adca51004e6cb --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/add model gallery.bru @@ -0,0 +1,22 @@ +meta { + name: add model gallery + type: http + seq: 10 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/galleries + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "url": "file:///home/dave/projects/model-gallery/huggingface/TheBloke__CodeLlama-7B-Instruct-GGML.yaml", + "name": "test" + } +} diff --git a/.bruno/LocalAI Test Requests/model gallery/delete model gallery.bru b/.bruno/LocalAI Test Requests/model gallery/delete model gallery.bru new file mode 100644 index 0000000000000000000000000000000000000000..3e211aa677e696cfda1fc25e7d759c02d278e8c9 --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/delete model gallery.bru @@ -0,0 +1,21 @@ +meta { + name: delete model gallery + type: http + seq: 11 +} + +delete { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/galleries + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "name": "test" + } +} diff --git a/.bruno/LocalAI Test Requests/model gallery/list MODELS in galleries.bru b/.bruno/LocalAI Test Requests/model gallery/list MODELS in galleries.bru new file mode 100644 index 0000000000000000000000000000000000000000..1d866f8a5b7ed4231f69d16faffcce61a2307736 --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/list MODELS in galleries.bru @@ -0,0 +1,11 @@ +meta { + name: list MODELS in galleries + type: http + seq: 7 +} + +get { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/available + body: none + auth: none +} diff --git a/.bruno/LocalAI Test Requests/model gallery/list model GALLERIES.bru b/.bruno/LocalAI Test Requests/model gallery/list model GALLERIES.bru new file mode 100644 index 0000000000000000000000000000000000000000..f766467266d95287faf96ac9403d1f073d50cb18 --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/list model GALLERIES.bru @@ -0,0 +1,11 @@ +meta { + name: list model GALLERIES + type: http + seq: 8 +} + +get { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/galleries + body: none + auth: none +} diff --git a/.bruno/LocalAI Test Requests/model gallery/model delete.bru b/.bruno/LocalAI Test Requests/model gallery/model delete.bru new file mode 100644 index 0000000000000000000000000000000000000000..b320dae35d361ab557cdd51d6259a1804cb26b70 --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/model delete.bru @@ -0,0 +1,11 @@ +meta { + name: model delete + type: http + seq: 7 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/galleries + body: none + auth: none +} diff --git a/.bruno/LocalAI Test Requests/model gallery/model gallery apply -gist-.bru b/.bruno/LocalAI Test Requests/model gallery/model gallery apply -gist-.bru new file mode 100644 index 0000000000000000000000000000000000000000..d94c75a20bf9e5b45e14658ac8e0ef867c20daea --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/model gallery apply -gist-.bru @@ -0,0 +1,21 @@ +meta { + name: model gallery apply -gist- + type: http + seq: 12 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/apply + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "id": "TheBloke__CodeLlama-7B-Instruct-GGML__codellama-7b-instruct.ggmlv3.Q2_K.bin" + } +} diff --git a/.bruno/LocalAI Test Requests/model gallery/model gallery apply.bru b/.bruno/LocalAI Test Requests/model gallery/model gallery apply.bru new file mode 100644 index 0000000000000000000000000000000000000000..aa308e1e984f4ccbed6057099027ea438773ef33 --- /dev/null +++ b/.bruno/LocalAI Test Requests/model gallery/model gallery apply.bru @@ -0,0 +1,22 @@ +meta { + name: model gallery apply + type: http + seq: 9 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/models/apply + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "id": "dave@TheBloke__CodeLlama-7B-Instruct-GGML__codellama-7b-instruct.ggmlv3.Q3_K_S.bin", + "name": "codellama7b" + } +} diff --git a/.bruno/LocalAI Test Requests/transcription/gb1.ogg b/.bruno/LocalAI Test Requests/transcription/gb1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..61f732a52c827b699283154f54de5df3ce466f3a --- /dev/null +++ b/.bruno/LocalAI Test Requests/transcription/gb1.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97a6384767e2fc3fb27c7593831aa19115d909fcdb85a1e389359ecc4b92a1e8 +size 1667662 diff --git a/.bruno/LocalAI Test Requests/transcription/transcribe.bru b/.bruno/LocalAI Test Requests/transcription/transcribe.bru new file mode 100644 index 0000000000000000000000000000000000000000..831aad90036a2f9d79ec94714943854abc672760 --- /dev/null +++ b/.bruno/LocalAI Test Requests/transcription/transcribe.bru @@ -0,0 +1,16 @@ +meta { + name: transcribe + type: http + seq: 1 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/v1/audio/transcriptions + body: multipartForm + auth: none +} + +body:multipart-form { + file: @file(transcription/gb1.ogg) + model: whisper-1 +} diff --git a/.bruno/LocalAI Test Requests/tts/-tts.bru b/.bruno/LocalAI Test Requests/tts/-tts.bru new file mode 100644 index 0000000000000000000000000000000000000000..643f2ace15443cb505d2b6393a63dc554b42e226 --- /dev/null +++ b/.bruno/LocalAI Test Requests/tts/-tts.bru @@ -0,0 +1,22 @@ +meta { + name: -tts + type: http + seq: 2 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/tts + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "model": "{{DEFAULT_MODEL}}", + "input": "A STRANGE GAME.\nTHE ONLY WINNING MOVE IS NOT TO PLAY.\n\nHOW ABOUT A NICE GAME OF CHESS?" + } +} diff --git a/.bruno/LocalAI Test Requests/tts/musicgen.bru b/.bruno/LocalAI Test Requests/tts/musicgen.bru new file mode 100644 index 0000000000000000000000000000000000000000..a720b8b1c780d380ccc15fae83de83d95426a1c8 --- /dev/null +++ b/.bruno/LocalAI Test Requests/tts/musicgen.bru @@ -0,0 +1,23 @@ +meta { + name: musicgen + type: http + seq: 2 +} + +post { + url: {{PROTOCOL}}{{HOST}}:{{PORT}}/tts + body: json + auth: none +} + +headers { + Content-Type: application/json +} + +body:json { + { + "backend": "transformers-musicgen", + "model": "facebook/musicgen-small", + "input": "80s Synths playing Jazz" + } +} diff --git a/.devcontainer-scripts/postcreate.sh b/.devcontainer-scripts/postcreate.sh new file mode 100644 index 0000000000000000000000000000000000000000..3f9035090a355a63c10b2590cb2b2fdd88ee04ac --- /dev/null +++ b/.devcontainer-scripts/postcreate.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +cd /workspace + +# Get the files into the volume without a bind mount +if [ ! -d ".git" ]; then + git clone https://github.com/mudler/LocalAI.git . +else + git fetch +fi + +echo "Standard Post-Create script completed." + +if [ -f "/devcontainer-customization/postcreate.sh" ]; then + echo "Launching customization postcreate.sh" + bash "/devcontainer-customization/postcreate.sh" +fi \ No newline at end of file diff --git a/.devcontainer-scripts/poststart.sh b/.devcontainer-scripts/poststart.sh new file mode 100644 index 0000000000000000000000000000000000000000..196e821dbd651bea6fded31a20b79c906c373078 --- /dev/null +++ b/.devcontainer-scripts/poststart.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd /workspace + +# Grab the pre-stashed backend assets to avoid build issues +cp -r /build/backend-assets /workspace/backend-assets + +# Ensures generated source files are present upon load +make prepare + +echo "Standard Post-Start script completed." + +if [ -f "/devcontainer-customization/poststart.sh" ]; then + echo "Launching customization poststart.sh" + bash "/devcontainer-customization/poststart.sh" +fi \ No newline at end of file diff --git a/.devcontainer-scripts/utils.sh b/.devcontainer-scripts/utils.sh new file mode 100644 index 0000000000000000000000000000000000000000..8416d43d5789a98fab714214022b2c747ff8ab23 --- /dev/null +++ b/.devcontainer-scripts/utils.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# This file contains some really simple functions that are useful when building up customization scripts. + + +# Checks if the git config has a user registered - and sets it up if not. +# +# Param 1: name +# Param 2: email +# +config_user() { + echo "Configuring git for $1 <$2>" + local gcn=$(git config --global user.name) + if [ -z "${gcn}" ]; then + echo "Setting up git user / remote" + git config --global user.name "$1" + git config --global user.email "$2" + + fi +} + +# Checks if the git remote is configured - and sets it up if not. Fetches either way. +# +# Param 1: remote name +# Param 2: remote url +# +config_remote() { + echo "Adding git remote and fetching $2 as $1" + local gr=$(git remote -v | grep $1) + if [ -z "${gr}" ]; then + git remote add $1 $2 + fi + git fetch $1 +} + +# Setup special .ssh files +# Prints out lines of text to make things pretty +# Param 1: bash array, filenames relative to the customization directory that should be copied to ~/.ssh +setup_ssh() { + echo "starting ~/.ssh directory setup..." + mkdir -p "${HOME}.ssh" + chmod 0700 "${HOME}/.ssh" + echo "-----" + local files=("$@") + for file in "${files[@]}" ; do + local cfile="/devcontainer-customization/${file}" + local hfile="${HOME}/.ssh/${file}" + if [ ! -f "${hfile}" ]; then + echo "copying \"${file}\"" + cp "${cfile}" "${hfile}" + chmod 600 "${hfile}" + fi + done + echo "~/.ssh directory setup complete!" +} diff --git a/.devcontainer/customization/README.md b/.devcontainer/customization/README.md new file mode 100644 index 0000000000000000000000000000000000000000..89eb48e8da99be0e6804ea3503f660a720fd494d --- /dev/null +++ b/.devcontainer/customization/README.md @@ -0,0 +1,25 @@ +Place any additional resources your environment requires in this directory + +Script hooks are currently called for: +`postcreate.sh` and `poststart.sh` + +If files with those names exist here, they will be called at the end of the normal script. + +This is a good place to set things like `git config --global user.name` are set - and to handle any other files that are mounted via this directory. + +To assist in doing so, `source /.devcontainer-scripts/utils.sh` will provide utility functions that may be useful - for example: + +``` +#!/bin/bash + +source "/.devcontainer-scripts/utils.sh" + +sshfiles=("config", "key.pub") + +setup_ssh "${sshfiles[@]}" + +config_user "YOUR NAME" "YOUR EMAIL" + +config_remote "REMOTE NAME" "REMOTE URL" + +``` \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000000000000000000000000000000..37c81ffc41da7915188ccf05e8db74badfed27ad --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.schema.json", + "name": "LocalAI", + "workspaceFolder": "/workspace", + "dockerComposeFile": [ "./docker-compose-devcontainer.yml" ], + "service": "api", + "shutdownAction": "stopCompose", + "customizations": { + "vscode": { + "extensions": [ + "golang.go", + "ms-vscode.makefile-tools", + "ms-azuretools.vscode-docker", + "ms-python.python", + "ms-python.debugpy", + "wayou.vscode-todo-highlight", + "waderyan.gitblame" + ] + } + }, + "forwardPorts": [8080, 3000], + "postCreateCommand": "bash /.devcontainer-scripts/postcreate.sh", + "postStartCommand": "bash /.devcontainer-scripts/poststart.sh" +} \ No newline at end of file diff --git a/.devcontainer/docker-compose-devcontainer.yml b/.devcontainer/docker-compose-devcontainer.yml new file mode 100644 index 0000000000000000000000000000000000000000..8795d64da169503ef17fcc6886557b873eddf3fb --- /dev/null +++ b/.devcontainer/docker-compose-devcontainer.yml @@ -0,0 +1,48 @@ +services: + api: + build: + context: .. + dockerfile: Dockerfile + target: devcontainer + args: + - FFMPEG=true + - IMAGE_TYPE=extras + - GO_TAGS=stablediffusion p2p tts + env_file: + - ../.env + ports: + - 8080:8080 + volumes: + - localai_workspace:/workspace + - ../models:/host-models + - ./customization:/devcontainer-customization + command: /bin/sh -c "while sleep 1000; do :; done" + cap_add: + - SYS_PTRACE + security_opt: + - seccomp:unconfined + prometheus: + image: prom/prometheus + container_name: prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - 9090:9090 + restart: unless-stopped + volumes: + - ./prometheus:/etc/prometheus + - prom_data:/prometheus + grafana: + image: grafana/grafana + container_name: grafana + ports: + - 3000:3000 + restart: unless-stopped + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=grafana + volumes: + - ./grafana:/etc/grafana/provisioning/datasources +volumes: + prom_data: + localai_workspace: \ No newline at end of file diff --git a/.devcontainer/grafana/datasource.yml b/.devcontainer/grafana/datasource.yml new file mode 100644 index 0000000000000000000000000000000000000000..1ed2fa3c2a28cc7193a341842bacbe40953a7c1d --- /dev/null +++ b/.devcontainer/grafana/datasource.yml @@ -0,0 +1,10 @@ + +apiVersion: 1 + +datasources: +- name: Prometheus + type: prometheus + url: http://prometheus:9090 + isDefault: true + access: proxy + editable: true diff --git a/.devcontainer/prometheus/prometheus.yml b/.devcontainer/prometheus/prometheus.yml new file mode 100644 index 0000000000000000000000000000000000000000..18c44da71447ad87832496ee321c88d84c6e5be0 --- /dev/null +++ b/.devcontainer/prometheus/prometheus.yml @@ -0,0 +1,21 @@ +global: + scrape_interval: 15s + scrape_timeout: 10s + evaluation_interval: 15s +alerting: + alertmanagers: + - static_configs: + - targets: [] + scheme: http + timeout: 10s + api_version: v1 +scrape_configs: +- job_name: prometheus + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /metrics + scheme: http + static_configs: + - targets: + - localhost:9090 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index dfdb8b771ce07609491fa2e83698969fd917a135..a10f3bed251ad5a4a3db7d411f25edc79d81cdd7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.sh text eol=lf +.bruno/LocalAI[[:space:]]Test[[:space:]]Requests/transcription/gb1.ogg filter=lfs diff=lfs merge=lfs -text diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000000000000000000000000000000000..0fc33f328016f5bab2b86ce98ff9d7a2067484ad --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: [mudler] +custom: +- https://www.buymeacoffee.com/mudler diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..36e22ced2a6345c527d8808d7710a3f887339b86 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug, unconfirmed, up-for-grabs +--- + + + +**LocalAI version:** + + +**Environment, CPU architecture, OS, and Version:** + + +**Describe the bug** + + +**To Reproduce** + + +**Expected behavior** + + +**Logs** + + +**Additional context** + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..acc65c80ddc9dbd7a3cd15738f8b13028b156e32 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Community Support + url: https://github.com/go-skynet/LocalAI/discussions + about: Please ask and answer questions here. + - name: Discord + url: https://discord.gg/uJAeKSAGDy + about: Join our community on Discord! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000000000000000000000000000000000..d3b2873b2c5e6660af541a22ac88dace41ae7bcc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement, up-for-grabs +--- + + + +**Is your feature request related to a problem? Please describe.** + + +**Describe the solution you'd like** + + +**Describe alternatives you've considered** + + +**Additional context** + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000000000000000000000000000000000..ec5e354c5740852dab276e85d0b53d04541d0923 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ +**Description** + +This PR fixes # + +**Notes for Reviewers** + + +**[Signed commits](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)** +- [ ] Yes, I signed my commits. + + \ No newline at end of file diff --git a/.github/bump_deps.sh b/.github/bump_deps.sh new file mode 100644 index 0000000000000000000000000000000000000000..66dea9a38ad21a51f0038edb68485caf2c56bb37 --- /dev/null +++ b/.github/bump_deps.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -xe +REPO=$1 +BRANCH=$2 +VAR=$3 + +LAST_COMMIT=$(curl -s -H "Accept: application/vnd.github.VERSION.sha" "https://api.github.com/repos/$REPO/commits/$BRANCH") + +# Read $VAR from Makefile (only first match) +set +e +CURRENT_COMMIT="$(grep -m1 "^$VAR?=" Makefile | cut -d'=' -f2)" +set -e + +sed -i Makefile -e "s/$VAR?=.*/$VAR?=$LAST_COMMIT/" + +if [ -z "$CURRENT_COMMIT" ]; then + echo "Could not find $VAR in Makefile." + exit 0 +fi + +echo "Changes: https://github.com/$REPO/compare/${CURRENT_COMMIT}..${LAST_COMMIT}" >> "${VAR}_message.txt" +echo "${LAST_COMMIT}" >> "${VAR}_commit.txt" \ No newline at end of file diff --git a/.github/bump_docs.sh b/.github/bump_docs.sh new file mode 100644 index 0000000000000000000000000000000000000000..e69d3824d27fcf4592cb095ab418c9115aae79f6 --- /dev/null +++ b/.github/bump_docs.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -xe +REPO=$1 + +LATEST_TAG=$(curl -s "https://api.github.com/repos/$REPO/releases/latest" | jq -r '.tag_name') + +cat <<< $(jq ".version = \"$LATEST_TAG\"" docs/data/version.json) > docs/data/version.json diff --git a/.github/check_and_update.py b/.github/check_and_update.py new file mode 100644 index 0000000000000000000000000000000000000000..704b658e67bf3caa60728ef6866b126e90831d28 --- /dev/null +++ b/.github/check_and_update.py @@ -0,0 +1,85 @@ +import hashlib +from huggingface_hub import hf_hub_download, get_paths_info +import requests +import sys +import os + +uri = sys.argv[1] +file_name = uri.split('/')[-1] + +# Function to parse the URI and determine download method +def parse_uri(uri): + if uri.startswith('huggingface://'): + repo_id = uri.split('://')[1] + return 'huggingface', repo_id.rsplit('/', 1)[0] + elif 'huggingface.co' in uri: + parts = uri.split('/resolve/') + if len(parts) > 1: + repo_path = parts[0].split('https://huggingface.co/')[-1] + return 'huggingface', repo_path + return 'direct', uri + +def calculate_sha256(file_path): + sha256_hash = hashlib.sha256() + with open(file_path, 'rb') as f: + for byte_block in iter(lambda: f.read(4096), b''): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + +def manual_safety_check_hf(repo_id): + scanResponse = requests.get('https://huggingface.co/api/models/' + repo_id + "/scan") + scan = scanResponse.json() + # Check if 'hasUnsafeFile' exists in the response + if 'hasUnsafeFile' in scan: + if scan['hasUnsafeFile']: + return scan + else: + return None + else: + return None + +download_type, repo_id_or_url = parse_uri(uri) + +new_checksum = None +file_path = None + +# Decide download method based on URI type +if download_type == 'huggingface': + # Check if the repo is flagged as dangerous by HF + hazard = manual_safety_check_hf(repo_id_or_url) + if hazard != None: + print(f'Error: HuggingFace has detected security problems for {repo_id_or_url}: {str(hazard)}', filename=file_name) + sys.exit(5) + # Use HF API to pull sha + for file in get_paths_info(repo_id_or_url, [file_name], repo_type='model'): + try: + new_checksum = file.lfs.sha256 + break + except Exception as e: + print(f'Error from Hugging Face Hub: {str(e)}', file=sys.stderr) + sys.exit(2) + if new_checksum is None: + try: + file_path = hf_hub_download(repo_id=repo_id_or_url, filename=file_name) + except Exception as e: + print(f'Error from Hugging Face Hub: {str(e)}', file=sys.stderr) + sys.exit(2) +else: + response = requests.get(repo_id_or_url) + if response.status_code == 200: + with open(file_name, 'wb') as f: + f.write(response.content) + file_path = file_name + elif response.status_code == 404: + print(f'File not found: {response.status_code}', file=sys.stderr) + sys.exit(2) + else: + print(f'Error downloading file: {response.status_code}', file=sys.stderr) + sys.exit(1) + +if new_checksum is None: + new_checksum = calculate_sha256(file_path) + print(new_checksum) + os.remove(file_path) +else: + print(new_checksum) diff --git a/.github/checksum_checker.sh b/.github/checksum_checker.sh new file mode 100644 index 0000000000000000000000000000000000000000..5cbd57f4a33b4093c61b2ebfab1248273f588b1b --- /dev/null +++ b/.github/checksum_checker.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# This scripts needs yq and huggingface_hub to be installed +# to install hugingface_hub run pip install huggingface_hub + +# Path to the input YAML file +input_yaml=$1 + +# Function to download file and check checksum using Python +function check_and_update_checksum() { + model_name="$1" + file_name="$2" + uri="$3" + old_checksum="$4" + idx="$5" + + # Download the file and calculate new checksum using Python + new_checksum=$(python3 ./.github/check_and_update.py $uri) + result=$? + + if [[ $result -eq 5 ]]; then + echo "Contaminated entry detected, deleting entry for $model_name..." + yq eval -i "del([$idx])" "$input_yaml" + return + fi + + if [[ "$new_checksum" == "" ]]; then + echo "Error calculating checksum for $file_name. Skipping..." + return + fi + + echo "Checksum for $file_name: $new_checksum" + + # Compare and update the YAML file if checksums do not match + + if [[ $result -eq 2 ]]; then + echo "File not found, deleting entry for $file_name..." + # yq eval -i "del(.[$idx].files[] | select(.filename == \"$file_name\"))" "$input_yaml" + elif [[ "$old_checksum" != "$new_checksum" ]]; then + echo "Checksum mismatch for $file_name. Updating..." + yq eval -i "del(.[$idx].files[] | select(.filename == \"$file_name\").sha256)" "$input_yaml" + yq eval -i "(.[$idx].files[] | select(.filename == \"$file_name\")).sha256 = \"$new_checksum\"" "$input_yaml" + elif [[ $result -ne 0 ]]; then + echo "Error downloading file $file_name. Skipping..." + else + echo "Checksum match for $file_name. No update needed." + fi +} + +# Read the YAML and process each file +len=$(yq eval '. | length' "$input_yaml") +for ((i=0; i<$len; i++)) +do + name=$(yq eval ".[$i].name" "$input_yaml") + files_len=$(yq eval ".[$i].files | length" "$input_yaml") + for ((j=0; j<$files_len; j++)) + do + filename=$(yq eval ".[$i].files[$j].filename" "$input_yaml") + uri=$(yq eval ".[$i].files[$j].uri" "$input_yaml") + checksum=$(yq eval ".[$i].files[$j].sha256" "$input_yaml") + echo "Checking model $name, file $filename. URI = $uri, Checksum = $checksum" + check_and_update_checksum "$name" "$filename" "$uri" "$checksum" "$i" + done +done diff --git a/.github/ci/modelslist.go b/.github/ci/modelslist.go new file mode 100644 index 0000000000000000000000000000000000000000..719cd094ae9dfeca130f84543c88dee215409798 --- /dev/null +++ b/.github/ci/modelslist.go @@ -0,0 +1,304 @@ +package main + +import ( + "fmt" + "html/template" + "io/ioutil" + "os" + + "github.com/microcosm-cc/bluemonday" + "gopkg.in/yaml.v3" +) + +var modelPageTemplate string = ` + + + + + + LocalAI models + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+

+ LocalAI model gallery list


+ +

+ + 🖼️ Available {{.AvailableModels}} models + +

+ +

+ Refer to the Model gallery for more information on how to use the models with LocalAI.
+ + You can install models with the CLI command local-ai models install . or by using the WebUI. +

+ + +
+ {{ range $_, $model := .Models }} +
+
+ {{ $icon := "https://upload.wikimedia.org/wikipedia/commons/6/65/No-Image-Placeholder.svg" }} + {{ if $model.Icon }} + {{ $icon = $model.Icon }} + {{ end }} +
+ {{$model.Name}} +
+
+
{{$model.Name}}
+ + +

{{ $model.Description }}

+ +
+
+ + + + + + + + +
+
+
+ {{ end }} + +
+
+
+ + + +
+ + + + +` + +type GalleryModel struct { + Name string `json:"name" yaml:"name"` + URLs []string `json:"urls" yaml:"urls"` + Icon string `json:"icon" yaml:"icon"` + Description string `json:"description" yaml:"description"` +} + +func main() { + // read the YAML file which contains the models + + f, err := ioutil.ReadFile(os.Args[1]) + if err != nil { + fmt.Println("Error reading file:", err) + return + } + + models := []*GalleryModel{} + err = yaml.Unmarshal(f, &models) + if err != nil { + // write to stderr + os.Stderr.WriteString("Error unmarshaling YAML: " + err.Error() + "\n") + return + } + + // Ensure that all arbitrary text content is sanitized before display + for i, m := range models { + models[i].Name = bluemonday.StrictPolicy().Sanitize(m.Name) + models[i].Description = bluemonday.StrictPolicy().Sanitize(m.Description) + } + + // render the template + data := struct { + Models []*GalleryModel + AvailableModels int + }{ + Models: models, + AvailableModels: len(models), + } + tmpl := template.Must(template.New("modelPage").Parse(modelPageTemplate)) + + err = tmpl.Execute(os.Stdout, data) + if err != nil { + fmt.Println("Error executing template:", err) + return + } +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000000000000000000000000000000..fcd6c88cb539226139967002ed9b9dad48a9b1f5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,135 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +version: 2 +updates: + - package-ecosystem: "gitsubmodule" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + ignore: + - dependency-name: "github.com/mudler/LocalAI/pkg/grpc/proto" + - package-ecosystem: "github-actions" + # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "weekly" + - package-ecosystem: "pip" + # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "weekly" + - package-ecosystem: "docker" + # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/autogptq" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/bark" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/common/template" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/coqui" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/diffusers" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/exllama" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/exllama2" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/mamba" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/openvoice" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/parler-tts" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/rerankers" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/sentencetransformers" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/transformers" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/transformers-musicgen" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/vall-e-x" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/backend/python/vllm" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/examples/chainlit" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/examples/functions" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/examples/langchain/langchainpy-localai-example" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/examples/langchain-chroma" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/examples/streamlit-bot" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/examples/k8sgpt" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/examples/kubernetes" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/examples/langchain" + schedule: + interval: "weekly" + - package-ecosystem: "gomod" + directory: "/examples/semantic-todo" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/examples/telegram-bot" + schedule: + interval: "weekly" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000000000000000000000000000000000..687a90d1e42a5d1ed642fe1c0bc049b454eac7d3 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,24 @@ +enhancements: + - head-branch: ['^feature', 'feature'] + +kind/documentation: +- any: + - changed-files: + - any-glob-to-any-file: 'docs/*' + - changed-files: + - any-glob-to-any-file: '*.md' + +area/ai-model: +- any: + - changed-files: + - any-glob-to-any-file: 'gallery/*' + +examples: +- any: + - changed-files: + - any-glob-to-any-file: 'examples/*' + +ci: +- any: + - changed-files: + - any-glob-to-any-file: '.github/*' diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000000000000000000000000000000000000..eee7f6ec3d9a7f448d4f76ac8ebab367a7e73762 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,37 @@ +# .github/release.yml + +changelog: + exclude: + labels: + - ignore-for-release + categories: + - title: Breaking Changes 🛠 + labels: + - Semver-Major + - breaking-change + - title: "Bug fixes :bug:" + labels: + - bug + - regression + - title: "🖧 P2P area" + labels: + - area/p2p + - title: Exciting New Features 🎉 + labels: + - Semver-Minor + - enhancement + - ux + - roadmap + - title: 🧠 Models + labels: + - area/ai-model + - title: 📖 Documentation and examples + labels: + - kind/documentation + - examples + - title: 👒 Dependencies + labels: + - dependencies + - title: Other Changes + labels: + - "*" diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000000000000000000000000000000000..af48badee058c6367b1692e09bee00868032e590 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,18 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 45 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 10 +# Issues with these labels will never be considered stale +exemptLabels: + - issue/willfix +# Label to use when marking an issue as stale +staleLabel: issue/stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: > + This issue is being automatically closed due to inactivity. + However, you may choose to reopen this issue. \ No newline at end of file diff --git a/.github/workflows/bump_deps.yaml b/.github/workflows/bump_deps.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c94a134d6f52ac1ed7226846a2cc09f31b36b113 --- /dev/null +++ b/.github/workflows/bump_deps.yaml @@ -0,0 +1,70 @@ +name: Bump dependencies +on: + schedule: + - cron: 0 20 * * * + workflow_dispatch: +jobs: + bump: + strategy: + fail-fast: false + matrix: + include: + - repository: "ggerganov/llama.cpp" + variable: "CPPLLAMA_VERSION" + branch: "master" + - repository: "go-skynet/go-ggml-transformers.cpp" + variable: "GOGGMLTRANSFORMERS_VERSION" + branch: "master" + - repository: "donomii/go-rwkv.cpp" + variable: "RWKV_VERSION" + branch: "main" + - repository: "ggerganov/whisper.cpp" + variable: "WHISPER_CPP_VERSION" + branch: "master" + - repository: "go-skynet/go-bert.cpp" + variable: "BERT_VERSION" + branch: "master" + - repository: "go-skynet/bloomz.cpp" + variable: "BLOOMZ_VERSION" + branch: "main" + - repository: "mudler/go-ggllm.cpp" + variable: "GOGGLLM_VERSION" + branch: "master" + - repository: "mudler/go-stable-diffusion" + variable: "STABLEDIFFUSION_VERSION" + branch: "master" + - repository: "mudler/go-piper" + variable: "PIPER_VERSION" + branch: "master" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Bump dependencies 🔧 + id: bump + run: | + bash .github/bump_deps.sh ${{ matrix.repository }} ${{ matrix.branch }} ${{ matrix.variable }} + { + echo 'message<> "$GITHUB_OUTPUT" + { + echo 'commit<> "$GITHUB_OUTPUT" + rm -rfv ${{ matrix.variable }}_message.txt + rm -rfv ${{ matrix.variable }}_commit.txt + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.UPDATE_BOT_TOKEN }} + push-to-fork: ci-forks/LocalAI + commit-message: ':arrow_up: Update ${{ matrix.repository }}' + title: 'chore: :arrow_up: Update ${{ matrix.repository }} to `${{ steps.bump.outputs.commit }}`' + branch: "update/${{ matrix.variable }}" + body: ${{ steps.bump.outputs.message }} + signoff: true + + + diff --git a/.github/workflows/bump_docs.yaml b/.github/workflows/bump_docs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6eb390dfc8724b0f08566e8d8800e4c36b1a71ed --- /dev/null +++ b/.github/workflows/bump_docs.yaml @@ -0,0 +1,31 @@ +name: Bump dependencies +on: + schedule: + - cron: 0 20 * * * + workflow_dispatch: +jobs: + bump: + strategy: + fail-fast: false + matrix: + include: + - repository: "mudler/LocalAI" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Bump dependencies 🔧 + run: | + bash .github/bump_docs.sh ${{ matrix.repository }} + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.UPDATE_BOT_TOKEN }} + push-to-fork: ci-forks/LocalAI + commit-message: ':arrow_up: Update docs version ${{ matrix.repository }}' + title: 'docs: :arrow_up: update docs version ${{ matrix.repository }}' + branch: "update/docs" + body: Bump of ${{ matrix.repository }} version inside docs + signoff: true + + + diff --git a/.github/workflows/checksum_checker.yaml b/.github/workflows/checksum_checker.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7b85ad355aebfe810f15fc7beeee455b13c708eb --- /dev/null +++ b/.github/workflows/checksum_checker.yaml @@ -0,0 +1,47 @@ +name: Check if checksums are up-to-date +on: + schedule: + - cron: 0 20 * * * + workflow_dispatch: +jobs: + checksum_check: + runs-on: arc-runner-set + steps: + - name: Force Install GIT latest + run: | + sudo apt-get update \ + && sudo apt-get install -y software-properties-common \ + && sudo apt-get update \ + && sudo add-apt-repository -y ppa:git-core/ppa \ + && sudo apt-get update \ + && sudo apt-get install -y git + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y pip wget + sudo pip install --upgrade pip + pip install huggingface_hub + - name: 'Setup yq' + uses: dcarbone/install-yq-action@v1.1.1 + with: + version: 'v4.44.2' + download-compressed: true + force: true + + - name: Checksum checker 🔧 + run: | + export HF_HOME=/hf_cache + sudo mkdir /hf_cache + sudo chmod 777 /hf_cache + bash .github/checksum_checker.sh gallery/index.yaml + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.UPDATE_BOT_TOKEN }} + push-to-fork: ci-forks/LocalAI + commit-message: ':arrow_up: Checksum updates in gallery/index.yaml' + title: 'chore(model-gallery): :arrow_up: update checksum' + branch: "update/checksum" + body: Updating checksums in gallery/index.yaml + signoff: true diff --git a/.github/workflows/dependabot_auto.yml b/.github/workflows/dependabot_auto.yml new file mode 100644 index 0000000000000000000000000000000000000000..951e65e153ac844d6207735f16d644bc2d97153f --- /dev/null +++ b/.github/workflows/dependabot_auto.yml @@ -0,0 +1,43 @@ +name: Dependabot auto-merge +on: +- pull_request_target + +permissions: + contents: write + pull-requests: write + packages: read + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2.2.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + skip-commit-verification: true + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Approve a PR if not already approved + run: | + gh pr checkout "$PR_URL" + if [ "$(gh pr status --json reviewDecision -q .currentBranch.reviewDecision)" != "APPROVED" ]; + then + gh pr review --approve "$PR_URL" + else + echo "PR already approved."; + fi + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Enable auto-merge for Dependabot PRs + if: ${{ contains(github.event.pull_request.title, 'bump')}} + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/deploy-explorer.yaml b/.github/workflows/deploy-explorer.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b8f3f7e9f4ef389a53417dab0bd1d447f2149564 --- /dev/null +++ b/.github/workflows/deploy-explorer.yaml @@ -0,0 +1,64 @@ +name: Explorer deployment + +on: + push: + branches: + - master + tags: + - 'v*' + +concurrency: + group: ci-deploy-${{ github.head_ref || github.ref }}-${{ github.repository }} + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install -y wget curl build-essential ffmpeg protobuf-compiler ccache upx-ucl gawk cmake libgmock-dev + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + make protogen-go + - name: Build api + run: | + CGO_ENABLED=0 make build-api + - name: rm + uses: appleboy/ssh-action@v1.1.0 + with: + host: ${{ secrets.EXPLORER_SSH_HOST }} + username: ${{ secrets.EXPLORER_SSH_USERNAME }} + key: ${{ secrets.EXPLORER_SSH_KEY }} + port: ${{ secrets.EXPLORER_SSH_PORT }} + script: | + sudo rm -rf local-ai/ || true + - name: copy file via ssh + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.EXPLORER_SSH_HOST }} + username: ${{ secrets.EXPLORER_SSH_USERNAME }} + key: ${{ secrets.EXPLORER_SSH_KEY }} + port: ${{ secrets.EXPLORER_SSH_PORT }} + source: "local-ai" + overwrite: true + rm: true + target: ./local-ai + - name: restarting + uses: appleboy/ssh-action@v1.1.0 + with: + host: ${{ secrets.EXPLORER_SSH_HOST }} + username: ${{ secrets.EXPLORER_SSH_USERNAME }} + key: ${{ secrets.EXPLORER_SSH_KEY }} + port: ${{ secrets.EXPLORER_SSH_PORT }} + script: | + sudo cp -rfv local-ai/local-ai /usr/bin/local-ai + sudo systemctl restart local-ai diff --git a/.github/workflows/disabled/comment-pr.yaml b/.github/workflows/disabled/comment-pr.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bb1012f2a7c02e08664ec394b71b1c6cd4fdbab3 --- /dev/null +++ b/.github/workflows/disabled/comment-pr.yaml @@ -0,0 +1,83 @@ +name: Comment PRs +on: + pull_request_target: + +jobs: + comment-pr: + env: + MODEL_NAME: hermes-2-theta-llama-3-8b + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + ref: "${{ github.event.pull_request.merge_commit_sha }}" + fetch-depth: 0 # needed to checkout all branches for this Action to work + - uses: mudler/localai-github-action@v1 + with: + model: 'hermes-2-theta-llama-3-8b' # Any from models.localai.io, or from huggingface.com with: "huggingface:///file" + # Check the PR diff using the current branch and the base branch of the PR + - uses: GrantBirki/git-diff-action@v2.7.0 + id: git-diff-action + with: + json_diff_file_output: diff.json + raw_diff_file_output: diff.txt + file_output_only: "true" + base_branch: ${{ github.event.pull_request.base.sha }} + - name: Show diff + env: + DIFF: ${{ steps.git-diff-action.outputs.raw-diff-path }} + run: | + cat $DIFF + - name: Summarize + env: + DIFF: ${{ steps.git-diff-action.outputs.raw-diff-path }} + id: summarize + run: | + input="$(cat $DIFF)" + + # Define the LocalAI API endpoint + API_URL="http://localhost:8080/chat/completions" + + # Create a JSON payload using jq to handle special characters + json_payload=$(jq -n --arg input "$input" '{ + model: "'$MODEL_NAME'", + messages: [ + { + role: "system", + content: "You are LocalAI-bot in Github that helps understanding PRs and assess complexity. Explain what has changed in this PR diff and why" + }, + { + role: "user", + content: $input + } + ] + }') + + # Send the request to LocalAI + response=$(curl -s -X POST $API_URL \ + -H "Content-Type: application/json" \ + -d "$json_payload") + + # Extract the summary from the response + summary="$(echo $response | jq -r '.choices[0].message.content')" + + # Print the summary + # -H "Authorization: Bearer $API_KEY" \ + echo "Summary:" + echo "$summary" + echo "payload sent" + echo "$json_payload" + { + echo 'message<> "$GITHUB_OUTPUT" + docker logs --tail 10 local-ai + - uses: mshick/add-pr-comment@v2 + if: always() + with: + repo-token: ${{ secrets.UPDATE_BOT_TOKEN }} + message: ${{ steps.summarize.outputs.message }} + message-failure: | + Uh oh! Could not analyze this PR, maybe it's too big? diff --git a/.github/workflows/disabled/test-gpu.yml b/.github/workflows/disabled/test-gpu.yml new file mode 100644 index 0000000000000000000000000000000000000000..ea1de749487a55c42f0f52fa1c01e09891fce007 --- /dev/null +++ b/.github/workflows/disabled/test-gpu.yml @@ -0,0 +1,63 @@ +--- +name: 'GPU tests' + +on: + pull_request: + push: + branches: + - master + tags: + - '*' + +concurrency: + group: ci-gpu-tests-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + ubuntu-latest: + runs-on: gpu + strategy: + matrix: + go-version: ['1.21.x'] + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + # You can test your matrix by printing the current Go version + - name: Display Go version + run: go version + - name: Dependencies + run: | + sudo apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y make wget + - name: Build + run: | + if [ ! -e /run/systemd/system ]; then + sudo mkdir /run/systemd/system + fi + sudo mkdir -p /host/tests/${{ github.head_ref || github.ref }} + sudo chmod -R 777 /host/tests/${{ github.head_ref || github.ref }} + make \ + TEST_DIR="/host/tests/${{ github.head_ref || github.ref }}" \ + BUILD_TYPE=cublas \ + prepare-e2e run-e2e-image test-e2e + - name: Release space from worker ♻ + if: always() + run: | + sudo rm -rf build || true + sudo rm -rf bin || true + sudo rm -rf dist || true + sudo docker logs $(sudo docker ps -q --filter ancestor=localai-tests) > logs.txt + sudo cat logs.txt || true + sudo rm -rf logs.txt + make clean || true + make \ + TEST_DIR="/host/tests/${{ github.head_ref || github.ref }}" \ + teardown-e2e || true + sudo rm -rf /host/tests/${{ github.head_ref || github.ref }} || true + docker system prune -f -a --volumes || true diff --git a/.github/workflows/generate_grpc_cache.yaml b/.github/workflows/generate_grpc_cache.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0b9105aa5555fd83536c43a0a919bc2962da663e --- /dev/null +++ b/.github/workflows/generate_grpc_cache.yaml @@ -0,0 +1,94 @@ +name: 'generate and publish GRPC docker caches' + +on: + workflow_dispatch: + push: + branches: + - master + +concurrency: + group: grpc-cache-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + generate_caches: + strategy: + matrix: + include: + - grpc-base-image: ubuntu:22.04 + runs-on: 'ubuntu-latest' + platforms: 'linux/amd64,linux/arm64' + runs-on: ${{matrix.runs-on}} + steps: + - name: Release space from worker + if: matrix.runs-on == 'ubuntu-latest' + run: | + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + df -h + echo + sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true + sudo apt-get remove --auto-remove android-sdk-platform-tools || true + sudo apt-get purge --auto-remove android-sdk-platform-tools || true + sudo rm -rf /usr/local/lib/android + sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true + sudo rm -rf /usr/share/dotnet + sudo apt-get remove -y '^mono-.*' || true + sudo apt-get remove -y '^ghc-.*' || true + sudo apt-get remove -y '.*jdk.*|.*jre.*' || true + sudo apt-get remove -y 'php.*' || true + sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true + sudo apt-get remove -y '^google-.*' || true + sudo apt-get remove -y azure-cli || true + sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true + sudo apt-get remove -y '^gfortran-.*' || true + sudo apt-get remove -y microsoft-edge-stable || true + sudo apt-get remove -y firefox || true + sudo apt-get remove -y powershell || true + sudo apt-get remove -y r-base-core || true + sudo apt-get autoremove -y + sudo apt-get clean + echo + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + sudo rm -rfv build || true + sudo rm -rf /usr/share/dotnet || true + sudo rm -rf /opt/ghc || true + sudo rm -rf "/usr/local/share/boost" || true + sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true + df -h + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache GRPC + uses: docker/build-push-action@v6 + with: + builder: ${{ steps.buildx.outputs.name }} + # The build-args MUST be an EXACT match between the image cache and other workflow steps that want to use that cache. + # This means that even the MAKEFLAGS have to be an EXACT match. + # If the build-args are not an EXACT match, it will result in a cache miss, which will require GRPC to be built from scratch. + build-args: | + GRPC_BASE_IMAGE=${{ matrix.grpc-base-image }} + GRPC_MAKEFLAGS=--jobs=4 --output-sync=target + GRPC_VERSION=v1.65.0 + context: . + file: ./Dockerfile + cache-to: type=gha,ignore-error=true + cache-from: type=gha + target: grpc + platforms: ${{ matrix.platforms }} + push: false diff --git a/.github/workflows/generate_intel_image.yaml b/.github/workflows/generate_intel_image.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0c2a7670becdd5e29c70666d9e56b58d7d85f45c --- /dev/null +++ b/.github/workflows/generate_intel_image.yaml @@ -0,0 +1,59 @@ +name: 'generate and publish intel docker caches' + +on: + workflow_dispatch: + push: + branches: + - master + +concurrency: + group: intel-cache-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + generate_caches: + strategy: + matrix: + include: + - base-image: intel/oneapi-basekit:2024.2.0-devel-ubuntu22.04 + runs-on: 'ubuntu-latest' + platforms: 'linux/amd64' + runs-on: ${{matrix.runs-on}} + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Login to quay + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: quay.io + username: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + password: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache Intel images + uses: docker/build-push-action@v6 + with: + builder: ${{ steps.buildx.outputs.name }} + build-args: | + BASE_IMAGE=${{ matrix.base-image }} + context: . + file: ./Dockerfile + tags: quay.io/go-skynet/intel-oneapi-base:latest + push: true + target: intel + platforms: ${{ matrix.platforms }} diff --git a/.github/workflows/image-pr.yml b/.github/workflows/image-pr.yml new file mode 100644 index 0000000000000000000000000000000000000000..8ebaa1b26cb8b7d57cd4c0e7d9a495f8f3b2873e --- /dev/null +++ b/.github/workflows/image-pr.yml @@ -0,0 +1,140 @@ +--- +name: 'build container images tests' + +on: + pull_request: + +concurrency: + group: ci-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + extras-image-build: + uses: ./.github/workflows/image_build.yml + with: + tag-latest: ${{ matrix.tag-latest }} + tag-suffix: ${{ matrix.tag-suffix }} + ffmpeg: ${{ matrix.ffmpeg }} + image-type: ${{ matrix.image-type }} + build-type: ${{ matrix.build-type }} + cuda-major-version: ${{ matrix.cuda-major-version }} + cuda-minor-version: ${{ matrix.cuda-minor-version }} + platforms: ${{ matrix.platforms }} + runs-on: ${{ matrix.runs-on }} + base-image: ${{ matrix.base-image }} + grpc-base-image: ${{ matrix.grpc-base-image }} + makeflags: ${{ matrix.makeflags }} + secrets: + dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }} + dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }} + quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + strategy: + # Pushing with all jobs in parallel + # eats the bandwidth of all the nodes + max-parallel: ${{ github.event_name != 'pull_request' && 4 || 8 }} + matrix: + include: + # This is basically covered by the AIO test + # - build-type: '' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # tag-suffix: '-ffmpeg' + # ffmpeg: 'true' + # image-type: 'extras' + # runs-on: 'arc-runner-set' + # base-image: "ubuntu:22.04" + # makeflags: "--jobs=3 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda12-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=3 --output-sync=target" + # - build-type: 'hipblas' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # tag-suffix: '-hipblas' + # ffmpeg: 'false' + # image-type: 'extras' + # base-image: "rocm/dev-ubuntu-22.04:6.1" + # grpc-base-image: "ubuntu:22.04" + # runs-on: 'arc-runner-set' + # makeflags: "--jobs=3 --output-sync=target" + # - build-type: 'sycl_f16' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + # grpc-base-image: "ubuntu:22.04" + # tag-suffix: 'sycl-f16-ffmpeg' + # ffmpeg: 'true' + # image-type: 'extras' + # runs-on: 'arc-runner-set' + # makeflags: "--jobs=3 --output-sync=target" + # core-image-build: + # uses: ./.github/workflows/image_build.yml + # with: + # tag-latest: ${{ matrix.tag-latest }} + # tag-suffix: ${{ matrix.tag-suffix }} + # ffmpeg: ${{ matrix.ffmpeg }} + # image-type: ${{ matrix.image-type }} + # build-type: ${{ matrix.build-type }} + # cuda-major-version: ${{ matrix.cuda-major-version }} + # cuda-minor-version: ${{ matrix.cuda-minor-version }} + # platforms: ${{ matrix.platforms }} + # runs-on: ${{ matrix.runs-on }} + # base-image: ${{ matrix.base-image }} + # grpc-base-image: ${{ matrix.grpc-base-image }} + # makeflags: ${{ matrix.makeflags }} + # secrets: + # dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }} + # dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }} + # quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + # quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + # strategy: + # matrix: + # include: + # - build-type: '' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # tag-suffix: '-ffmpeg-core' + # ffmpeg: 'true' + # image-type: 'core' + # runs-on: 'ubuntu-latest' + # base-image: "ubuntu:22.04" + # makeflags: "--jobs=4 --output-sync=target" + # - build-type: 'sycl_f16' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + # grpc-base-image: "ubuntu:22.04" + # tag-suffix: 'sycl-f16-ffmpeg-core' + # ffmpeg: 'true' + # image-type: 'core' + # runs-on: 'arc-runner-set' + # makeflags: "--jobs=3 --output-sync=target" + # - build-type: 'cublas' + # cuda-major-version: "12" + # cuda-minor-version: "0" + # platforms: 'linux/amd64' + # tag-latest: 'false' + # tag-suffix: '-cublas-cuda12-ffmpeg-core' + # ffmpeg: 'true' + # image-type: 'core' + # runs-on: 'ubuntu-latest' + # base-image: "ubuntu:22.04" + # makeflags: "--jobs=4 --output-sync=target" + # - build-type: 'vulkan' + # platforms: 'linux/amd64' + # tag-latest: 'false' + # tag-suffix: '-vulkan-ffmpeg-core' + # ffmpeg: 'true' + # image-type: 'core' + # runs-on: 'ubuntu-latest' + # base-image: "ubuntu:22.04" + # makeflags: "--jobs=4 --output-sync=target" diff --git a/.github/workflows/image.yml b/.github/workflows/image.yml new file mode 100644 index 0000000000000000000000000000000000000000..6db8bb076c1b45080a47beca9daae950742822e7 --- /dev/null +++ b/.github/workflows/image.yml @@ -0,0 +1,357 @@ +--- +name: 'build container images' + +on: + push: + branches: + - master + tags: + - '*' + +concurrency: + group: ci-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + hipblas-jobs: + uses: ./.github/workflows/image_build.yml + with: + tag-latest: ${{ matrix.tag-latest }} + tag-suffix: ${{ matrix.tag-suffix }} + ffmpeg: ${{ matrix.ffmpeg }} + image-type: ${{ matrix.image-type }} + build-type: ${{ matrix.build-type }} + cuda-major-version: ${{ matrix.cuda-major-version }} + cuda-minor-version: ${{ matrix.cuda-minor-version }} + platforms: ${{ matrix.platforms }} + runs-on: ${{ matrix.runs-on }} + base-image: ${{ matrix.base-image }} + grpc-base-image: ${{ matrix.grpc-base-image }} + aio: ${{ matrix.aio }} + makeflags: ${{ matrix.makeflags }} + latest-image: ${{ matrix.latest-image }} + latest-image-aio: ${{ matrix.latest-image-aio }} + secrets: + dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }} + dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }} + quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + strategy: + # Pushing with all jobs in parallel + # eats the bandwidth of all the nodes + max-parallel: 2 + matrix: + include: + - build-type: 'hipblas' + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-hipblas-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + aio: "-aio-gpu-hipblas" + base-image: "rocm/dev-ubuntu-22.04:6.1" + grpc-base-image: "ubuntu:22.04" + latest-image: 'latest-gpu-hipblas' + latest-image-aio: 'latest-aio-gpu-hipblas' + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'hipblas' + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-hipblas' + ffmpeg: 'false' + image-type: 'extras' + base-image: "rocm/dev-ubuntu-22.04:6.1" + grpc-base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'hipblas' + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-hipblas-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + base-image: "rocm/dev-ubuntu-22.04:6.1" + grpc-base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'hipblas' + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-hipblas-core' + ffmpeg: 'false' + image-type: 'core' + base-image: "rocm/dev-ubuntu-22.04:6.1" + grpc-base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + self-hosted-jobs: + uses: ./.github/workflows/image_build.yml + with: + tag-latest: ${{ matrix.tag-latest }} + tag-suffix: ${{ matrix.tag-suffix }} + ffmpeg: ${{ matrix.ffmpeg }} + image-type: ${{ matrix.image-type }} + build-type: ${{ matrix.build-type }} + cuda-major-version: ${{ matrix.cuda-major-version }} + cuda-minor-version: ${{ matrix.cuda-minor-version }} + platforms: ${{ matrix.platforms }} + runs-on: ${{ matrix.runs-on }} + base-image: ${{ matrix.base-image }} + grpc-base-image: ${{ matrix.grpc-base-image }} + aio: ${{ matrix.aio }} + makeflags: ${{ matrix.makeflags }} + latest-image: ${{ matrix.latest-image }} + latest-image-aio: ${{ matrix.latest-image-aio }} + secrets: + dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }} + dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }} + quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + strategy: + # Pushing with all jobs in parallel + # eats the bandwidth of all the nodes + max-parallel: ${{ github.event_name != 'pull_request' && 5 || 8 }} + matrix: + include: + # Extra images + - build-type: '' + #platforms: 'linux/amd64,linux/arm64' + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '' + ffmpeg: '' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=3 --output-sync=target" + - build-type: '' + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "11" + cuda-minor-version: "7" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda11' + ffmpeg: '' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda12' + ffmpeg: '' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "11" + cuda-minor-version: "7" + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-cublas-cuda11-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + aio: "-aio-gpu-nvidia-cuda-11" + latest-image: 'latest-gpu-nvidia-cuda-11' + latest-image-aio: 'latest-aio-gpu-nvidia-cuda-11' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-cublas-cuda12-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + aio: "-aio-gpu-nvidia-cuda-12" + latest-image: 'latest-gpu-nvidia-cuda-12' + latest-image-aio: 'latest-aio-gpu-nvidia-cuda-12' + makeflags: "--jobs=3 --output-sync=target" + - build-type: '' + #platforms: 'linux/amd64,linux/arm64' + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '' + ffmpeg: '' + image-type: 'extras' + base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'sycl_f16' + platforms: 'linux/amd64' + tag-latest: 'auto' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f16-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + aio: "-aio-gpu-intel-f16" + latest-image: 'latest-gpu-intel-f16' + latest-image-aio: 'latest-aio-gpu-intel-f16' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'sycl_f32' + platforms: 'linux/amd64' + tag-latest: 'auto' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f32-ffmpeg' + ffmpeg: 'true' + image-type: 'extras' + runs-on: 'arc-runner-set' + aio: "-aio-gpu-intel-f32" + latest-image: 'latest-gpu-intel-f32' + latest-image-aio: 'latest-aio-gpu-intel-f32' + makeflags: "--jobs=3 --output-sync=target" + # Core images + - build-type: 'sycl_f16' + platforms: 'linux/amd64' + tag-latest: 'false' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f16-core' + ffmpeg: 'false' + image-type: 'core' + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'sycl_f32' + platforms: 'linux/amd64' + tag-latest: 'false' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f32-core' + ffmpeg: 'false' + image-type: 'core' + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'sycl_f16' + platforms: 'linux/amd64' + tag-latest: 'false' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f16-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + - build-type: 'sycl_f32' + platforms: 'linux/amd64' + tag-latest: 'false' + base-image: "quay.io/go-skynet/intel-oneapi-base:latest" + grpc-base-image: "ubuntu:22.04" + tag-suffix: '-sycl-f32-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + runs-on: 'arc-runner-set' + makeflags: "--jobs=3 --output-sync=target" + + core-image-build: + uses: ./.github/workflows/image_build.yml + with: + tag-latest: ${{ matrix.tag-latest }} + tag-suffix: ${{ matrix.tag-suffix }} + ffmpeg: ${{ matrix.ffmpeg }} + image-type: ${{ matrix.image-type }} + build-type: ${{ matrix.build-type }} + cuda-major-version: ${{ matrix.cuda-major-version }} + cuda-minor-version: ${{ matrix.cuda-minor-version }} + platforms: ${{ matrix.platforms }} + runs-on: ${{ matrix.runs-on }} + aio: ${{ matrix.aio }} + base-image: ${{ matrix.base-image }} + grpc-base-image: ${{ matrix.grpc-base-image }} + makeflags: ${{ matrix.makeflags }} + latest-image: ${{ matrix.latest-image }} + latest-image-aio: ${{ matrix.latest-image-aio }} + secrets: + dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }} + dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }} + quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }} + quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }} + strategy: + max-parallel: ${{ github.event_name != 'pull_request' && 2 || 4 }} + matrix: + include: + - build-type: '' + platforms: 'linux/amd64,linux/arm64' + tag-latest: 'auto' + tag-suffix: '-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + aio: "-aio-cpu" + latest-image: 'latest-cpu' + latest-image-aio: 'latest-aio-cpu' + makeflags: "--jobs=4 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "11" + cuda-minor-version: "7" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda11-core' + ffmpeg: '' + image-type: 'core' + base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=4 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda12-core' + ffmpeg: '' + image-type: 'core' + base-image: "ubuntu:22.04" + runs-on: 'arc-runner-set' + makeflags: "--jobs=4 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "11" + cuda-minor-version: "7" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda11-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=4 --output-sync=target" + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-cublas-cuda12-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=4 --output-sync=target" + - build-type: 'vulkan' + platforms: 'linux/amd64' + tag-latest: 'false' + tag-suffix: '-vulkan-ffmpeg-core' + latest-image: 'latest-vulkan-ffmpeg-core' + ffmpeg: 'true' + image-type: 'core' + runs-on: 'arc-runner-set' + base-image: "ubuntu:22.04" + makeflags: "--jobs=4 --output-sync=target" diff --git a/.github/workflows/image_build.yml b/.github/workflows/image_build.yml new file mode 100644 index 0000000000000000000000000000000000000000..4a5735e5cfe0ff6eeeade26a42f0f55763306383 --- /dev/null +++ b/.github/workflows/image_build.yml @@ -0,0 +1,335 @@ +--- +name: 'build container images (reusable)' + +on: + workflow_call: + inputs: + base-image: + description: 'Base image' + required: true + type: string + grpc-base-image: + description: 'GRPC Base image, must be a compatible image with base-image' + required: false + default: '' + type: string + build-type: + description: 'Build type' + default: '' + type: string + cuda-major-version: + description: 'CUDA major version' + default: "12" + type: string + cuda-minor-version: + description: 'CUDA minor version' + default: "4" + type: string + platforms: + description: 'Platforms' + default: '' + type: string + tag-latest: + description: 'Tag latest' + default: '' + type: string + latest-image: + description: 'Tag latest' + default: '' + type: string + latest-image-aio: + description: 'Tag latest' + default: '' + type: string + tag-suffix: + description: 'Tag suffix' + default: '' + type: string + ffmpeg: + description: 'FFMPEG' + default: '' + type: string + image-type: + description: 'Image type' + default: '' + type: string + runs-on: + description: 'Runs on' + required: true + default: '' + type: string + makeflags: + description: 'Make Flags' + required: false + default: '--jobs=4 --output-sync=target' + type: string + aio: + description: 'AIO Image Name' + required: false + default: '' + type: string + secrets: + dockerUsername: + required: true + dockerPassword: + required: true + quayUsername: + required: true + quayPassword: + required: true +jobs: + reusable_image-build: + runs-on: ${{ inputs.runs-on }} + steps: + - name: Force Install GIT latest + run: | + sudo apt-get update \ + && sudo apt-get install -y software-properties-common \ + && sudo apt-get update \ + && sudo add-apt-repository -y ppa:git-core/ppa \ + && sudo apt-get update \ + && sudo apt-get install -y git + - name: Checkout + uses: actions/checkout@v4 + + - name: Release space from worker + if: inputs.runs-on == 'ubuntu-latest' + run: | + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + df -h + echo + sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true + sudo apt-get remove --auto-remove android-sdk-platform-tools || true + sudo apt-get purge --auto-remove android-sdk-platform-tools || true + sudo rm -rf /usr/local/lib/android + sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true + sudo rm -rf /usr/share/dotnet + sudo apt-get remove -y '^mono-.*' || true + sudo apt-get remove -y '^ghc-.*' || true + sudo apt-get remove -y '.*jdk.*|.*jre.*' || true + sudo apt-get remove -y 'php.*' || true + sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true + sudo apt-get remove -y '^google-.*' || true + sudo apt-get remove -y azure-cli || true + sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true + sudo apt-get remove -y '^gfortran-.*' || true + sudo apt-get remove -y microsoft-edge-stable || true + sudo apt-get remove -y firefox || true + sudo apt-get remove -y powershell || true + sudo apt-get remove -y r-base-core || true + sudo apt-get autoremove -y + sudo apt-get clean + echo + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + sudo rm -rfv build || true + sudo rm -rf /usr/share/dotnet || true + sudo rm -rf /opt/ghc || true + sudo rm -rf "/usr/local/share/boost" || true + sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true + df -h + + - name: Docker meta + id: meta + if: github.event_name != 'pull_request' + uses: docker/metadata-action@v5 + with: + images: | + quay.io/go-skynet/local-ai + localai/localai + tags: | + type=ref,event=branch + type=semver,pattern={{raw}} + type=sha + flavor: | + latest=${{ inputs.tag-latest }} + suffix=${{ inputs.tag-suffix }} + - name: Docker meta for PR + id: meta_pull_request + if: github.event_name == 'pull_request' + uses: docker/metadata-action@v5 + with: + images: | + ttl.sh/localai-ci-pr-${{ github.event.number }} + tags: | + type=ref,event=branch + type=semver,pattern={{raw}} + type=sha + flavor: | + latest=${{ inputs.tag-latest }} + suffix=${{ inputs.tag-suffix }} + - name: Docker meta AIO (quay.io) + if: inputs.aio != '' + id: meta_aio + uses: docker/metadata-action@v5 + with: + images: | + quay.io/go-skynet/local-ai + tags: | + type=ref,event=branch + type=semver,pattern={{raw}} + flavor: | + latest=${{ inputs.tag-latest }} + suffix=${{ inputs.aio }} + + - name: Docker meta AIO (dockerhub) + if: inputs.aio != '' + id: meta_aio_dockerhub + uses: docker/metadata-action@v5 + with: + images: | + localai/localai + tags: | + type=ref,event=branch + type=semver,pattern={{raw}} + flavor: | + suffix=${{ inputs.aio }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.dockerUsername }} + password: ${{ secrets.dockerPassword }} + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: quay.io + username: ${{ secrets.quayUsername }} + password: ${{ secrets.quayPassword }} + + - name: Build and push + uses: docker/build-push-action@v6 + if: github.event_name != 'pull_request' + with: + builder: ${{ steps.buildx.outputs.name }} + # The build-args MUST be an EXACT match between the image cache and other workflow steps that want to use that cache. + # This means that even the MAKEFLAGS have to be an EXACT match. + # If the build-args are not an EXACT match, it will result in a cache miss, which will require GRPC to be built from scratch. + # This is why some build args like GRPC_VERSION and MAKEFLAGS are hardcoded + build-args: | + BUILD_TYPE=${{ inputs.build-type }} + CUDA_MAJOR_VERSION=${{ inputs.cuda-major-version }} + CUDA_MINOR_VERSION=${{ inputs.cuda-minor-version }} + FFMPEG=${{ inputs.ffmpeg }} + IMAGE_TYPE=${{ inputs.image-type }} + BASE_IMAGE=${{ inputs.base-image }} + GRPC_BASE_IMAGE=${{ inputs.grpc-base-image || inputs.base-image }} + GRPC_MAKEFLAGS=--jobs=4 --output-sync=target + GRPC_VERSION=v1.65.0 + MAKEFLAGS=${{ inputs.makeflags }} + context: . + file: ./Dockerfile + cache-from: type=gha + platforms: ${{ inputs.platforms }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} +### Start testing image + - name: Build and push + uses: docker/build-push-action@v6 + if: github.event_name == 'pull_request' + with: + builder: ${{ steps.buildx.outputs.name }} + # The build-args MUST be an EXACT match between the image cache and other workflow steps that want to use that cache. + # This means that even the MAKEFLAGS have to be an EXACT match. + # If the build-args are not an EXACT match, it will result in a cache miss, which will require GRPC to be built from scratch. + # This is why some build args like GRPC_VERSION and MAKEFLAGS are hardcoded + build-args: | + BUILD_TYPE=${{ inputs.build-type }} + CUDA_MAJOR_VERSION=${{ inputs.cuda-major-version }} + CUDA_MINOR_VERSION=${{ inputs.cuda-minor-version }} + FFMPEG=${{ inputs.ffmpeg }} + IMAGE_TYPE=${{ inputs.image-type }} + BASE_IMAGE=${{ inputs.base-image }} + GRPC_BASE_IMAGE=${{ inputs.grpc-base-image || inputs.base-image }} + GRPC_MAKEFLAGS=--jobs=4 --output-sync=target + GRPC_VERSION=v1.65.0 + MAKEFLAGS=${{ inputs.makeflags }} + context: . + file: ./Dockerfile + cache-from: type=gha + platforms: ${{ inputs.platforms }} + push: true + tags: ${{ steps.meta_pull_request.outputs.tags }} + labels: ${{ steps.meta_pull_request.outputs.labels }} + - name: Testing image + if: github.event_name == 'pull_request' + run: | + echo "Image is available at ttl.sh/localai-ci-pr-${{ github.event.number }}:${{ steps.meta_pull_request.outputs.version }}" >> $GITHUB_STEP_SUMMARY +## End testing image + - name: Build and push AIO image + if: inputs.aio != '' + uses: docker/build-push-action@v6 + with: + builder: ${{ steps.buildx.outputs.name }} + build-args: | + BASE_IMAGE=quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} + MAKEFLAGS=${{ inputs.makeflags }} + context: . + file: ./Dockerfile.aio + platforms: ${{ inputs.platforms }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta_aio.outputs.tags }} + labels: ${{ steps.meta_aio.outputs.labels }} + + - name: Build and push AIO image (dockerhub) + if: inputs.aio != '' + uses: docker/build-push-action@v6 + with: + builder: ${{ steps.buildx.outputs.name }} + build-args: | + BASE_IMAGE=localai/localai:${{ steps.meta.outputs.version }} + MAKEFLAGS=${{ inputs.makeflags }} + context: . + file: ./Dockerfile.aio + platforms: ${{ inputs.platforms }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta_aio_dockerhub.outputs.tags }} + labels: ${{ steps.meta_aio_dockerhub.outputs.labels }} + + - name: Latest tag + # run this on branches, when it is a tag and there is a latest-image defined + if: github.event_name != 'pull_request' && inputs.latest-image != '' && github.ref_type == 'tag' + run: | + docker pull localai/localai:${{ steps.meta.outputs.version }} + docker tag localai/localai:${{ steps.meta.outputs.version }} localai/localai:${{ inputs.latest-image }} + docker push localai/localai:${{ inputs.latest-image }} + docker pull quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} + docker tag quay.io/go-skynet/local-ai:${{ steps.meta.outputs.version }} quay.io/go-skynet/local-ai:${{ inputs.latest-image }} + docker push quay.io/go-skynet/local-ai:${{ inputs.latest-image }} + - name: Latest AIO tag + # run this on branches, when it is a tag and there is a latest-image defined + if: github.event_name != 'pull_request' && inputs.latest-image-aio != '' && github.ref_type == 'tag' + run: | + docker pull localai/localai:${{ steps.meta_aio_dockerhub.outputs.version }} + docker tag localai/localai:${{ steps.meta_aio_dockerhub.outputs.version }} localai/localai:${{ inputs.latest-image-aio }} + docker push localai/localai:${{ inputs.latest-image-aio }} + docker pull quay.io/go-skynet/local-ai:${{ steps.meta_aio.outputs.version }} + docker tag quay.io/go-skynet/local-ai:${{ steps.meta_aio.outputs.version }} quay.io/go-skynet/local-ai:${{ inputs.latest-image-aio }} + docker push quay.io/go-skynet/local-ai:${{ inputs.latest-image-aio }} + + - name: job summary + run: | + echo "Built image: ${{ steps.meta.outputs.labels }}" >> $GITHUB_STEP_SUMMARY + + - name: job summary(AIO) + if: inputs.aio != '' + run: | + echo "Built image: ${{ steps.meta_aio.outputs.labels }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000000000000000000000000000000000..e3ecf923f01cf733143c18534c6203268a038e1e --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 \ No newline at end of file diff --git a/.github/workflows/localaibot_automerge.yml b/.github/workflows/localaibot_automerge.yml new file mode 100644 index 0000000000000000000000000000000000000000..6a1ab8918b912c60a94bdc61adefa758fb1d2ea0 --- /dev/null +++ b/.github/workflows/localaibot_automerge.yml @@ -0,0 +1,35 @@ +name: LocalAI-bot auto-merge +on: +- pull_request_target + +permissions: + contents: write + pull-requests: write + packages: read + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'localai-bot' }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Approve a PR if not already approved + run: | + gh pr checkout "$PR_URL" + if [ "$(gh pr status --json reviewDecision -q .currentBranch.reviewDecision)" != "APPROVED" ]; + then + gh pr review --approve "$PR_URL" + else + echo "PR already approved."; + fi + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Enable auto-merge for LocalAIBot PRs + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/notify-models.yaml b/.github/workflows/notify-models.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e17ee7fcb26a07256726c7725e15a0d62b32376d --- /dev/null +++ b/.github/workflows/notify-models.yaml @@ -0,0 +1,168 @@ +name: Notifications for new models +on: + pull_request: + types: + - closed + +jobs: + notify-discord: + if: ${{ (github.event.pull_request.merged == true) && (contains(github.event.pull_request.labels.*.name, 'area/ai-model')) }} + env: + MODEL_NAME: hermes-2-theta-llama-3-8b + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed to checkout all branches for this Action to work + - uses: mudler/localai-github-action@v1 + with: + model: 'hermes-2-theta-llama-3-8b' # Any from models.localai.io, or from huggingface.com with: "huggingface:///file" + # Check the PR diff using the current branch and the base branch of the PR + - uses: GrantBirki/git-diff-action@v2.7.0 + id: git-diff-action + with: + json_diff_file_output: diff.json + raw_diff_file_output: diff.txt + file_output_only: "true" + - name: Summarize + env: + DIFF: ${{ steps.git-diff-action.outputs.raw-diff-path }} + id: summarize + run: | + input="$(cat $DIFF)" + + # Define the LocalAI API endpoint + API_URL="http://localhost:8080/chat/completions" + + # Create a JSON payload using jq to handle special characters + json_payload=$(jq -n --arg input "$input" '{ + model: "'$MODEL_NAME'", + messages: [ + { + role: "system", + content: "You are LocalAI-bot. Write a discord message to notify everyone about the new model from the git diff. Make it informal. An example can include: the URL of the model, the name, and a brief description of the model if exists. Also add an hint on how to install it in LocalAI and that can be browsed over https://models.localai.io. For example: local-ai run model_name_here" + }, + { + role: "user", + content: $input + } + ] + }') + + # Send the request to LocalAI + response=$(curl -s -X POST $API_URL \ + -H "Content-Type: application/json" \ + -d "$json_payload") + + # Extract the summary from the response + summary="$(echo $response | jq -r '.choices[0].message.content')" + + # Print the summary + # -H "Authorization: Bearer $API_KEY" \ + echo "Summary:" + echo "$summary" + echo "payload sent" + echo "$json_payload" + { + echo 'message<> "$GITHUB_OUTPUT" + docker logs --tail 10 local-ai + - name: Discord notification + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_USERNAME: "LocalAI-Bot" + DISCORD_AVATAR: "https://avatars.githubusercontent.com/u/139863280?v=4" + uses: Ilshidur/action-discord@master + with: + args: ${{ steps.summarize.outputs.message }} + - name: Setup tmate session if fails + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + notify-twitter: + if: ${{ (github.event.pull_request.merged == true) && (contains(github.event.pull_request.labels.*.name, 'area/ai-model')) }} + env: + MODEL_NAME: hermes-2-theta-llama-3-8b + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed to checkout all branches for this Action to work + - name: Start LocalAI + run: | + echo "Starting LocalAI..." + docker run -e -ti -d --name local-ai -p 8080:8080 localai/localai:master-ffmpeg-core run --debug $MODEL_NAME + until [ "`docker inspect -f {{.State.Health.Status}} local-ai`" == "healthy" ]; do echo "Waiting for container to be ready"; docker logs --tail 10 local-ai; sleep 2; done + # Check the PR diff using the current branch and the base branch of the PR + - uses: GrantBirki/git-diff-action@v2.7.0 + id: git-diff-action + with: + json_diff_file_output: diff.json + raw_diff_file_output: diff.txt + file_output_only: "true" + - name: Summarize + env: + DIFF: ${{ steps.git-diff-action.outputs.raw-diff-path }} + id: summarize + run: | + input="$(cat $DIFF)" + + # Define the LocalAI API endpoint + API_URL="http://localhost:8080/chat/completions" + + # Create a JSON payload using jq to handle special characters + json_payload=$(jq -n --arg input "$input" '{ + model: "'$MODEL_NAME'", + messages: [ + { + role: "system", + content: "You are LocalAI-bot. Write a twitter message to notify everyone about the new model from the git diff. Make it informal and really short. An example can include: the name, and a brief description of the model if exists. Also add an hint on how to install it in LocalAI. For example: local-ai run model_name_here" + }, + { + role: "user", + content: $input + } + ] + }') + + # Send the request to LocalAI + response=$(curl -s -X POST $API_URL \ + -H "Content-Type: application/json" \ + -d "$json_payload") + + # Extract the summary from the response + summary="$(echo $response | jq -r '.choices[0].message.content')" + + # Print the summary + # -H "Authorization: Bearer $API_KEY" \ + echo "Summary:" + echo "$summary" + echo "payload sent" + echo "$json_payload" + { + echo 'message<> "$GITHUB_OUTPUT" + docker logs --tail 10 local-ai + - uses: Eomm/why-don-t-you-tweet@v2 + with: + tweet-message: ${{ steps.summarize.outputs.message }} + env: + # Get your tokens from https://developer.twitter.com/apps + TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_APP_KEY }} + TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_APP_SECRET }} + TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} + TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + - name: Setup tmate session if fails + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true diff --git a/.github/workflows/notify-releases.yaml b/.github/workflows/notify-releases.yaml new file mode 100644 index 0000000000000000000000000000000000000000..faaaacdb2f817206faf353cedcd0e910ebe71ebb --- /dev/null +++ b/.github/workflows/notify-releases.yaml @@ -0,0 +1,63 @@ +name: Release notifications +on: + release: + types: + - published + +jobs: + notify-discord: + runs-on: ubuntu-latest + env: + RELEASE_BODY: ${{ github.event.release.body }} + RELEASE_TITLE: ${{ github.event.release.name }} + RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} + steps: + - uses: mudler/localai-github-action@v1 + with: + model: 'hermes-2-theta-llama-3-8b' # Any from models.localai.io, or from huggingface.com with: "huggingface:///file" + - name: Summarize + id: summarize + run: | + input="$RELEASE_TITLE\b$RELEASE_BODY" + + # Define the LocalAI API endpoint + API_URL="http://localhost:8080/chat/completions" + + # Create a JSON payload using jq to handle special characters + json_payload=$(jq -n --arg input "$input" '{ + model: "'$MODEL_NAME'", + messages: [ + { + role: "system", + content: "Write a discord message with a bullet point summary of the release notes." + }, + { + role: "user", + content: $input + } + ] + }') + + # Send the request to LocalAI API + response=$(curl -s -X POST $API_URL \ + -H "Content-Type: application/json" \ + -d "$json_payload") + + # Extract the summary from the response + summary=$(echo $response | jq -r '.choices[0].message.content') + + # Print the summary + # -H "Authorization: Bearer $API_KEY" \ + { + echo 'message<> "$GITHUB_OUTPUT" + - name: Discord notification + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_RELEASE }} + DISCORD_USERNAME: "LocalAI-Bot" + DISCORD_AVATAR: "https://avatars.githubusercontent.com/u/139863280?v=4" + uses: Ilshidur/action-discord@master + with: + args: ${{ steps.summarize.outputs.message }} \ No newline at end of file diff --git a/.github/workflows/prlint.yaml b/.github/workflows/prlint.yaml new file mode 100644 index 0000000000000000000000000000000000000000..66f338e4778b9b88182f0b2d10b52927a5a048c0 --- /dev/null +++ b/.github/workflows/prlint.yaml @@ -0,0 +1,28 @@ +name: Check PR style + +on: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + +jobs: + title-lint: + runs-on: ubuntu-latest + permissions: + statuses: write + steps: + - uses: aslafy-z/conventional-pr-title-action@v3 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# check-pr-description: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v2 +# - uses: jadrol/pr-description-checker-action@v1.0.0 +# id: description-checker +# with: +# repo-token: ${{ secrets.GITHUB_TOKEN }} +# exempt-labels: no qa diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000000000000000000000000000000000..47a69b0f111e24b900ee3737258c82ef7892ecef --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,357 @@ +name: Build and Release + +on: + push: + branches: + - master + tags: + - 'v*' + pull_request: + +env: + GRPC_VERSION: v1.65.0 + +permissions: + contents: write + +concurrency: + group: ci-releases-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + + build-linux-arm: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg protobuf-compiler ccache upx-ucl gawk + sudo apt-get install -qy binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libgmock-dev + - name: Install CUDA Dependencies + run: | + curl -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/cross-linux-aarch64/cuda-keyring_1.1-1_all.deb + sudo dpkg -i cuda-keyring_1.1-1_all.deb + sudo apt-get update + sudo apt-get install -y cuda-cross-aarch64 cuda-nvcc-cross-aarch64-${CUDA_VERSION} libcublas-cross-aarch64-${CUDA_VERSION} + env: + CUDA_VERSION: 12-4 + - name: Cache grpc + id: cache-grpc + uses: actions/cache@v4 + with: + path: grpc + key: ${{ runner.os }}-arm-grpc-${{ env.GRPC_VERSION }} + - name: Build grpc + if: steps.cache-grpc.outputs.cache-hit != 'true' + run: | + + git clone --recurse-submodules -b ${{ env.GRPC_VERSION }} --depth 1 --shallow-submodules https://github.com/grpc/grpc && \ + cd grpc && sed -i "216i\ TESTONLY" "third_party/abseil-cpp/absl/container/CMakeLists.txt" && mkdir -p cmake/build && \ + cd cmake/build && cmake -DgRPC_INSTALL=ON \ + -DgRPC_BUILD_TESTS=OFF \ + ../.. && sudo make --jobs 5 --output-sync=target + - name: Install gRPC + run: | + GNU_HOST=aarch64-linux-gnu + C_COMPILER_ARM_LINUX=$GNU_HOST-gcc + CXX_COMPILER_ARM_LINUX=$GNU_HOST-g++ + + CROSS_TOOLCHAIN=/usr/$GNU_HOST + CROSS_STAGING_PREFIX=$CROSS_TOOLCHAIN/stage + CMAKE_CROSS_TOOLCHAIN=/tmp/arm.toolchain.cmake + + # https://cmake.org/cmake/help/v3.13/manual/cmake-toolchains.7.html#cross-compiling-for-linux + echo "set(CMAKE_SYSTEM_NAME Linux)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_SYSTEM_PROCESSOR arm)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_STAGING_PREFIX $CROSS_STAGING_PREFIX)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_SYSROOT ${CROSS_TOOLCHAIN}/sysroot)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_C_COMPILER /usr/bin/$C_COMPILER_ARM_LINUX)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_CXX_COMPILER /usr/bin/$CXX_COMPILER_ARM_LINUX)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> $CMAKE_CROSS_TOOLCHAIN && \ + echo "set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)" >> $CMAKE_CROSS_TOOLCHAIN + GRPC_DIR=$PWD/grpc + cd grpc && cd cmake/build && sudo make --jobs 5 --output-sync=target install && \ + GRPC_CROSS_BUILD_DIR=$GRPC_DIR/cmake/cross_build && \ + mkdir -p $GRPC_CROSS_BUILD_DIR && \ + cd $GRPC_CROSS_BUILD_DIR && \ + cmake -DCMAKE_TOOLCHAIN_FILE=$CMAKE_CROSS_TOOLCHAIN \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$CROSS_TOOLCHAIN/grpc_install \ + ../.. && \ + sudo make -j`nproc` install + - name: Build + id: build + run: | + GNU_HOST=aarch64-linux-gnu + C_COMPILER_ARM_LINUX=$GNU_HOST-gcc + CXX_COMPILER_ARM_LINUX=$GNU_HOST-g++ + + CROSS_TOOLCHAIN=/usr/$GNU_HOST + CROSS_STAGING_PREFIX=$CROSS_TOOLCHAIN/stage + CMAKE_CROSS_TOOLCHAIN=/tmp/arm.toolchain.cmake + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + export PATH=$PATH:$GOPATH/bin + export PATH=/usr/local/cuda/bin:$PATH + sudo rm -rf /usr/aarch64-linux-gnu/lib/libstdc++.so.6 + sudo cp -rf /usr/aarch64-linux-gnu/lib/libstdc++.so* /usr/aarch64-linux-gnu/lib/libstdc++.so.6 + sudo cp /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 ld.so + BACKEND_LIBS="./grpc/cmake/cross_build/third_party/re2/libre2.a ./grpc/cmake/cross_build/libgrpc.a ./grpc/cmake/cross_build/libgrpc++.a ./grpc/cmake/cross_build/third_party/protobuf/libprotobuf.a /usr/aarch64-linux-gnu/lib/libc.so.6 /usr/aarch64-linux-gnu/lib/libstdc++.so.6 /usr/aarch64-linux-gnu/lib/libgomp.so.1 /usr/aarch64-linux-gnu/lib/libm.so.6 /usr/aarch64-linux-gnu/lib/libgcc_s.so.1 /usr/aarch64-linux-gnu/lib/libdl.so.2 /usr/aarch64-linux-gnu/lib/libpthread.so.0 ./ld.so" \ + GOOS=linux \ + GOARCH=arm64 \ + CMAKE_ARGS="-DProtobuf_INCLUDE_DIRS=$CROSS_STAGING_PREFIX/include -DProtobuf_DIR=$CROSS_STAGING_PREFIX/lib/cmake/protobuf -DgRPC_DIR=$CROSS_STAGING_PREFIX/lib/cmake/grpc -DCMAKE_TOOLCHAIN_FILE=$CMAKE_CROSS_TOOLCHAIN -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++" make dist-cross-linux-arm64 + - uses: actions/upload-artifact@v4 + with: + name: LocalAI-linux-arm64 + path: release/ + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + release/* + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + build-linux: + runs-on: arc-runner-set + steps: + - name: Force Install GIT latest + run: | + sudo apt-get update \ + && sudo apt-get install -y software-properties-common \ + && sudo apt-get update \ + && sudo add-apt-repository -y ppa:git-core/ppa \ + && sudo apt-get update \ + && sudo apt-get install -y git + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install -y wget curl build-essential ffmpeg protobuf-compiler ccache upx-ucl gawk cmake libgmock-dev + - name: Intel Dependencies + run: | + wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo apt update + sudo apt install -y intel-basekit + - name: Install CUDA Dependencies + run: | + curl -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb + sudo dpkg -i cuda-keyring_1.1-1_all.deb + sudo apt-get update + sudo apt-get install -y cuda-nvcc-${CUDA_VERSION} libcublas-dev-${CUDA_VERSION} + env: + CUDA_VERSION: 12-5 + - name: "Install Hipblas" + env: + ROCM_VERSION: "6.1" + AMDGPU_VERSION: "6.1" + run: | + set -ex + + sudo apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates curl libnuma-dev gnupg + + curl -sL https://repo.radeon.com/rocm/rocm.gpg.key | sudo apt-key add - + + printf "deb [arch=amd64] https://repo.radeon.com/rocm/apt/$ROCM_VERSION/ jammy main" | sudo tee /etc/apt/sources.list.d/rocm.list + + printf "deb [arch=amd64] https://repo.radeon.com/amdgpu/$AMDGPU_VERSION/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/amdgpu.list + printf 'Package: *\nPin: release o=repo.radeon.com\nPin-Priority: 600' | sudo tee /etc/apt/preferences.d/rocm-pin-600 + sudo apt-get update + + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \ + hipblas-dev rocm-dev \ + rocblas-dev + + sudo apt-get clean + sudo rm -rf /var/lib/apt/lists/* + sudo ldconfig + - name: Cache grpc + id: cache-grpc + uses: actions/cache@v4 + with: + path: grpc + key: ${{ runner.os }}-grpc-${{ env.GRPC_VERSION }} + - name: Build grpc + if: steps.cache-grpc.outputs.cache-hit != 'true' + run: | + git clone --recurse-submodules -b ${{ env.GRPC_VERSION }} --depth 1 --shallow-submodules https://github.com/grpc/grpc && \ + cd grpc && sed -i "216i\ TESTONLY" "third_party/abseil-cpp/absl/container/CMakeLists.txt" && mkdir -p cmake/build && \ + cd cmake/build && cmake -DgRPC_INSTALL=ON \ + -DgRPC_BUILD_TESTS=OFF \ + ../.. && sudo make --jobs 5 --output-sync=target + - name: Install gRPC + run: | + cd grpc && cd cmake/build && sudo make --jobs 5 --output-sync=target install + # BACKEND_LIBS needed for gpu-workload: /opt/intel/oneapi/*/lib/libiomp5.so /opt/intel/oneapi/*/lib/libmkl_core.so /opt/intel/oneapi/*/lib/libmkl_core.so.2 /opt/intel/oneapi/*/lib/libmkl_intel_ilp64.so /opt/intel/oneapi/*/lib/libmkl_intel_ilp64.so.2 /opt/intel/oneapi/*/lib/libmkl_sycl_blas.so /opt/intel/oneapi/*/lib/libmkl_sycl_blas.so.4 /opt/intel/oneapi/*/lib/libmkl_tbb_thread.so /opt/intel/oneapi/*/lib/libmkl_tbb_thread.so.2 /opt/intel/oneapi/*/lib/libsycl.so /opt/intel/oneapi/*/lib/libsycl.so.7 /opt/intel/oneapi/*/lib/libsycl.so.7.1.0 /opt/rocm-*/lib/libamdhip64.so /opt/rocm-*/lib/libamdhip64.so.5 /opt/rocm-*/lib/libamdhip64.so.6 /opt/rocm-*/lib/libamdhip64.so.6.1.60100 /opt/rocm-*/lib/libhipblas.so /opt/rocm-*/lib/libhipblas.so.2 /opt/rocm-*/lib/libhipblas.so.2.1.60100 /opt/rocm-*/lib/librocblas.so /opt/rocm-*/lib/librocblas.so.4 /opt/rocm-*/lib/librocblas.so.4.1.60100 /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/lib/x86_64-linux-gnu/libOpenCL.so.1 /usr/lib/x86_64-linux-gnu/libOpenCL.so.1.0.0 /usr/lib/x86_64-linux-gnu/libm.so.6 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 /usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/librt.so.1 /usr/local/cuda-*/targets/x86_64-linux/lib/libcublas.so /usr/local/cuda-*/targets/x86_64-linux/lib/libcublasLt.so /usr/local/cuda-*/targets/x86_64-linux/lib/libcudart.so /usr/local/cuda-*/targets/x86_64-linux/lib/stubs/libcuda.so + - name: Build + id: build + run: | + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + export PATH=$PATH:$GOPATH/bin + export PATH=/usr/local/cuda/bin:$PATH + export PATH=/opt/rocm/bin:$PATH + source /opt/intel/oneapi/setvars.sh + sudo cp /lib64/ld-linux-x86-64.so.2 ld.so + BACKEND_LIBS="./ld.so ./sources/go-piper/piper/build/fi/lib/libfmt.a ./sources/go-piper/piper-phonemize/pi/lib/libonnxruntime.so.1.14.1 ./sources/go-piper/piper-phonemize/pi/src/libespeak-ng/libespeak-ng.so /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/librt.so.1 /usr/lib/x86_64-linux-gnu/libpthread.so.0 ./sources/go-piper/piper-phonemize/pi/lib/libpiper_phonemize.so.1 ./sources/go-piper/piper/build/si/lib/libspdlog.a ./sources/go-piper/espeak/ei/lib/libucd.so" \ + make -j4 dist + - uses: actions/upload-artifact@v4 + with: + name: LocalAI-linux + path: release/ + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + release/* + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + build-stablediffusion: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends libopencv-dev protobuf-compiler ccache upx-ucl + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + - name: Build stablediffusion + run: | + export PATH=$PATH:$GOPATH/bin + make backend-assets/grpc/stablediffusion + mkdir -p release && cp backend-assets/grpc/stablediffusion release + env: + GO_TAGS: stablediffusion + - uses: actions/upload-artifact@v4 + with: + name: stablediffusion + path: release/ + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + release/* + + build-macOS-x86_64: + runs-on: macos-13 + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + brew install protobuf grpc + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@8ba23be9613c672d40ae261d2a1335d639bdd59b + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.0 + - name: Build + id: build + run: | + export C_INCLUDE_PATH=/usr/local/include + export CPLUS_INCLUDE_PATH=/usr/local/include + export PATH=$PATH:$GOPATH/bin + export SKIP_GRPC_BACKEND=backend-assets/grpc/whisper + make dist + - uses: actions/upload-artifact@v4 + with: + name: LocalAI-MacOS-x86_64 + path: release/ + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + release/* + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + + build-macOS-arm64: + runs-on: macos-14 + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-go@v5 + with: + go-version: '1.21.x' + cache: false + - name: Dependencies + run: | + brew install protobuf grpc libomp llvm + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + - name: Build + id: build + run: | + export C_INCLUDE_PATH=/usr/local/include + export CPLUS_INCLUDE_PATH=/usr/local/include + export PATH=$PATH:$GOPATH/bin + export CC=/opt/homebrew/opt/llvm/bin/clang + make dist + - uses: actions/upload-artifact@v4 + with: + name: LocalAI-MacOS-arm64 + path: release/ + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + release/* + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true diff --git a/.github/workflows/secscan.yaml b/.github/workflows/secscan.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3fd808e116e9b8fecfcf352406c34e3088ff45ad --- /dev/null +++ b/.github/workflows/secscan.yaml @@ -0,0 +1,30 @@ +name: "Security Scan" + +# Run workflow each time code is pushed to your repository and on a schedule. +# The scheduled workflow runs every at 00:00 on Sunday UTC time. +on: + push: + schedule: + - cron: '0 0 * * 0' + +jobs: + tests: + runs-on: ubuntu-latest + env: + GO111MODULE: on + steps: + - name: Checkout Source + uses: actions/checkout@v4 + if: ${{ github.actor != 'dependabot[bot]' }} + - name: Run Gosec Security Scanner + if: ${{ github.actor != 'dependabot[bot]' }} + uses: securego/gosec@v2.21.4 + with: + # we let the report trigger content trigger a failure using the GitHub Security features. + args: '-no-fail -fmt sarif -out results.sarif ./...' + - name: Upload SARIF file + if: ${{ github.actor != 'dependabot[bot]' }} + uses: github/codeql-action/upload-sarif@v3 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: results.sarif diff --git a/.github/workflows/test-extra.yml b/.github/workflows/test-extra.yml new file mode 100644 index 0000000000000000000000000000000000000000..a2c3487295aee47614e9cdf94a3d0c500d4acf10 --- /dev/null +++ b/.github/workflows/test-extra.yml @@ -0,0 +1,302 @@ +--- +name: 'Tests extras backends' + +on: + pull_request: + push: + branches: + - master + tags: + - '*' + +concurrency: + group: ci-tests-extra-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + tests-transformers: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test transformers + run: | + make --jobs=5 --output-sync=target -C backend/python/transformers + make --jobs=5 --output-sync=target -C backend/python/transformers test + + tests-sentencetransformers: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test sentencetransformers + run: | + make --jobs=5 --output-sync=target -C backend/python/sentencetransformers + make --jobs=5 --output-sync=target -C backend/python/sentencetransformers test + + + tests-rerankers: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test rerankers + run: | + make --jobs=5 --output-sync=target -C backend/python/rerankers + make --jobs=5 --output-sync=target -C backend/python/rerankers test + + tests-diffusers: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential ffmpeg + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + pip install --user --no-cache-dir grpcio-tools==1.64.1 + - name: Test diffusers + run: | + make --jobs=5 --output-sync=target -C backend/python/diffusers + make --jobs=5 --output-sync=target -C backend/python/diffusers test + + tests-parler-tts: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test parler-tts + run: | + make --jobs=5 --output-sync=target -C backend/python/parler-tts + make --jobs=5 --output-sync=target -C backend/python/parler-tts test + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + + tests-openvoice: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test openvoice + run: | + make --jobs=5 --output-sync=target -C backend/python/openvoice + make --jobs=5 --output-sync=target -C backend/python/openvoice test + + tests-transformers-musicgen: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + + - name: Test transformers-musicgen + run: | + make --jobs=5 --output-sync=target -C backend/python/transformers-musicgen + make --jobs=5 --output-sync=target -C backend/python/transformers-musicgen test + + # tests-bark: + # runs-on: ubuntu-latest + # steps: + # - name: Release space from worker + # run: | + # echo "Listing top largest packages" + # pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + # head -n 30 <<< "${pkgs}" + # echo + # df -h + # echo + # sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true + # sudo apt-get remove --auto-remove android-sdk-platform-tools || true + # sudo apt-get purge --auto-remove android-sdk-platform-tools || true + # sudo rm -rf /usr/local/lib/android + # sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true + # sudo rm -rf /usr/share/dotnet + # sudo apt-get remove -y '^mono-.*' || true + # sudo apt-get remove -y '^ghc-.*' || true + # sudo apt-get remove -y '.*jdk.*|.*jre.*' || true + # sudo apt-get remove -y 'php.*' || true + # sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true + # sudo apt-get remove -y '^google-.*' || true + # sudo apt-get remove -y azure-cli || true + # sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true + # sudo apt-get remove -y '^gfortran-.*' || true + # sudo apt-get remove -y microsoft-edge-stable || true + # sudo apt-get remove -y firefox || true + # sudo apt-get remove -y powershell || true + # sudo apt-get remove -y r-base-core || true + # sudo apt-get autoremove -y + # sudo apt-get clean + # echo + # echo "Listing top largest packages" + # pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + # head -n 30 <<< "${pkgs}" + # echo + # sudo rm -rfv build || true + # sudo rm -rf /usr/share/dotnet || true + # sudo rm -rf /opt/ghc || true + # sudo rm -rf "/usr/local/share/boost" || true + # sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true + # df -h + # - name: Clone + # uses: actions/checkout@v4 + # with: + # submodules: true + # - name: Dependencies + # run: | + # sudo apt-get update + # sudo apt-get install build-essential ffmpeg + # # Install UV + # curl -LsSf https://astral.sh/uv/install.sh | sh + # sudo apt-get install -y ca-certificates cmake curl patch python3-pip + # sudo apt-get install -y libopencv-dev + # pip install --user --no-cache-dir grpcio-tools==1.64.1 + + # - name: Test bark + # run: | + # make --jobs=5 --output-sync=target -C backend/python/bark + # make --jobs=5 --output-sync=target -C backend/python/bark test + + + # Below tests needs GPU. Commented out for now + # TODO: Re-enable as soon as we have GPU nodes + # tests-vllm: + # runs-on: ubuntu-latest + # steps: + # - name: Clone + # uses: actions/checkout@v4 + # with: + # submodules: true + # - name: Dependencies + # run: | + # sudo apt-get update + # sudo apt-get install build-essential ffmpeg + # # Install UV + # curl -LsSf https://astral.sh/uv/install.sh | sh + # sudo apt-get install -y ca-certificates cmake curl patch python3-pip + # sudo apt-get install -y libopencv-dev + # pip install --user --no-cache-dir grpcio-tools==1.64.1 + # - name: Test vllm + # run: | + # make --jobs=5 --output-sync=target -C backend/python/vllm + # make --jobs=5 --output-sync=target -C backend/python/vllm test + tests-vallex: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake curl patch python3-pip + sudo apt-get install -y libopencv-dev + pip install --user --no-cache-dir grpcio-tools==1.64.1 + - name: Test vall-e-x + run: | + make --jobs=5 --output-sync=target -C backend/python/vall-e-x + make --jobs=5 --output-sync=target -C backend/python/vall-e-x test + + tests-coqui: + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ffmpeg + sudo apt-get install -y ca-certificates cmake curl patch espeak espeak-ng python3-pip + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + pip install --user --no-cache-dir grpcio-tools==1.64.1 + - name: Test coqui + run: | + make --jobs=5 --output-sync=target -C backend/python/coqui + make --jobs=5 --output-sync=target -C backend/python/coqui test diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000000000000000000000000000000000..ecef0569d3b0f7bd2587bd8ce433e5ec1e149c3b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,242 @@ +--- +name: 'tests' + +on: + pull_request: + push: + branches: + - master + tags: + - '*' + +env: + GRPC_VERSION: v1.65.0 + +concurrency: + group: ci-tests-${{ github.head_ref || github.ref }}-${{ github.repository }} + cancel-in-progress: true + +jobs: + tests-linux: + runs-on: ubuntu-latest + strategy: + matrix: + go-version: ['1.21.x'] + steps: + - name: Release space from worker + run: | + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + df -h + echo + sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true + sudo apt-get remove --auto-remove android-sdk-platform-tools || true + sudo apt-get purge --auto-remove android-sdk-platform-tools || true + sudo rm -rf /usr/local/lib/android + sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true + sudo rm -rf /usr/share/dotnet + sudo apt-get remove -y '^mono-.*' || true + sudo apt-get remove -y '^ghc-.*' || true + sudo apt-get remove -y '.*jdk.*|.*jre.*' || true + sudo apt-get remove -y 'php.*' || true + sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true + sudo apt-get remove -y '^google-.*' || true + sudo apt-get remove -y azure-cli || true + sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true + sudo apt-get remove -y '^gfortran-.*' || true + sudo apt-get autoremove -y + sudo apt-get clean + echo + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + sudo rm -rfv build || true + df -h + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + cache: false + # You can test your matrix by printing the current Go version + - name: Display Go version + run: go version + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ccache upx-ucl curl ffmpeg + sudo apt-get install -y libgmock-dev + curl https://repo.anaconda.com/pkgs/misc/gpgkeys/anaconda.asc | gpg --dearmor > conda.gpg && \ + sudo install -o root -g root -m 644 conda.gpg /usr/share/keyrings/conda-archive-keyring.gpg && \ + gpg --keyring /usr/share/keyrings/conda-archive-keyring.gpg --no-default-keyring --fingerprint 34161F5BF5EB1D4BFBBB8F0A8AEB4F8B29D82806 && \ + sudo /bin/bash -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/conda-archive-keyring.gpg] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main" > /etc/apt/sources.list.d/conda.list' && \ + sudo /bin/bash -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/conda-archive-keyring.gpg] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main" | tee -a /etc/apt/sources.list.d/conda.list' && \ + sudo apt-get update && \ + sudo apt-get install -y conda + # Install UV + curl -LsSf https://astral.sh/uv/install.sh | sh + sudo apt-get install -y ca-certificates cmake patch python3-pip unzip + sudo apt-get install -y libopencv-dev + + curl -L -s https://github.com/protocolbuffers/protobuf/releases/download/v26.1/protoc-26.1-linux-x86_64.zip -o protoc.zip && \ + unzip -j -d /usr/local/bin protoc.zip bin/protoc && \ + rm protoc.zip + + curl -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb + sudo dpkg -i cuda-keyring_1.1-1_all.deb + sudo apt-get update + sudo apt-get install -y cuda-nvcc-${CUDA_VERSION} libcublas-dev-${CUDA_VERSION} + export CUDACXX=/usr/local/cuda/bin/nvcc + + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + + # The python3-grpc-tools package in 22.04 is too old + pip install --user grpcio-tools + + sudo rm -rfv /usr/bin/conda || true + PATH=$PATH:/opt/conda/bin make -C backend/python/sentencetransformers + + # Pre-build piper before we start tests in order to have shared libraries in place + make sources/go-piper && \ + GO_TAGS="tts" make -C sources/go-piper piper.o && \ + sudo cp -rfv sources/go-piper/piper-phonemize/pi/lib/. /usr/lib/ && \ + # Pre-build stable diffusion before we install a newer version of abseil (not compatible with stablediffusion-ncn) + PATH="$PATH:/root/go/bin" GO_TAGS="stablediffusion tts" GRPC_BACKENDS=backend-assets/grpc/stablediffusion make build + env: + CUDA_VERSION: 12-4 + - name: Cache grpc + id: cache-grpc + uses: actions/cache@v4 + with: + path: grpc + key: ${{ runner.os }}-grpc-${{ env.GRPC_VERSION }} + - name: Build grpc + if: steps.cache-grpc.outputs.cache-hit != 'true' + run: | + git clone --recurse-submodules -b ${{ env.GRPC_VERSION }} --depth 1 --jobs 5 --shallow-submodules https://github.com/grpc/grpc && \ + cd grpc && sed -i "216i\ TESTONLY" "third_party/abseil-cpp/absl/container/CMakeLists.txt" && mkdir -p cmake/build && cd cmake/build && \ + cmake -DgRPC_INSTALL=ON \ + -DgRPC_BUILD_TESTS=OFF \ + ../.. && sudo make --jobs 5 + - name: Install gRPC + run: | + cd grpc && cd cmake/build && sudo make --jobs 5 install + - name: Test + run: | + PATH="$PATH:/root/go/bin" GO_TAGS="stablediffusion tts" make --jobs 5 --output-sync=target test + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + + tests-aio-container: + runs-on: ubuntu-latest + steps: + - name: Release space from worker + run: | + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + df -h + echo + sudo apt-get remove -y '^llvm-.*|^libllvm.*' || true + sudo apt-get remove --auto-remove android-sdk-platform-tools || true + sudo apt-get purge --auto-remove android-sdk-platform-tools || true + sudo rm -rf /usr/local/lib/android + sudo apt-get remove -y '^dotnet-.*|^aspnetcore-.*' || true + sudo rm -rf /usr/share/dotnet + sudo apt-get remove -y '^mono-.*' || true + sudo apt-get remove -y '^ghc-.*' || true + sudo apt-get remove -y '.*jdk.*|.*jre.*' || true + sudo apt-get remove -y 'php.*' || true + sudo apt-get remove -y hhvm powershell firefox monodoc-manual msbuild || true + sudo apt-get remove -y '^google-.*' || true + sudo apt-get remove -y azure-cli || true + sudo apt-get remove -y '^mongo.*-.*|^postgresql-.*|^mysql-.*|^mssql-.*' || true + sudo apt-get remove -y '^gfortran-.*' || true + sudo apt-get autoremove -y + sudo apt-get clean + echo + echo "Listing top largest packages" + pkgs=$(dpkg-query -Wf '${Installed-Size}\t${Package}\t${Status}\n' | awk '$NF == "installed"{print $1 "\t" $2}' | sort -nr) + head -n 30 <<< "${pkgs}" + echo + sudo rm -rfv build || true + df -h + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Dependencies + run: | + # Install protoc + curl -L -s https://github.com/protocolbuffers/protobuf/releases/download/v26.1/protoc-26.1-linux-x86_64.zip -o protoc.zip && \ + unzip -j -d /usr/local/bin protoc.zip bin/protoc && \ + rm protoc.zip + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + PATH="$PATH:$HOME/go/bin" make protogen-go + - name: Build images + run: | + docker build --build-arg FFMPEG=true --build-arg IMAGE_TYPE=extras --build-arg EXTRA_BACKENDS=rerankers --build-arg MAKEFLAGS="--jobs=5 --output-sync=target" -t local-ai:tests -f Dockerfile . + BASE_IMAGE=local-ai:tests DOCKER_AIO_IMAGE=local-ai-aio:test make docker-aio + - name: Test + run: | + PATH="$PATH:$HOME/go/bin" LOCALAI_MODELS_DIR=$PWD/models LOCALAI_IMAGE_TAG=test LOCALAI_IMAGE=local-ai-aio \ + make run-e2e-aio + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true + + tests-apple: + runs-on: macOS-14 + strategy: + matrix: + go-version: ['1.21.x'] + steps: + - name: Clone + uses: actions/checkout@v4 + with: + submodules: true + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + cache: false + # You can test your matrix by printing the current Go version + - name: Display Go version + run: go version + - name: Dependencies + run: | + brew install protobuf grpc make protoc-gen-go protoc-gen-go-grpc libomp llvm + pip install --user --no-cache-dir grpcio-tools + - name: Test + run: | + export C_INCLUDE_PATH=/usr/local/include + export CPLUS_INCLUDE_PATH=/usr/local/include + export CC=/opt/homebrew/opt/llvm/bin/clang + # Used to run the newer GNUMake version from brew that supports --output-sync + export PATH="/opt/homebrew/opt/make/libexec/gnubin:$PATH" + BUILD_TYPE="GITHUB_CI_HAS_BROKEN_METAL" CMAKE_ARGS="-DGGML_F16C=OFF -DGGML_AVX512=OFF -DGGML_AVX2=OFF -DGGML_FMA=OFF" make --jobs 4 --output-sync=target test + - name: Setup tmate session if tests fail + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3.19 + with: + detached: true + connect-timeout-seconds: 180 + limit-access-to-actor: true diff --git a/.github/workflows/update_swagger.yaml b/.github/workflows/update_swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fb4762f826db4855d0148cb1eeef4d3e9319c8db --- /dev/null +++ b/.github/workflows/update_swagger.yaml @@ -0,0 +1,37 @@ +name: Update swagger +on: + schedule: + - cron: 0 20 * * * + workflow_dispatch: +jobs: + swagger: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install protobuf-compiler + - run: | + go install github.com/swaggo/swag/cmd/swag@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1958fcbe2ca8bd93af633f11e97d44e567e945af + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.2 + - name: Bump swagger 🔧 + run: | + make protogen-go swagger + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.UPDATE_BOT_TOKEN }} + push-to-fork: ci-forks/LocalAI + commit-message: 'feat(swagger): update swagger' + title: 'feat(swagger): update swagger' + branch: "update/swagger" + body: Update swagger + signoff: true + diff --git a/.github/workflows/yaml-check.yml b/.github/workflows/yaml-check.yml new file mode 100644 index 0000000000000000000000000000000000000000..68b5e987322a5e1d31357d6215a5b51197f6dbfb --- /dev/null +++ b/.github/workflows/yaml-check.yml @@ -0,0 +1,18 @@ +name: 'Yamllint GitHub Actions' +on: + - pull_request +jobs: + yamllint: + name: 'Yamllint' + runs-on: ubuntu-latest + steps: + - name: 'Checkout' + uses: actions/checkout@master + - name: 'Yamllint' + uses: karancode/yamllint-github-action@master + with: + yamllint_file_or_dir: 'gallery' + yamllint_strict: false + yamllint_comment: true + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..7203cb3f17c6038d175f2276f1fa943df4ad6034 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "golang.go" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..504934210b3b550f6e2f8721f0cf474e52e10c10 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,34 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": false, + "cwd": "${fileDirname}", + "env": { + "OPENAI_API_BASE": "http://localhost:8080/v1", + "OPENAI_API_KEY": "abc" + } + }, + { + "name": "Launch LocalAI API", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceRoot}", + "args": [], + "env": { + "LOCALAI_LOG_LEVEL": "debug", + "LOCALAI_P2P": "true", + "LOCALAI_FEDERATED": "true" + }, + "buildFlags": ["-tags", "stablediffusion p2p tts", "-v"], + "envFile": "${workspaceFolder}/.env", + "cwd": "${workspaceRoot}" + } + ] +} \ No newline at end of file