| import asyncio |
| from unittest.mock import AsyncMock, MagicMock, patch |
|
|
| import pytest |
|
|
| from lm_eval.models.openai_completions import LocalCompletionsAPI |
|
|
|
|
| @pytest.fixture |
| def api(): |
| return LocalCompletionsAPI( |
| base_url="http://test-url.com", tokenizer_backend=None, model="gpt-3.5-turbo" |
| ) |
|
|
|
|
| @pytest.fixture |
| def api_tokenized(): |
| return LocalCompletionsAPI( |
| base_url="http://test-url.com", |
| model="EleutherAI/pythia-1b", |
| tokenizer_backend="huggingface", |
| ) |
|
|
|
|
| @pytest.fixture |
| def api_batch_ssl_tokenized(): |
| return LocalCompletionsAPI( |
| base_url="https://test-url.com", |
| model="EleutherAI/pythia-1b", |
| verify_certificate=False, |
| num_concurrent=2, |
| tokenizer_backend="huggingface", |
| ) |
|
|
|
|
| def test_create_payload_generate(api): |
| messages = ["Generate a story"] |
| gen_kwargs = { |
| "max_tokens": 100, |
| "temperature": 0.7, |
| "until": ["The End"], |
| "do_sample": True, |
| "seed": 1234, |
| } |
| payload = api._create_payload(messages, generate=True, gen_kwargs=gen_kwargs) |
|
|
| assert payload == { |
| "prompt": ["Generate a story"], |
| "model": "gpt-3.5-turbo", |
| "max_tokens": 100, |
| "temperature": 0.7, |
| "stop": ["The End"], |
| "seed": 1234, |
| } |
|
|
|
|
| def test_create_payload_loglikelihood(api): |
| messages = ["The capital of France is"] |
| payload = api._create_payload(messages, generate=False, gen_kwargs=None) |
|
|
| assert payload == { |
| "model": "gpt-3.5-turbo", |
| "prompt": ["The capital of France is"], |
| "max_tokens": 1, |
| "logprobs": 1, |
| "echo": True, |
| "temperature": 0, |
| "seed": 1234, |
| } |
|
|
|
|
| @pytest.mark.parametrize( |
| "input_messages, generate, gen_kwargs, expected_payload", |
| [ |
| ( |
| ["Hello, how are"], |
| True, |
| {"max_gen_toks": 100, "temperature": 0.7, "until": ["hi"]}, |
| { |
| "prompt": "Hello, how are", |
| "model": "gpt-3.5-turbo", |
| "max_tokens": 100, |
| "temperature": 0.7, |
| "stop": ["hi"], |
| "seed": 1234, |
| }, |
| ), |
| ( |
| ["Hello, how are", "you"], |
| True, |
| {}, |
| { |
| "prompt": "Hello, how are", |
| "model": "gpt-3.5-turbo", |
| "max_tokens": 256, |
| "temperature": 0, |
| "stop": [], |
| "seed": 1234, |
| }, |
| ), |
| ], |
| ) |
| def test_model_generate_call_usage( |
| api, input_messages, generate, gen_kwargs, expected_payload |
| ): |
| with patch("requests.post") as mock_post: |
| mock_response = MagicMock() |
| mock_response.json.return_value = {"result": "success"} |
| mock_post.return_value = mock_response |
|
|
| |
| result = api.model_call( |
| input_messages, generate=generate, gen_kwargs=gen_kwargs |
| ) |
|
|
| |
| mock_post.assert_called_once() |
| _, kwargs = mock_post.call_args |
| assert "json" in kwargs |
| assert kwargs["json"] == expected_payload |
| assert result == {"result": "success"} |
|
|
|
|
| @pytest.mark.parametrize( |
| "input_messages, generate, gen_kwargs, expected_payload", |
| [ |
| ( |
| [[1, 2, 3, 4, 5]], |
| False, |
| None, |
| { |
| "model": "EleutherAI/pythia-1b", |
| "prompt": [[1, 2, 3, 4, 5]], |
| "max_tokens": 1, |
| "logprobs": 1, |
| "echo": True, |
| "seed": 1234, |
| "temperature": 0, |
| }, |
| ), |
| ], |
| ) |
| def test_model_tokenized_call_usage( |
| api_tokenized, input_messages, generate, gen_kwargs, expected_payload |
| ): |
| with patch("requests.post") as mock_post: |
| mock_response = MagicMock() |
| mock_response.json.return_value = {"result": "success"} |
| mock_post.return_value = mock_response |
|
|
| |
| result = api_tokenized.model_call( |
| input_messages, generate=generate, gen_kwargs=gen_kwargs |
| ) |
|
|
| |
| mock_post.assert_called_once() |
| _, kwargs = mock_post.call_args |
| assert "json" in kwargs |
| assert kwargs["json"] == expected_payload |
| assert result == {"result": "success"} |
|
|
|
|
| class DummyAsyncContextManager: |
| def __init__(self, result): |
| self.result = result |
|
|
| async def __aenter__(self): |
| return self.result |
|
|
| async def __aexit__(self, exc_type, exc, tb): |
| pass |
|
|
|
|
| @pytest.mark.parametrize( |
| "expected_inputs, expected_ctxlens, expected_cache_keys", |
| [ |
| ( |
| [ |
| [1, 2, 3, 4, 5], |
| [6, 7, 8, 9, 10], |
| [11, 12, 13, 14, 15], |
| [16, 17, 18, 19, 20], |
| ], |
| [3, 3, 3, 3], |
| ["cache_key1", "cache_key2", "cache_key3", "cache_key4"], |
| ), |
| ], |
| ) |
| def test_get_batched_requests_with_no_ssl( |
| api_batch_ssl_tokenized, expected_inputs, expected_ctxlens, expected_cache_keys |
| ): |
| with ( |
| patch( |
| "lm_eval.models.api_models.TCPConnector", autospec=True |
| ) as mock_connector, |
| patch( |
| "lm_eval.models.api_models.ClientSession", autospec=True |
| ) as mock_client_session, |
| patch( |
| "lm_eval.models.openai_completions.LocalCompletionsAPI.parse_logprobs", |
| autospec=True, |
| ) as mock_parse, |
| ): |
| mock_session_instance = AsyncMock() |
| mock_post_response = AsyncMock() |
| mock_post_response.status = 200 |
| mock_post_response.ok = True |
| mock_post_response.json = AsyncMock(return_value={"mocked": "response"}) |
| mock_post_response.raise_for_status = lambda: None |
| mock_session_instance.post = lambda *args, **kwargs: DummyAsyncContextManager( |
| mock_post_response |
| ) |
| mock_client_session.return_value.__aenter__.return_value = mock_session_instance |
| mock_parse.return_value = [(1.23, True), (4.56, False)] |
|
|
| async def run(): |
| return await api_batch_ssl_tokenized.get_batched_requests( |
| expected_inputs, |
| expected_cache_keys, |
| generate=False, |
| ctxlens=expected_ctxlens, |
| ) |
|
|
| result_batches = asyncio.run(run()) |
|
|
| mock_connector.assert_called_with(limit=2, ssl=False) |
| assert result_batches |
|
|