QuivrHQ / quivr

Open-source RAG Framework for building GenAI Second Brains 🧠 Build productivity assistant (RAG) ⚡️🤖 Chat with your docs (PDF, CSV, ...) & apps using Langchain, GPT 3.5 / 4 turbo, Private, Anthropic, VertexAI, Ollama, LLMs, Groq that you can share with users ! Efficient retrieval augmented generation framework
https://quivr.com
Other
36.32k stars 3.54k forks source link

[Bug]: JSONDecodeError using api, endpoint: "{base_url}/chat/{chat_id}/question?brain_id={brain_id}" #3082

Open HELIOPOTELICKI opened 1 month ago

HELIOPOTELICKI commented 1 month ago

What happened?

I uploaded the containers locally, and using Python, I implemented the functions to interact with Quivr. I have used this class that I implemented a few months ago, and it worked well (before having the notifier, by the way).

I updated Quivr, and now I encounter this JSONDecode error.

The error occurs using my implementation and through the Swagger UI as well.

class QuivrAPI:
    def __init__(self, base_url: Optional[str] = None, api_key: Optional[str] = None) -> None:
        """
        Initialize the QuivrAPI class with base URL and API key.

        Args:
            base_url (Optional[str]): The base URL for the API. Defaults to environment variable QUIVR_API_URL.
            api_key (Optional[str]): The API key for authentication. Defaults to environment variable QUIVR_API_KEY.
        """
        self.base_url: str = base_url or os.getenv("QUIVR_API_URL")
        self.headers: Dict[str, str] = {
            "Authorization": f"Bearer {api_key or os.getenv('QUIVR_API_KEY')}",
            "accept": "application/json"
        }

    def ask_question(self, question: str, brain_id: str, prompt_id: str, chat_id: Optional[str] = None, model: Optional[str] = "gpt-4o", temperature: Optional[int] = 0, max_tokens: Optional[int] = 4000) -> Dict[str, Any]:
            """
            Ask a question to a specific brain.

            Args:
                question (str): The question to ask.
                brain_id (str): The ID of the brain.
                prompt_id (str): The ID of the prompt.
                chat_id (Optional[str]): The ID of the chat. Defaults to None.
                model (Optional[str]): The model to use. Defaults to "gpt-4o".
                temperature (Optional[int]): The temperature setting for the model. Defaults to 0.
                max_tokens (Optional[int]): The maximum number of tokens to generate. Defaults to 4000.

            Returns:
                Dict[str, Any]: The response from the API as a dictionary.
            """
            if chat_id is None:
                chat = self.create_chat()
                chat_id = chat["chat_id"]

            payload: Dict[str, Any] = {
                "question": question,
                "model": model,
                "temperature": temperature,
                "max_tokens": max_tokens,
                "brain_id": brain_id,
                "prompt_id": prompt_id
            }
            response = requests.post(
                f"{self.base_url}/chat/{chat_id}/question?brain_id={brain_id}",
                json=payload,
                headers=self.headers
            )
            return response.json()

Error:

---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
File c:\Users\helio\anaconda3\envs\moderator\Lib\site-packages\requests\models.py:974, in Response.json(self, **kwargs)
    [973](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:973) try:
--> [974](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:974)     return complexjson.loads(self.text, **kwargs)
    [975](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:975) except JSONDecodeError as e:
    [976](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:976)     # Catch JSON-related errors and raise as requests.JSONDecodeError
    [977](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:977)     # This aliases json.JSONDecodeError and simplejson.JSONDecodeError

File c:\Users\helio\anaconda3\envs\moderator\Lib\json\__init__.py:346, in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    [343](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/__init__.py:343) if (cls is None and object_hook is None and
    [344](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/__init__.py:344)         parse_int is None and parse_float is None and
    [345](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/__init__.py:345)         parse_constant is None and object_pairs_hook is None and not kw):
--> [346](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/__init__.py:346)     return _default_decoder.decode(s)
    [347](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/__init__.py:347) if cls is None:

File c:\Users\helio\anaconda3\envs\moderator\Lib\json\decoder.py:337, in JSONDecoder.decode(self, s, _w)
    [333](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:333) """Return the Python representation of ``s`` (a ``str`` instance
    [334](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:334) containing a JSON document).
    [335](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:335) 
    [336](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:336) """
--> [337](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:337) obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    [338](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:338) end = _w(s, end).end()

File c:\Users\helio\anaconda3\envs\moderator\Lib\json\decoder.py:355, in JSONDecoder.raw_decode(self, s, idx)
    [354](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:354) except StopIteration as err:
--> [355](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:355)     raise JSONDecodeError("Expecting value", s, err.value) from None
    [356](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/json/decoder.py:356) return obj, end

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

JSONDecodeError                           Traceback (most recent call last)
Cell In[10], [line 1](vscode-notebook-cell:?execution_count=10&line=1)
----> [1](vscode-notebook-cell:?execution_count=10&line=1) quivr.ask_question(question="Qual é o atual presidente do Brasil?", 
      [2](vscode-notebook-cell:?execution_count=10&line=2)                    brain_id="40ba47d7-51b2-4b2a-9247-89e29619efb0", 
      [3](vscode-notebook-cell:?execution_count=10&line=3)                    prompt_id="b813c6a2-8364-4f4f-8b0[4](vscode-notebook-cell:?execution_count=10&line=4)-6cf24d1985cc",
      4                    )

File f:\COGMO\COGMO-AGENTS\CogmoAgents-Moderador\app\services\quivr_utils.py:194, in QuivrAPI.ask_question(self, question, brain_id, prompt_id, chat_id, model, temperature, max_tokens)
    [181](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:181) payload: Dict[str, Any] = {
    [182](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:182)     "question": question,
    [183](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:183)     "model": model,
   (...)
    [187](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:187)     "prompt_id": prompt_id
    [188](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:188) }
    [189](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:189) response = requests.post(
    [190](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:190)     f"{self.base_url}/chat/{chat_id}/question?brain_id={brain_id}",
    [191](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:191)     json=payload,
    [192](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:192)     headers=self.headers
    [193](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:193) )
--> [194](file:///F:/COGMO/COGMO-AGENTS/CogmoAgents-Moderador/app/services/quivr_utils.py:194) return response.json()

File c:\Users\helio\anaconda3\envs\moderator\Lib\site-packages\requests\models.py:978, in Response.json(self, **kwargs)
    [974](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:974)     return complexjson.loads(self.text, **kwargs)
    [975](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:975) except JSONDecodeError as e:
    [976](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:976)     # Catch JSON-related errors and raise as requests.JSONDecodeError
    [977](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:977)     # This aliases json.JSONDecodeError and simplejson.JSONDecodeError
--> [978](file:///C:/Users/helio/anaconda3/envs/moderator/Lib/site-packages/requests/models.py:978)     raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

On swagger: image

OS: Windows 11 Pro Python: 3.11.9 Quivr: 0.0.300

Relevant log output

No response

Twitter / LinkedIn details

No response

linear[bot] commented 1 month ago

CORE-165 [Bug]: JSONDecodeError using api, endpoint: "{base_url}/chat/{chat_id}/question?brain_id={brain_id}"

dosubot[bot] commented 1 month ago

Hey there, @HELIOPOTELICKI! I'm here to help you with your bug report. I'm a bot that can assist with solving bugs, answering questions, and becoming a contributor. Let's get to the bottom of this together!

You are encountering a JSONDecodeError when using the QuivrAPI class to interact with the endpoint {base_url}/chat/{chat_id}/question?brain_id={brain_id} because the code attempts to parse a string that is not valid JSON. Specifically, the error occurs in the make_recursive_tool_calls method when it tries to parse the function.arguments field of a tool_call object.

Here is the relevant code snippet:

function_args = json.loads(tool_call.function.arguments)

If tool_call.function.arguments is not a valid JSON string, json.loads will raise a JSONDecodeError.

To fix this issue, ensure that tool_call.function.arguments is a valid JSON string before attempting to parse it. You can add error handling to catch and log the error, or validate the string before parsing.

Here is an example of how you can add error handling:

import json

def safe_json_loads(json_string):
    try:
        return json.loads(json_string)
    except json.JSONDecodeError as e:
        logger.error(f"JSONDecodeError: {e}")
        return None

# Usage in make_recursive_tool_calls
function_args = safe_json_loads(tool_call.function.arguments)
if function_args is None:
    # Handle the error appropriately, e.g., skip this tool call or return an error response
    continue

By adding this error handling, you can avoid the JSONDecodeError and handle invalid JSON strings more gracefully [1].

To continue talking to Dosu, mention @dosu.