Litellm/fixes
diff --git a/llama_index/llms/litellm.py b/llama_index/llms/litellm.py
index e0325fd27980d..77c2f317b1435 100644
--- a/llama_index/llms/litellm.py
+++ b/llama_index/llms/litellm.py
@@ -29,7 +29,6 @@
     acompletion_with_retry,
     completion_with_retry,
     from_openai_message_dict,
-    is_chat_model,
     is_function_calling_model,
     openai_modelname_to_contextsize,
     to_openai_message_dicts,
@@ -61,6 +60,7 @@ def __init__(
         max_retries: int = 10,
         api_key: Optional[str] = None,
         api_type: Optional[str] = None,
+        api_base: Optional[str] = None,
         callback_manager: Optional[CallbackManager] = None,
         **kwargs: Any,
     ) -> None:
@@ -78,6 +78,8 @@ def __init__(
             additional_kwargs["api_key"] = api_key
         if api_type is not None:
             additional_kwargs["api_type"] = api_type
+        if api_base is not None:
+            additional_kwargs["api_base"] = api_base
 
         super().__init__(
             model=model,
@@ -107,7 +109,7 @@ def metadata(self) -> LLMMetadata:
         return LLMMetadata(
             context_window=openai_modelname_to_contextsize(self._get_model_name()),
             num_output=self.max_tokens or -1,
-            is_chat_model=self._is_chat_model,
+            is_chat_model=True,
             is_function_calling_model=is_function_calling_model(self._get_model_name()),
             model_name=self.model,
         )
@@ -132,10 +134,12 @@ def stream_chat(
 
     @llm_completion_callback()
     def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
+        # litellm assumes all llms are chat llms
         if self._is_chat_model:
             complete_fn = chat_to_completion_decorator(self._chat)
         else:
             complete_fn = self._complete
+
         return complete_fn(prompt, **kwargs)
 
     @llm_completion_callback()
@@ -148,7 +152,8 @@ def stream_complete(self, prompt: str, **kwargs: Any) -> CompletionResponseGen:
 
     @property
     def _is_chat_model(self) -> bool:
-        return is_chat_model(self._get_model_name())
+        # litellm assumes all llms are chat llms
+        return True
 
     @property
     def _model_kwargs(self) -> Dict[str, Any]:
@@ -174,6 +179,11 @@ def _chat(self, messages: Sequence[ChatMessage], **kwargs: Any) -> ChatResponse:
 
         message_dicts = to_openai_message_dicts(messages)
         all_kwargs = self._get_all_kwargs(**kwargs)
+        if "max_tokens" in all_kwargs and all_kwargs["max_tokens"] is None:
+            all_kwargs.pop(
+                "max_tokens"
+            )  # don't send max_tokens == None, this throws errors for Non OpenAI providers
+
         response = completion_with_retry(
             is_chat_model=self._is_chat_model,
             max_retries=self.max_retries,
@@ -198,6 +208,10 @@ def _stream_chat(
 
         message_dicts = to_openai_message_dicts(messages)
         all_kwargs = self._get_all_kwargs(**kwargs)
+        if "max_tokens" in all_kwargs and all_kwargs["max_tokens"] is None:
+            all_kwargs.pop(
+                "max_tokens"
+            )  # don't send max_tokens == None, this throws errors for Non OpenAI providers
 
         def gen() -> ChatResponseGen:
             content = ""
@@ -243,58 +257,10 @@ def gen() -> ChatResponseGen:
         return gen()
 
     def _complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
-        if self._is_chat_model:
-            raise ValueError("This model is a chat model.")
-
-        all_kwargs = self._get_all_kwargs(**kwargs)
-        if self.max_tokens is None:
-            # NOTE: non-chat completion endpoint requires max_tokens to be set
-            max_tokens = self._get_max_token_for_prompt(prompt)
-            all_kwargs["max_tokens"] = max_tokens
-
-        response = completion_with_retry(
-            is_chat_model=self._is_chat_model,
-            max_retries=self.max_retries,
-            prompt=prompt,
-            stream=False,
-            **all_kwargs,
-        )
-        text = response["choices"][0]["text"]
-        return CompletionResponse(
-            text=text,
-            raw=response,
-            additional_kwargs=self._get_response_token_counts(response),
-        )
+        raise NotImplementedError("litellm assumes all llms are chat llms.")
 
     def _stream_complete(self, prompt: str, **kwargs: Any) -> CompletionResponseGen:
-        if self._is_chat_model:
-            raise ValueError("This model is a chat model.")
-
-        all_kwargs = self._get_all_kwargs(**kwargs)
-        if self.max_tokens is None:
-            # NOTE: non-chat completion endpoint requires max_tokens to be set
-            max_tokens = self._get_max_token_for_prompt(prompt)
-            all_kwargs["max_tokens"] = max_tokens
-
-        def gen() -> CompletionResponseGen:
-            text = ""
-            for response in completion_with_retry(
-                is_chat_model=self._is_chat_model,
-                max_retries=self.max_retries,
-                prompt=prompt,
-                stream=True,
-                **all_kwargs,
-            ):
-                delta = response["choices"][0]["text"]
-                text += delta
-                yield CompletionResponse(
-                    delta=delta,
-                    text=text,
-                    raw=response,
-                    additional_kwargs=self._get_response_token_counts(response),
-                )
-
-        return gen()
+        raise NotImplementedError("litellm assumes all llms are chat llms.")
 
     def _get_max_token_for_prompt(self, prompt: str) -> int:
         try:
@@ -304,7 +270,12 @@ def _get_max_token_for_prompt(self, prompt: str) -> int:
                 "Please install tiktoken to use the max_tokens=None feature."
             )
         context_window = self.metadata.context_window
-        encoding = tiktoken.encoding_for_model(self._get_model_name())
+        try:
+            encoding = tiktoken.encoding_for_model(self._get_model_name())
+        except KeyError:
+            encoding = encoding = tiktoken.get_encoding(
+                "cl100k_base"
+            )  # default to using cl10k_base
         tokens = encoding.encode(prompt)
         max_token = context_window - len(tokens)
         if max_token <= 0:
@@ -452,57 +423,9 @@ async def gen() -> ChatResponseAsyncGen:
         return gen()
 
     async def _acomplete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
-        if self._is_chat_model:
-            raise ValueError("This model is a chat model.")
-
-        all_kwargs = self._get_all_kwargs(**kwargs)
-        if self.max_tokens is None:
-            # NOTE: non-chat completion endpoint requires max_tokens to be set
-            max_tokens = self._get_max_token_for_prompt(prompt)
-            all_kwargs["max_tokens"] = max_tokens
-
-        response = await acompletion_with_retry(
-            is_chat_model=self._is_chat_model,
-            max_retries=self.max_retries,
-            prompt=prompt,
-            stream=False,
-            **all_kwargs,
-        )
-        text = response["choices"][0]["text"]
-        return CompletionResponse(
-            text=text,
-            raw=response,
-            additional_kwargs=self._get_response_token_counts(response),
-        )
+        raise NotImplementedError("litellm assumes all llms are chat llms.")
 
     async def _astream_complete(
         self, prompt: str, **kwargs: Any
     ) -> CompletionResponseAsyncGen:
-        if self._is_chat_model:
-            raise ValueError("This model is a chat model.")
-
-        all_kwargs = self._get_all_kwargs(**kwargs)
-        if self.max_tokens is None:
-            # NOTE: non-chat completion endpoint requires max_tokens to be set
-            max_tokens = self._get_max_token_for_prompt(prompt)
-            all_kwargs["max_tokens"] = max_tokens
-
-        async def gen() -> CompletionResponseAsyncGen:
-            text = ""
-            async for response in await acompletion_with_retry(
-                is_chat_model=self._is_chat_model,
-                max_retries=self.max_retries,
-                prompt=prompt,
-                stream=True,
-                **all_kwargs,
-            ):
-                delta = response["choices"][0]["text"]
-                text += delta
-                yield CompletionResponse(
-                    delta=delta,
-                    text=text,
-                    raw=response,
-                    additional_kwargs=self._get_response_token_counts(response),
-                )
-
-        return gen()
+        raise NotImplementedError("litellm assumes all llms are chat llms.")
diff --git a/tests/llms/test_litellm.py b/tests/llms/test_litellm.py
index 5e044f0221049..3d6643f18d50b 100644
--- a/tests/llms/test_litellm.py
+++ b/tests/llms/test_litellm.py
@@ -148,3 +148,38 @@ def test_chat_model_basic(monkeypatch: MonkeyPatch) -> None:
 def test_metadata() -> None:
     llm = LiteLLM(model="gpt-3.5-turbo")
     assert isinstance(llm.metadata.context_window, int)
+
+
+@pytest.mark.skipif(litellm is None, reason="litellm not installed")
+def test_deep_infra() -> None:
+    # deep infra call
+    llm = LiteLLM(
+        model="deepinfra/meta-llama/Llama-2-70b-chat-hf", max_tokens=10, api_key=""
+    )
+    message = ChatMessage(role="user", content="why does LiteLLM love LlamaIndex")
+    chat_response = llm.chat([message])
+    print("\ndeepinfra Chat response\n")
+    print(chat_response)
+
+
+@pytest.mark.skipif(litellm is None, reason="litellm not installed")
+def test_openai() -> None:
+    llm = LiteLLM(model="gpt-3.5-turbo", api_key="")
+    message = ChatMessage(role="user", content="why does LiteLLM love LlamaIndex")
+    chat_response = llm.chat([message])
+    print("gpt-3.5-turbo Chat response\n")
+    print(chat_response)
+
+
+@pytest.mark.skipif(litellm is None, reason="litellm not installed")
+def test_tg_ai() -> None:
+    # deep infra call
+    llm = LiteLLM(
+        model="together_ai/togethercomputer/Llama-2-7B-32K-Instruct",
+        max_tokens=10,
+        api_key="",
+    )
+    message = ChatMessage(role="user", content="why does LiteLLM love LlamaIndex")
+    chat_response = llm.chat([message])
+    print("\ntogetherai Chat response\n")
+    print(chat_response)

# Description
Fixes LiteLLM Huggingface, Deep Infra integration 

Fixes # (issue)

## Type of Change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

- [ ] Added new unit/integration tests
- [ ] Added new notebook (that tests end-to-end)
- [ ] I stared at the code and made sure it makes sense

# Suggested Checklist:

- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I ran `make format; make lint` to appease the lint gods
