diff --git a/tasks/workstation/linux/software/llm.yml b/tasks/workstation/linux/software/llm.yml index de2f683..b9b19ff 100644 --- a/tasks/workstation/linux/software/llm.yml +++ b/tasks/workstation/linux/software/llm.yml @@ -26,12 +26,25 @@ - name: Workstation | Linux | Software | LLMs block: + - name: Workstation | Linux | Software | LLMs | Facts | Provisioned + debug: + var: "{{ item }}" + loop: + - ollama_enabled + - manage_models + - zeroclaw_enabled + - open_webui_enabled + - open_webui_port + - codium_config + - name: Workstation | Linux | Software | LLMs | Facts 01 ansible.builtin.set_fact: ollama: ollama zeroclaw: zeroclaw zerocode: zerocode qwen_code: qwen-code + dummy_service: 'cronie' + dummy_website: 'https://hyperling.com' # Good to keep low to prevent swap usage. llm_concurrency: "{{ (ansible_memtotal_mb / 64000) | round(0, method='ceil') | int }}" # Allow having multiple chats open without them just waiting each other. @@ -147,8 +160,8 @@ - name: Workstation | Linux | Software | LLMs | Packages | Install ansible.builtin.package: name: - - "{{ zeroclaw }}" - "{{ ollama }}" + - "{{ zeroclaw }}" - "{{ zerocode }}" - "{{ qwen_code }}" state: present @@ -273,7 +286,8 @@ mode: "0755" - - block: + - name: Workstation | Linux | Software | LLMs | runit | open-webui + block: - name: Workstation | Linux | Software | LLMs | runit | open-webui | Packages ansible.builtin.package: @@ -288,21 +302,14 @@ state: present when: ansible_pkg_mgr == "pacman" - - name: Workstation | Linux | Software | LLMs | runit | open-webui | Dir | Run - ansible.builtin.file: - name: "/etc/sv/open_webui" - state: directory - owner: root - mode: "0755" - - - name: Workstation | Linux | Software | LLMs | runit | open-webui | Dir | Log + - name: Workstation | Linux | Software | LLMs | runit | open-webui | Dir | /etc/sv ansible.builtin.file: name: "/etc/sv/open_webui/log" state: directory owner: root mode: "0755" - - name: Workstation | Linux | Software | LLMs | runit | open-webui | Dir | Log Config + - name: Workstation | Linux | Software | LLMs | runit | open-webui | Dir | /var/log ansible.builtin.file: name: "/var/log/open_webui" state: directory @@ -313,21 +320,52 @@ ansible.builtin.copy: dest: /etc/sv/open_webui/run content: | - #!/bin/sh -e + #!/bin/sh + exec 2>&1 + # Wait for Docker to start up. while [ ! -S /var/run/docker.sock ]; do sleep 1; done + + # Ensure the old container is gone. + echo "Stopping..." + docker stop open-webui && + echo "Container stopped" || + echo "Container already stopped." + echo "Deleting..." + docker rm -f open-webui && + echo "Container deleted" || + echo "Container already deleted." + # Start the open-webui program. + set -e exec docker run --rm \ - -p 3000:{{ open_webui_port }} \ + -p {{ open_webui_port }}:8080 \ --add-host=host.docker.internal:host-gateway \ -v open-webui:/app/backend/data \ - -e WEBUI_SECRET_KEY=your-secret-key \ + -e WEBUI_SECRET_KEY=7578094558f49cf38be40fc463cc0451 \ -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \ --name open-webui \ ghcr.io/open-webui/open-webui:main mode: "0755" - when: open_webui + - name: Workstation | Linux | Software | LLMs | runit | open-webui | Script | Log + ansible.builtin.copy: + dest: /etc/sv/open_webui/log/run + content: | + #!/bin/sh -e + exec svlogd -tt /var/log/open_webui + mode: "0755" + + - name: Workstation | Linux | Software | LLMs | runit | open-webui | Script | Log Config + ansible.builtin.copy: + dest: /var/log/open_webui/config + content: | + s1000000 # rotate at 1 MB + n5 # keep 5 old files + dateformat %Y-%m-%d_%H-%M-%S # each run gets its own file. + mode: "0755" + + when: open_webui_enabled when: ansible_service_mgr == "runit" @@ -337,10 +375,10 @@ state: started enabled: true loop: - - "{{ ollama }}" - - "{{ zeroclaw }}" - - "docker" - - "open_webui" + - "{{ ollama if ollama_enabled else dummy_service }}" + - "{{ zeroclaw if zeroclaw_enabled else dummy_service }}" + - "{{ 'docker' if open_webui_enabled else dummy_service }}" + - "{{ 'open_webui' if open_webui_enabled else dummy_service }}" - name: Workstation | Linux | Software | LLMs | Services | Verify ansible.builtin.uri: @@ -352,9 +390,21 @@ retries: 12 delay: 5 loop: - - http://127.0.0.1:11434/ - - http://127.0.0.1:42617/health - - http://127.0.0.1:3000 + - "{{ 'http://127.0.0.1:11434/' if ollama_enabled else dummy_website }}" + - "{{ 'http://127.0.0.1:42617/health' if zeroclaw_enabled else dummy_website }}" + + - name: Workstation | Linux | Software | LLMs | Services | Verify | Okay to Fail + ansible.builtin.uri: + url: "{{ item }}" + status_code: 200 + timeout: 5 + register: health + until: health.status == 200 + retries: 12 + delay: 5 + loop: + - "{{ 'http://127.0.0.1:3000/health' if open_webui_enabled else dummy_website }}" + ignore_errors: true #- name: Workstation | Linux | Software | LLMs | Config | zeroclaw | Root # ansible.builtin.blockinfile: @@ -419,54 +469,67 @@ - .bashrc - .zshrc - - name: Workstation | Linux | Software | LLMs | Models | ollama | Manual Script | Message - ansible.builtin.debug: - msg: <- - The next task may take hours, if not days. If you'd like a status bar, - I highly recommed reloading your RC file and running `pull-models`. - That will give you a much better idea of what's going on. + - name: Workstation | Linux | Software | LLMs | Models | ollama | Manage + block: - - name: Workstation | Linux | Software | LLMs | Models | ollama | Install - ansible.builtin.shell: | - set -o pipefail - item='{{ item.model }}' - if ollama list | grep -q $item; then - echo "OKAY" && - return - else - ollama pull $item 1>/dev/null && - echo "INSTALLED" && - return - fi - echo "FAILED" - loop: "{{ llm_installs }}" - register: shell_check - changed_when: "'INSTALLED' in shell_check.stdout" - failed_when: "'FAILED' in shell_check.stdout" - become: true - become_user: "{{ user }}" - when: llm_installs | length > 0 + - name: Workstation | Linux | Software | LLMs | Models | ollama | Manage | Message + ansible.builtin.debug: + msg: <- + The next task may take hours, if not days. If you'd like a status + bar to know what's being worked on and its progress, I highly + recommed reloading your RC file and running `pull-models`. That + will give you a much better idea of what's going on. - - name: Workstation | Linux | Software | LLMs | Models | ollama | Remove - ansible.builtin.shell: | - set -o pipefail - item='{{ item.model }}' - if ollama list | grep -q $item; then - ollama rm $item && - echo "INSTALLED" && - return - else - echo "OKAY" && - return - fi - echo "FAILED" - loop: "{{ llm_removals }}" - register: shell_check - changed_when: "'INSTALLED' in shell_check.stdout" - failed_when: "'FAILED' in shell_check.stdout" - become: true - become_user: "{{ user }}" - when: llm_removals | length > 0 + - name: Workstation | Linux | Software | LLMs | Models | ollama | Manage | Install + ansible.builtin.shell: | + set -o pipefail + item='{{ item.model }}' + if ollama list | grep -q $item; then + echo "OKAY" && + return + else + ollama pull $item 1>/dev/null && + echo "INSTALLED" && + return + fi + echo "FAILED" + loop: "{{ llm_installs }}" + register: shell_check + changed_when: "'INSTALLED' in shell_check.stdout" + failed_when: "'FAILED' in shell_check.stdout" + become: true + become_user: "{{ user }}" + when: manage_models + and llm_installs | length > 0 + + - name: Workstation | Linux | Software | LLMs | Models | ollama | Manage | Remove + ansible.builtin.shell: | + set -o pipefail + item='{{ item.model }}' + if ollama list | grep -q $item; then + ollama rm $item && + echo "INSTALLED" && + return + else + echo "OKAY" && + return + fi + echo "FAILED" + loop: "{{ llm_removals }}" + register: shell_check + changed_when: "'INSTALLED' in shell_check.stdout" + failed_when: "'FAILED' in shell_check.stdout" + become: true + become_user: "{{ user }}" + when: llm_removals | length > 0 + + when: manage_models + + - name: Workstation | Linux | Software | LLMs | Models | ollama | Get Models + ansible.builtin.shell: + cmd: ollama ls | tail -n +2 | awk '{print $1}' + register: llm_models + changed_when: llm_models.rc == 0 # Cheat Sheet: https://docs.zeroclaw.com/master/en/providers/configuration.html - name: Workstation | Linux | Software | LLMs | Models | zeroclaw | Add Providers @@ -476,14 +539,17 @@ insertafter: EOF block: | {% for llm in llm_installs %} + {% if llm.model in llm_models %} [providers.models.ollama.{{ llm.provider }}] model = "{{ llm.model }}" timeout_secs = 3600 # 1 hour, default is 120 (2 minutes), issue happens between 5 and 6 minutes though. context_window = {{ llm_context }} + {% endif %} {% endfor %} state: present create: false backup: true + when: zeroclaw_enabled - name: Workstation | Linux | Software | LLMs | Models | Continue | Config ansible.builtin.copy: @@ -495,6 +561,7 @@ schema: v1 models: {% for llm in llm_installs %} + {% if llm.model in llm_models %} - name: {{ llm.provider }} provider: ollama model: {{ llm.model }} @@ -509,7 +576,9 @@ maxTokens: {{ llm_context }} roles: - autocomplete + {% endif %} {% endfor %} mode: "0644" + when: codium_config when: ansible_pkg_mgr == "pacman"