File size: 10,568 Bytes
447ebeb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
import sys, os
import traceback
from dotenv import load_dotenv

load_dotenv()
import os, io, asyncio

# this file is to test litellm/proxy

sys.path.insert(
    0, os.path.abspath("../..")
)  # Adds the parent directory to the system path
import pytest, time
import litellm
from litellm import embedding, completion, completion_cost, Timeout
from litellm import RateLimitError
import importlib, inspect

# test /chat/completion request to the proxy
from fastapi.testclient import TestClient
from fastapi import FastAPI
from litellm.proxy.proxy_server import (
    router,
    save_worker_config,
    initialize,
)  # Replace with the actual module where your FastAPI router is defined

filepath = os.path.dirname(os.path.abspath(__file__))
python_file_path = f"{filepath}/test_configs/custom_callbacks.py"


@pytest.fixture
def client():
    filepath = os.path.dirname(os.path.abspath(__file__))
    config_fp = f"{filepath}/test_configs/test_custom_logger.yaml"
    app = FastAPI()
    asyncio.run(initialize(config=config_fp))
    app.include_router(router)  # Include your router in the test app
    return TestClient(app)


# Your bearer token
token = os.getenv("PROXY_MASTER_KEY")

headers = {"Authorization": f"Bearer {token}"}


print("Testing proxy custom logger")


def test_embedding(client):
    try:
        litellm.set_verbose = False
        from litellm.proxy.types_utils.utils import get_instance_fn

        my_custom_logger = get_instance_fn(
            value="custom_callbacks.my_custom_logger", config_file_path=python_file_path
        )
        print("id of initialized custom logger", id(my_custom_logger))
        litellm.callbacks = [my_custom_logger]
        # Your test data
        print("initialized proxy")
        # import the initialized custom logger
        print(litellm.callbacks)

        # assert len(litellm.callbacks) == 1 # assert litellm is initialized with 1 callback
        print("my_custom_logger", my_custom_logger)
        assert my_custom_logger.async_success_embedding is False

        test_data = {"model": "azure-embedding-model", "input": ["hello"]}
        response = client.post("/embeddings", json=test_data, headers=headers)
        print("made request", response.status_code, response.text)
        print(
            "vars my custom logger /embeddings",
            vars(my_custom_logger),
            "id",
            id(my_custom_logger),
        )
        assert (
            my_custom_logger.async_success_embedding is True
        )  # checks if the status of async_success is True, only the async_log_success_event can set this to true
        assert (
            my_custom_logger.async_embedding_kwargs["model"] == "azure-embedding-model"
        )  # checks if kwargs passed to async_log_success_event are correct
        kwargs = my_custom_logger.async_embedding_kwargs
        litellm_params = kwargs.get("litellm_params")
        metadata = litellm_params.get("metadata", None)
        print("\n\n Metadata in custom logger kwargs", litellm_params.get("metadata"))
        assert metadata is not None
        assert "user_api_key" in metadata
        assert "headers" in metadata
        proxy_server_request = litellm_params.get("proxy_server_request")
        model_info = litellm_params.get("model_info")
        assert proxy_server_request == {
            "url": "http://testserver/embeddings",
            "method": "POST",
            "headers": {
                "host": "testserver",
                "accept": "*/*",
                "accept-encoding": "gzip, deflate, zstd",
                "connection": "keep-alive",
                "user-agent": "testclient",
                "content-length": "51",
                "content-type": "application/json",
            },
            "body": {"model": "azure-embedding-model", "input": ["hello"]},
        }
        assert model_info == {
            "input_cost_per_token": 0.002,
            "mode": "embedding",
            "id": "hello",
            "db_model": False,
        }
        result = response.json()
        print(f"Received response: {result}")
        print("Passed Embedding custom logger on proxy!")
    except Exception as e:
        pytest.fail(f"LiteLLM Proxy test failed. Exception {str(e)}")


def test_chat_completion(client):
    try:
        # Your test data
        litellm.set_verbose = False
        from litellm.proxy.types_utils.utils import get_instance_fn

        my_custom_logger = get_instance_fn(
            value="custom_callbacks.my_custom_logger", config_file_path=python_file_path
        )

        print("id of initialized custom logger", id(my_custom_logger))

        litellm.callbacks = [my_custom_logger]
        # import the initialized custom logger
        print(litellm.callbacks)

        # assert len(litellm.callbacks) == 1 # assert litellm is initialized with 1 callback

        print("LiteLLM Callbacks", litellm.callbacks)
        print("my_custom_logger", my_custom_logger)
        assert my_custom_logger.async_success == False

        test_data = {
            "model": "Azure OpenAI GPT-4 Canada",
            "messages": [
                {"role": "user", "content": "write a litellm poem"},
            ],
            "max_tokens": 10,
        }

        response = client.post("/chat/completions", json=test_data, headers=headers)
        print("made request", response.status_code, response.text)
        print("LiteLLM Callbacks", litellm.callbacks)
        time.sleep(1)  # sleep while waiting for callback to run

        print(
            "my_custom_logger in /chat/completions",
            my_custom_logger,
            "id",
            id(my_custom_logger),
        )
        print("vars my custom logger, ", vars(my_custom_logger))
        assert (
            my_custom_logger.async_success == True
        )  # checks if the status of async_success is True, only the async_log_success_event can set this to true
        assert (
            my_custom_logger.async_completion_kwargs["model"] == "chatgpt-v-3"
        )  # checks if kwargs passed to async_log_success_event are correct
        print(
            "\n\n Custom Logger Async Completion args",
            my_custom_logger.async_completion_kwargs,
        )
        litellm_params = my_custom_logger.async_completion_kwargs.get("litellm_params")
        metadata = litellm_params.get("metadata", None)
        print("\n\n Metadata in custom logger kwargs", litellm_params.get("metadata"))
        assert metadata is not None
        assert "user_api_key" in metadata
        assert "user_api_key_metadata" in metadata
        assert "headers" in metadata
        config_model_info = litellm_params.get("model_info")
        proxy_server_request_object = litellm_params.get("proxy_server_request")

        assert config_model_info == {
            "id": "gm",
            "input_cost_per_token": 0.0002,
            "mode": "chat",
            "db_model": False,
        }

        assert "authorization" not in proxy_server_request_object["headers"]
        assert proxy_server_request_object == {
            "url": "http://testserver/chat/completions",
            "method": "POST",
            "headers": {
                "host": "testserver",
                "accept": "*/*",
                "accept-encoding": "gzip, deflate, zstd",
                "connection": "keep-alive",
                "user-agent": "testclient",
                "content-length": "115",
                "content-type": "application/json",
            },
            "body": {
                "model": "Azure OpenAI GPT-4 Canada",
                "messages": [{"role": "user", "content": "write a litellm poem"}],
                "max_tokens": 10,
            },
        }
        result = response.json()
        print(f"Received response: {result}")
        print("\nPassed /chat/completions with Custom Logger!")
    except Exception as e:
        pytest.fail(f"LiteLLM Proxy test failed. Exception {str(e)}")


def test_chat_completion_stream(client):
    try:
        # Your test data
        litellm.set_verbose = False
        from litellm.proxy.types_utils.utils import get_instance_fn

        my_custom_logger = get_instance_fn(
            value="custom_callbacks.my_custom_logger", config_file_path=python_file_path
        )

        print("id of initialized custom logger", id(my_custom_logger))

        litellm.callbacks = [my_custom_logger]
        import json

        print("initialized proxy")
        # import the initialized custom logger
        print(litellm.callbacks)

        print("LiteLLM Callbacks", litellm.callbacks)
        print("my_custom_logger", my_custom_logger)

        assert (
            my_custom_logger.streaming_response_obj == None
        )  # no streaming response obj is set pre call

        test_data = {
            "model": "Azure OpenAI GPT-4 Canada",
            "messages": [
                {"role": "user", "content": "write 1 line poem about LiteLLM"},
            ],
            "max_tokens": 40,
            "stream": True,  # streaming  call
        }

        response = client.post("/chat/completions", json=test_data, headers=headers)
        print("made request", response.status_code, response.text)
        complete_response = ""
        for line in response.iter_lines():
            if line:
                # Process the streaming data line here
                print("\n\n Line", line)
                print(line)
                line = str(line)

                json_data = line.replace("data: ", "")

                if "[DONE]" in json_data:
                    break

                # Parse the JSON string
                data = json.loads(json_data)

                print("\n\n decode_data", data)

                # Access the content of choices[0]['message']['content']
                content = data["choices"][0]["delta"].get("content", None) or ""

                # Process the content as needed
                print("Content:", content)

                complete_response += content

        print("\n\nHERE is the complete streaming response string", complete_response)
        print("\n\nHERE IS the streaming Response from callback\n\n")
        print(my_custom_logger.streaming_response_obj)
        import time

        time.sleep(0.5)

        streamed_response = my_custom_logger.streaming_response_obj
        assert (
            complete_response == streamed_response["choices"][0]["message"]["content"]
        )

    except Exception as e:
        pytest.fail(f"LiteLLM Proxy test failed. Exception {str(e)}")