Skip to content

Commit

Permalink
test: Split inference tests to text and vision (#1008)
Browse files Browse the repository at this point in the history
# What does this PR do?

This PR splits the inference tests into text and vision to make testing
on vLLM provider easier as mentioned in
#951 since serving
multiple models (e.g. Llama-3.2-11B-Vision-Instruct and
Llama-3.1-8B-Instruct) on a single port using the OpenAI API is [not
supported yet](https://docs.vllm.ai/en/v0.5.5/serving/faq.html) so it's
a bit tricky to test both at the same time.

## Test Plan

All previously passing tests related to text still pass:
`LLAMA_STACK_BASE_URL=http://localhost:5002 pytest -v
tests/client-sdk/inference/test_text_inference.py`

All vision tests passed via `LLAMA_STACK_BASE_URL=http://localhost:5002
pytest -v tests/client-sdk/inference/test_vision_inference.py`.

Signed-off-by: Yuan Tang <[email protected]>
  • Loading branch information
terrytangyuan authored Feb 7, 2025
1 parent a9950ce commit c97e05f
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 122 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
echo "REPORT_FILE=${REPORT_OUTPUT}" >> "$GITHUB_ENV"
export INFERENCE_MODEL=meta-llama/Llama-3.1-8B-Instruct
LLAMA_STACK_CONFIG=./llama_stack/templates/${{ matrix.provider }}/run.yaml pytest --md-report --md-report-verbose=1 ./tests/client-sdk/inference/test_inference.py --md-report-output "$REPORT_OUTPUT"
LLAMA_STACK_CONFIG=./llama_stack/templates/${{ matrix.provider }}/run.yaml pytest --md-report --md-report-verbose=1 ./tests/client-sdk/inference/ --md-report-output "$REPORT_OUTPUT"
- name: Output reports to the job summary
if: always()
Expand Down
6 changes: 3 additions & 3 deletions tests/client-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ You can run llama stack integration tests on either a Llama Stack Library or a L
To test on a Llama Stack library with certain configuration, run
```bash
LLAMA_STACK_CONFIG=./llama_stack/templates/cerebras/run.yaml
pytest -s -v tests/client-sdk/inference/test_inference.py
pytest -s -v tests/client-sdk/inference/
```
or just the template name
```bash
LLAMA_STACK_CONFIG=together
pytest -s -v tests/client-sdk/inference/test_inference.py
pytest -s -v tests/client-sdk/inference/
```

To test on a Llama Stack endpoint, run
```bash
LLAMA_STACK_BASE_URL=http//localhost:8089
pytest -s -v tests/client-sdk/inference/test_inference.py
pytest -s -v tests/client-sdk/inference
```

## Report Generation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

import base64
import pathlib

import pytest
from pydantic import BaseModel

Expand Down Expand Up @@ -56,23 +53,6 @@ def get_weather_tool_definition():
}


@pytest.fixture
def image_path():
return pathlib.Path(__file__).parent / "dog.png"


@pytest.fixture
def base64_image_data(image_path):
# Convert the image to base64
return base64.b64encode(image_path.read_bytes()).decode("utf-8")


@pytest.fixture
def base64_image_url(base64_image_data, image_path):
# suffix includes the ., so we remove it
return f"data:image/{image_path.suffix[1:]};base64,{base64_image_data}"


def test_text_completion_non_streaming(llama_stack_client, text_model_id):
response = llama_stack_client.inference.completion(
content="Complete the sentence using one word: Roses are red, violets are ",
Expand Down Expand Up @@ -299,101 +279,3 @@ class AnswerFormat(BaseModel):
assert answer.last_name == "Jordan"
assert answer.year_of_birth == 1963
assert answer.num_seasons_in_nba == 15


def test_image_chat_completion_non_streaming(llama_stack_client, vision_model_id):
message = {
"role": "user",
"content": [
{
"type": "image",
"image": {
"url": {
# TODO: Replace with Github based URI to resources/sample1.jpg
"uri": "https://www.healthypawspetinsurance.com/Images/V3/DogAndPuppyInsurance/Dog_CTA_Desktop_HeroImage.jpg"
},
},
},
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=False,
)
message_content = response.completion_message.content.lower().strip()
assert len(message_content) > 0
assert any(expected in message_content for expected in {"dog", "puppy", "pup"})


def test_image_chat_completion_streaming(llama_stack_client, vision_model_id):
message = {
"role": "user",
"content": [
{
"type": "image",
"image": {
"url": {
# TODO: Replace with Github based URI to resources/sample1.jpg
"uri": "https://www.healthypawspetinsurance.com/Images/V3/DogAndPuppyInsurance/Dog_CTA_Desktop_HeroImage.jpg"
},
},
},
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=True,
)
streamed_content = ""
for chunk in response:
streamed_content += chunk.event.delta.text.lower()
assert len(streamed_content) > 0
assert any(expected in streamed_content for expected in {"dog", "puppy", "pup"})


@pytest.mark.parametrize("type_", ["url", "data"])
def test_image_chat_completion_base64(llama_stack_client, vision_model_id, base64_image_data, base64_image_url, type_):
image_spec = {
"url": {
"type": "image",
"image": {
"url": {
"uri": base64_image_url,
},
},
},
"data": {
"type": "image",
"image": {
"data": base64_image_data,
},
},
}[type_]

message = {
"role": "user",
"content": [
image_spec,
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=False,
)
message_content = response.completion_message.content.lower().strip()
assert len(message_content) > 0
133 changes: 133 additions & 0 deletions tests/client-sdk/inference/test_vision_inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.

import base64
import pathlib

import pytest


@pytest.fixture(scope="session")
def inference_provider_type(llama_stack_client):
providers = llama_stack_client.providers.list()
inference_providers = [p for p in providers if p.api == "inference"]
assert len(inference_providers) > 0, "No inference providers found"
return inference_providers[0].provider_type


@pytest.fixture
def image_path():
return pathlib.Path(__file__).parent / "dog.png"


@pytest.fixture
def base64_image_data(image_path):
# Convert the image to base64
return base64.b64encode(image_path.read_bytes()).decode("utf-8")


@pytest.fixture
def base64_image_url(base64_image_data, image_path):
# suffix includes the ., so we remove it
return f"data:image/{image_path.suffix[1:]};base64,{base64_image_data}"


def test_image_chat_completion_non_streaming(llama_stack_client, vision_model_id):
message = {
"role": "user",
"content": [
{
"type": "image",
"image": {
"url": {
# TODO: Replace with Github based URI to resources/sample1.jpg
"uri": "https://www.healthypawspetinsurance.com/Images/V3/DogAndPuppyInsurance/Dog_CTA_Desktop_HeroImage.jpg"
},
},
},
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=False,
)
message_content = response.completion_message.content.lower().strip()
assert len(message_content) > 0
assert any(expected in message_content for expected in {"dog", "puppy", "pup"})


def test_image_chat_completion_streaming(llama_stack_client, vision_model_id):
message = {
"role": "user",
"content": [
{
"type": "image",
"image": {
"url": {
# TODO: Replace with Github based URI to resources/sample1.jpg
"uri": "https://www.healthypawspetinsurance.com/Images/V3/DogAndPuppyInsurance/Dog_CTA_Desktop_HeroImage.jpg"
},
},
},
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=True,
)
streamed_content = ""
for chunk in response:
streamed_content += chunk.event.delta.text.lower()
assert len(streamed_content) > 0
assert any(expected in streamed_content for expected in {"dog", "puppy", "pup"})


@pytest.mark.parametrize("type_", ["url", "data"])
def test_image_chat_completion_base64(llama_stack_client, vision_model_id, base64_image_data, base64_image_url, type_):
image_spec = {
"url": {
"type": "image",
"image": {
"url": {
"uri": base64_image_url,
},
},
},
"data": {
"type": "image",
"image": {
"data": base64_image_data,
},
},
}[type_]

message = {
"role": "user",
"content": [
image_spec,
{
"type": "text",
"text": "Describe what is in this image.",
},
],
}
response = llama_stack_client.inference.chat_completion(
model_id=vision_model_id,
messages=[message],
stream=False,
)
message_content = response.completion_message.content.lower().strip()
assert len(message_content) > 0

0 comments on commit c97e05f

Please sign in to comment.