Repository: deepset-ai/haystack

Issue:
GPT-4-32k support broken
**Describe the bug**
Token limit for `gpt-4-32k` gets set to 2049.

**Error message**
```
Traceback (most recent call last):
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/pipelines/base.py", line 552, in run
    node_output, stream_id = self._run_node(node_id, node_input)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/pipelines/base.py", line 467, in _run_node
    return self.graph.nodes[node_id]["component"]._dispatch_run(**node_input)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/base.py", line 201, in _dispatch_run
    return self._dispatch_run_general(self.run, **kwargs)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/base.py", line 245, in _dispatch_run_general
    output, stream = run_method(**run_inputs, **run_params)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/prompt/prompt_node.py", line 361, in run
    results = self(prompt_collector=prompt_collector, **invocation_context)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/prompt/prompt_node.py", line 145, in __call__
    return self.prompt(prompt_template, *args, **kwargs)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/prompt/prompt_node.py", line 171, in prompt
    prompt = self.prompt_model._ensure_token_limit(prompt)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/prompt/prompt_model.py", line 134, in _ensure_token_limit
    return self.model_invocation_layer._ensure_token_limit(prompt=prompt)
  File "/home/dnetguru/.conda/envs/thunk/lib/python3.10/site-packages/haystack/nodes/prompt/invocation_layer/chatgpt.py", line 120, in _ensure_token_limit
    raise ValueError(
ValueError: The prompt or the messages are too long (12807 tokens). The length of the prompt or messages and the answer (100 tokens) should be within the max token limit (2049 tokens). Reduce the length of the prompt or messages.
```

**Expected behavior**
`gpt-4-32k` should support up to 32768 tokens.

**To Reproduce**
Pass more than 2049 tokens to a PromptNode using `gpt-4-32k`


Discussion:

Resolving patch:
diff --git a/haystack/utils/openai_utils.py b/haystack/utils/openai_utils.py
--- a/haystack/utils/openai_utils.py
+++ b/haystack/utils/openai_utils.py
@@ -34,7 +34,7 @@
 
 if USE_TIKTOKEN:
     import tiktoken  # pylint: disable=import-error
-    from tiktoken.model import MODEL_TO_ENCODING
+    from tiktoken.model import MODEL_TO_ENCODING, MODEL_PREFIX_TO_ENCODING
 else:
     logger.warning(
         "OpenAI tiktoken module is not available for Python < 3.8,Linux ARM64 and AARCH64. Falling back to GPT2TokenizerFast."
@@ -97,11 +97,18 @@ def _openai_text_completion_tokenization_details(model_name: str):
     """
     tokenizer_name = "gpt2"
     max_tokens_limit = 2049  # Based on this ref: https://platform.openai.com/docs/models/gpt-3
-    model_tokenizer = MODEL_TO_ENCODING.get(model_name) if USE_TIKTOKEN else None
 
-    # covering the lack of support in Tiktoken. https://github.com/openai/tiktoken/pull/72
-    if model_name == "gpt-35-turbo" and USE_TIKTOKEN:
-        model_tokenizer = "cl100k_base"
+    if USE_TIKTOKEN:
+        if model_name == "gpt-35-turbo":
+            # covering the lack of support in Tiktoken. https://github.com/openai/tiktoken/pull/72
+            model_tokenizer = "cl100k_base"
+        elif model_name in MODEL_TO_ENCODING:
+            model_tokenizer = MODEL_TO_ENCODING[model_name]
+        else:
+            for model_prefix, tokenizer in MODEL_PREFIX_TO_ENCODING.items():
+                if model_name.startswith(model_prefix):
+                    model_tokenizer = tokenizer
+                    break
 
     if model_tokenizer:
         # Based on OpenAI models page, 'davinci' considers have 2049 tokens,


Test patch:
diff --git a/test/utils/test_openai_utils.py b/test/utils/test_openai_utils.py
--- a/test/utils/test_openai_utils.py
+++ b/test/utils/test_openai_utils.py
@@ -1,10 +1,53 @@
+import pytest
 from unittest.mock import patch
 
 import pytest
 from tenacity import wait_none
 
 from haystack.errors import OpenAIError, OpenAIRateLimitError, OpenAIUnauthorizedError
-from haystack.utils.openai_utils import openai_request
+from haystack.utils.openai_utils import openai_request, _openai_text_completion_tokenization_details
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt_default():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="text-ada-001")
+    assert tokenizer_name == "r50k_base"
+    assert max_tokens_limit == 2049
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt_davinci():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="text-davinci-003")
+    assert tokenizer_name == "p50k_base"
+    assert max_tokens_limit == 4097
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt3_5_azure():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="gpt-35-turbo")
+    assert tokenizer_name == "cl100k_base"
+    assert max_tokens_limit == 4096
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt3_5():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="gpt-3.5-turbo")
+    assert tokenizer_name == "cl100k_base"
+    assert max_tokens_limit == 4096
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt_4():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="gpt-4")
+    assert tokenizer_name == "cl100k_base"
+    assert max_tokens_limit == 8192
+
+
+@pytest.mark.unit
+def test_openai_text_completion_tokenization_details_gpt_4_32k():
+    tokenizer_name, max_tokens_limit = _openai_text_completion_tokenization_details(model_name="gpt-4-32k")
+    assert tokenizer_name == "cl100k_base"
+    assert max_tokens_limit == 32768
 
 
 @pytest.mark.unit