diff --git a/.scripts/build_steps.sh b/.scripts/build_steps.sh index 5c97f74..a5a9998 100755 --- a/.scripts/build_steps.sh +++ b/.scripts/build_steps.sh @@ -36,7 +36,7 @@ mv /opt/conda/conda-meta/history /opt/conda/conda-meta/history.$(date +%Y-%m-%d- echo > /opt/conda/conda-meta/history micromamba install --root-prefix ~/.conda --prefix /opt/conda \ --yes --override-channels --channel conda-forge --strict-channel-priority \ - pip python=3.12 conda-build conda-forge-ci-setup=4 "conda-build>=26.3" + pip rattler-build conda-forge-ci-setup=4 "conda-build>=26.3" export CONDA_LIBMAMBA_SOLVER_NO_CHANNELS_FROM_INSTALLED=1 # set up the condarc @@ -50,7 +50,7 @@ source run_conda_forge_build_setup make_build_number "${FEEDSTOCK_ROOT}" "${RECIPE_ROOT}" "${CONFIG_FILE}" if [[ "${HOST_PLATFORM}" != "${BUILD_PLATFORM}" ]] && [[ "${HOST_PLATFORM}" != linux-* ]] && [[ "${BUILD_WITH_CONDA_DEBUG:-0}" != 1 ]]; then - EXTRA_CB_OPTIONS="${EXTRA_CB_OPTIONS:-} --no-test" + EXTRA_CB_OPTIONS="${EXTRA_CB_OPTIONS:-} --test skip" fi @@ -67,15 +67,15 @@ if [[ "${BUILD_WITH_CONDA_DEBUG:-0}" == 1 ]]; then # - --output-id vs. --output-name # - --clobber-file vs. none # - none vs. --target-platform - conda debug \ - "${RECIPE_ROOT}" \ + export CONDA_BLD_PATH="${CONDA_BLD_PATH:-${FEEDSTOCK_ROOT}/build_artifacts}" + rattler-build debug setup \ + --recipe "${RECIPE_ROOT}" \ -m "${CI_SUPPORT}/${CONFIG}.yaml" \ ${EXTRA_CB_OPTIONS:-} \ - ${BUILD_OUTPUT_ID:+--output-id "${BUILD_OUTPUT_ID}"} \ - --clobber-file "${CI_SUPPORT}/clobber_${CONFIG}.yaml" + ${BUILD_OUTPUT_ID:+--output-name "${BUILD_OUTPUT_ID}"} \ + --target-platform "${HOST_PLATFORM}" - # Drop into an interactive shell - /bin/bash + rattler-build debug shell else # differences between conda-build vs. rattler-build # - recipe is positional vs. --recipe "${RECIPE_ROOT}" @@ -83,13 +83,15 @@ else # - --clobber-file vs. none # - none vs. --target-platform # - --extra-meta a=b c=d vs. --extra-meta a=b --extra-meta c=d - conda-build \ - "${RECIPE_ROOT}" \ + + rattler-build build \ + --recipe "${RECIPE_ROOT}" \ -m "${CI_SUPPORT}/${CONFIG}.yaml" \ ${EXTRA_CB_OPTIONS:-} \ - --suppress-variables \ - --clobber-file "${CI_SUPPORT}/clobber_${CONFIG}.yaml" \ - --extra-meta flow_run_id="${flow_run_id:-}" remote_url="${remote_url:-}" sha="${sha:-}" + --target-platform "${HOST_PLATFORM}" \ + --extra-meta flow_run_id="${flow_run_id:-}" \ + --extra-meta remote_url="${remote_url:-}" \ + --extra-meta sha="${sha:-}" ( startgroup "Inspecting artifacts" ) 2> /dev/null # inspect_artifacts was only added in conda-forge-ci-setup 4.9.4 diff --git a/.scripts/run_osx_build.sh b/.scripts/run_osx_build.sh index b0eda55..18a7c7f 100755 --- a/.scripts/run_osx_build.sh +++ b/.scripts/run_osx_build.sh @@ -26,7 +26,7 @@ chmod +x "${micromamba_exe}" echo "Creating environment" "${micromamba_exe}" create --yes --root-prefix "${MAMBA_ROOT_PREFIX}" --prefix "${MINIFORGE_HOME}" \ --channel conda-forge \ - pip python=3.12 conda-build conda-forge-ci-setup=4 "conda-build>=26.3" + pip rattler-build conda-forge-ci-setup=4 "conda-build>=26.3" echo "Moving pkgs cache from ${MAMBA_ROOT_PREFIX} to ${MINIFORGE_HOME}" mv "${MAMBA_ROOT_PREFIX}/pkgs" "${MINIFORGE_HOME}" echo "Cleaning up micromamba" @@ -89,33 +89,33 @@ source run_conda_forge_build_setup ( endgroup "Configuring conda" ) 2> /dev/null -echo -e "\n\nMaking the build clobber file" -make_build_number ./ ./recipe ./.ci_support/${CONFIG}.yaml - if [[ -f LICENSE.txt ]]; then cp LICENSE.txt "recipe/recipe-scripts-license.txt" fi if [[ "${BUILD_WITH_CONDA_DEBUG:-0}" == 1 ]]; then - if [[ "x${BUILD_OUTPUT_ID:-}" != "x" ]]; then - EXTRA_CB_OPTIONS="${EXTRA_CB_OPTIONS:-} --output-id ${BUILD_OUTPUT_ID}" - fi - conda debug ./recipe -m ./.ci_support/${CONFIG}.yaml \ - ${EXTRA_CB_OPTIONS:-} \ - --clobber-file ./.ci_support/clobber_${CONFIG}.yaml - - # Drop into an interactive shell - /bin/bash + export CONDA_BLD_PATH="${CONDA_BLD_PATH:-${FEEDSTOCK_ROOT:-$PWD}/build_artifacts}" + rattler-build debug setup \ + --recipe ./recipe \ + -m ./.ci_support/${CONFIG}.yaml \ + --target-platform "${HOST_PLATFORM}" \ + ${BUILD_OUTPUT_ID:+--output-name "${BUILD_OUTPUT_ID}"} \ + ${EXTRA_CB_OPTIONS:-} + + rattler-build debug shell else if [[ "${HOST_PLATFORM}" != "${BUILD_PLATFORM}" ]]; then - EXTRA_CB_OPTIONS="${EXTRA_CB_OPTIONS:-} --no-test" + EXTRA_CB_OPTIONS="${EXTRA_CB_OPTIONS:-} --test skip" fi - conda-build ./recipe -m ./.ci_support/${CONFIG}.yaml \ - --suppress-variables ${EXTRA_CB_OPTIONS:-} \ - --clobber-file ./.ci_support/clobber_${CONFIG}.yaml \ - --extra-meta flow_run_id="$flow_run_id" remote_url="$remote_url" sha="$sha" + rattler-build build --recipe ./recipe \ + -m ./.ci_support/${CONFIG}.yaml \ + ${EXTRA_CB_OPTIONS:-} \ + --target-platform "${HOST_PLATFORM}" \ + --extra-meta flow_run_id="$flow_run_id" \ + --extra-meta remote_url="$remote_url" \ + --extra-meta sha="$sha" ( startgroup "Inspecting artifacts" ) 2> /dev/null diff --git a/.scripts/run_win_build.bat b/.scripts/run_win_build.bat index c07d98e..8d64121 100755 --- a/.scripts/run_win_build.bat +++ b/.scripts/run_win_build.bat @@ -31,7 +31,7 @@ if !errorlevel! neq 0 exit /b !errorlevel! echo Creating environment call "%MICROMAMBA_EXE%" create --yes --root-prefix "%MAMBA_ROOT_PREFIX%" --prefix "%MINIFORGE_HOME%" ^ --channel conda-forge ^ - pip python=3.12 conda-build conda-forge-ci-setup=4 "conda-build>=26.3" + pip rattler-build conda-forge-ci-setup=4 "conda-build>=26.3" if !errorlevel! neq 0 exit /b !errorlevel! echo Removing %MAMBA_ROOT_PREFIX% del /S /Q "%MAMBA_ROOT_PREFIX%" >nul @@ -64,19 +64,19 @@ if EXIST LICENSE.txt ( ) if NOT [%HOST_PLATFORM%] == [%BUILD_PLATFORM%] ( if [%CROSSCOMPILING_EMULATOR%] == [] ( - set "EXTRA_CB_OPTIONS=%EXTRA_CB_OPTIONS% --no-test" + set "EXTRA_CB_OPTIONS=%EXTRA_CB_OPTIONS% --test skip" ) ) if NOT [%flow_run_id%] == [] ( - set "EXTRA_CB_OPTIONS=%EXTRA_CB_OPTIONS% --extra-meta flow_run_id=%flow_run_id% remote_url=%remote_url% sha=%sha%" + set "EXTRA_CB_OPTIONS=%EXTRA_CB_OPTIONS% --extra-meta flow_run_id=%flow_run_id% --extra-meta remote_url=%remote_url% --extra-meta sha=%sha%" ) call :end_group :: Build the recipe echo Building recipe -conda-build.exe "recipe" -m .ci_support\%CONFIG%.yaml --suppress-variables %EXTRA_CB_OPTIONS% +rattler-build.exe build --recipe "recipe" -m .ci_support\%CONFIG%.yaml %EXTRA_CB_OPTIONS% --target-platform %HOST_PLATFORM% if !errorlevel! neq 0 exit /b !errorlevel! call :start_group "Inspecting artifacts" diff --git a/conda-forge.yml b/conda-forge.yml index 683ad2c..ef44705 100644 --- a/conda-forge.yml +++ b/conda-forge.yml @@ -1,5 +1,6 @@ build_platform: osx_arm64: osx_64 +conda_build_tool: rattler-build conda_build: error_overlinking: true conda_forge_output_validation: true diff --git a/recipe/meta.yaml b/recipe/meta.yaml deleted file mode 100644 index f724d10..0000000 --- a/recipe/meta.yaml +++ /dev/null @@ -1,80 +0,0 @@ -{% set name = "llama-cpp-python" %} -# NOTE: VERIFY llama_cpp_version before merging! -{% set version = "0.3.32" %} -{% set llama_cpp_version = "9851" %} - -package: - name: {{ name|lower }} - version: {{ version }} - -source: - url: https://pypi.org/packages/source/{{ name[0] }}/{{ name }}/llama_cpp_python-{{ version }}.tar.gz - sha256: b06502361770f82eb08b7f1a192eb084b9ead2b88fe32cda8c397a2782eabde6 - patches: - # Asks cdll to look for the library in the path as well. - - 0001-Adapt-shared-library-relocation.patch - -build: - number: 0 - script: - - export CMAKE_ARGS="${CMAKE_ARGS} -DLLAMA_BUILD=OFF" # [unix] - - set CMAKE_ARGS=%CMAKE_ARGS% -DLLAMA_BUILD=OFF # [win] - - export CMAKE_ARGS="${CMAKE_ARGS} -DLLAVA_BUILD=OFF" # [unix] - - set CMAKE_ARGS=%CMAKE_ARGS% -DLLAVA_BUILD=OFF # [win] - - - {{ PYTHON }} -m pip install . -vv -requirements: - build: - - python # [build_platform != target_platform] - - cross-python_{{ target_platform }} # [build_platform != target_platform] - - - {{ compiler('c') }} - - {{ stdlib("c") }} - - {{ compiler('cxx') }} - - cmake - - make - - pkgconfig - - host: - - python - - scikit-build-core >=0.5.1 - - pip - - run: - - python - - typing-extensions >=4.5.0 - - numpy >=1.20.0 - - diskcache >=5.6.1 - - pyyaml >=5.1 - - - llama.cpp {{ llama_cpp_version }} - - # Split into llama-cpp-python-server - - uvicorn >=0.22.0 - - fastapi >=0.100.0 - - pydantic-settings >=2.0.1 - - sse-starlette >=1.6.1 - - starlette-context >=0.3.6,<0.4 -test: - imports: - - llama_cpp - commands: - - pip check - requires: - - pip - -about: - home: https://github.com/abetlen/llama-cpp-python - summary: Python bindings for the llama.cpp library - license: MIT - license_file: - - LICENSE.md - -extra: - recipe-maintainers: - - JohanMabille - - jjerphan - - jonashaag - - YYYasin19 - - sodre - - toniher diff --git a/recipe/recipe.yaml b/recipe/recipe.yaml new file mode 100644 index 0000000..e00bdc4 --- /dev/null +++ b/recipe/recipe.yaml @@ -0,0 +1,98 @@ +schema_version: 1 + +context: + name: llama-cpp-python + version: "0.3.32" + # NOTE: VERIFY llama_cpp_version before merging! + llama_cpp_version: "9851" + +package: + name: ${{ name|lower }} + version: ${{ version }} + +source: + url: https://pypi.org/packages/source/${{ name[0] }}/${{ name }}/llama_cpp_python-${{ version }}.tar.gz + sha256: b06502361770f82eb08b7f1a192eb084b9ead2b88fe32cda8c397a2782eabde6 + patches: + # Asks cdll to look for the library in the path as well. + - 0001-Adapt-shared-library-relocation.patch + +build: + number: 1 + script: + - if: win + then: + - set "CMAKE_ARGS=%CMAKE_ARGS% -DLLAMA_BUILD=OFF -DLLAVA_BUILD=OFF" + - ${{ PYTHON }} -m pip install . -vv + else: + - export CMAKE_ARGS="${CMAKE_ARGS} -DLLAMA_BUILD=OFF -DLLAVA_BUILD=OFF" + - ${{ PYTHON }} -m pip install . -vv + +requirements: + build: + - if: build_platform != target_platform + then: + - python + - cross-python_${{ target_platform }} + - ${{ compiler('c') }} + - ${{ stdlib('c') }} + - ${{ compiler('cxx') }} + - cmake + - make + - pkgconfig + host: + - python + - scikit-build-core >=0.5.1 + - pip + run: + - python + - typing-extensions >=4.5.0 + - numpy >=1.20.0 + - diskcache >=5.6.1 + - pyyaml >=5.1 + - llama.cpp ==${{ llama_cpp_version }} + # Split into llama-cpp-python-server + - uvicorn >=0.22.0 + - fastapi >=0.100.0 + - pydantic-settings >=2.0.1 + - sse-starlette >=1.6.1 + - starlette-context >=0.3.6,<0.4 + +tests: + - python: + imports: + - llama_cpp + pip_check: true + - script: + # Exercises the bindings and calls into libllama. + - python test.py + # Downloads a tiny GGUF model and runs a full load/tokenize/inference/embed check. + - if: win + then: + - curl.exe -L --retry 3 -o tinystories.gguf https://huggingface.co/ggml-org/models/resolve/main/tinyllamas/stories260K.gguf + else: + - curl -L --retry 3 -o tinystories.gguf https://huggingface.co/ggml-org/models/resolve/main/tinyllamas/stories260K.gguf + - python test_gguf.py tinystories.gguf + requirements: + run: + - curl + files: + recipe: + - test.py + - test_gguf.py + +about: + homepage: https://github.com/abetlen/llama-cpp-python + summary: Python bindings for the llama.cpp library + license: MIT + license_file: + - LICENSE.md + +extra: + recipe-maintainers: + - JohanMabille + - jjerphan + - jonashaag + - YYYasin19 + - sodre + - toniher diff --git a/recipe/test.py b/recipe/test.py new file mode 100644 index 0000000..c7d06f8 --- /dev/null +++ b/recipe/test.py @@ -0,0 +1,4 @@ +import llama_cpp +print(llama_cpp.__version__) +print(llama_cpp.llama_backend_init()) # calls into libllama +llama_cpp.llama_backend_free() diff --git a/recipe/test_gguf.py b/recipe/test_gguf.py new file mode 100644 index 0000000..7b5adc8 --- /dev/null +++ b/recipe/test_gguf.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +import sys +import time + +def main(): + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(1) + + model_path = sys.argv[1] + + print("1. Importing llama_cpp ...", end=" ", flush=True) + from llama_cpp import Llama + print("OK") + + print(f"2. Loading model: {model_path} ...", end=" ", flush=True) + t0 = time.time() + llm = Llama(model_path=model_path, n_ctx=512, verbose=False) + print(f"OK ({time.time() - t0:.1f}s)") + + print("3. Tokenization ...", end=" ", flush=True) + tokens = llm.tokenize(b"Hello, world!") + assert len(tokens) > 0 + print(f"OK ({len(tokens)} tokens)") + + print("4. Inference ...", end=" ", flush=True) + t0 = time.time() + output = llm( + "Q: What is the capital of France? A:", + max_tokens=16, + stop=["Q:", "\n"], + echo=False, + ) + elapsed = time.time() - t0 + text = output["choices"][0]["text"].strip() + print(f"OK ({elapsed:.1f}s)") + print(f" Response: {text!r}") + + print("5. Embedding ...", end=" ", flush=True) + try: + emb_llm = Llama(model_path=model_path, embedding=True, n_ctx=64, verbose=False) + vec = emb_llm.embed("test sentence") + assert len(vec) > 0 + print(f"OK (dim={len(vec)})") + except Exception as e: + print(f"SKIP ({e})") + + print("\nAll checks passed.") + +if __name__ == "__main__": + main()