Search code examples
pythonpython-requestsopenai-api

Call OpenAI API with Python requests is missing a model parameter


I'm trying to call OpenAI API from Python. I know they have their own openai package, but I want to use a generic solution. I chose the requests package for its flexibility. Here is my call

>>> headers = {"Authorization": "Bearer xxx"}
>>> url = 'https://api.openai.com/v1/completions'
>>> data = {'model': 'text-davinci-002', 'prompt': 'Once upon a time'}
>>> requests.get(url, headers=headers, data=data).content
...  "error": {\n        "message": "you must provide a model parameter"

The header contains the API token. It's correct, I tried it. I also tried to pass the same dictionary as json, as data but as a json string. Always the same error message. Any idea how to make the call?

Update:

>>> requests.get(url, headers=headers, json=data).content
>>> requests.get(url, headers=headers, json=json.dumps(data)).content
>>> requests.get(url, headers=headers, data=json.dumps(data)).content
>>> requests.get(url, headers=headers, data=json.dumps(data).encode()).content

These all return the same error. I tried to add 'Content-Type': 'application/json' to the headers too.

update2: It works for the completion endpoint with POST, but not for the edit endpoint.

>>> completion_url =  "https://api.openai.com/v1/completions"
>>> completion_data = {'model': 'text-davinci-002', 'prompt': 'Once upon a time'}
>>> requests.post(completion_url, headers=headers, json=completion_data).json()
... # it works
>>> edit_url =  "https://api.openai.com/v1/edits"
>>> completion_data = {'model': 'text-davinci-002', 'input': 'Once upon a time', 'instruction': 'Continue'}
>>> requests.get(edit_url, headers=headers, json=edit_data).json()['error']['message']
'you must provide a model parameter'
>>> requests.post(edit_url, headers=headers, json=edit_data).json()['error']['message']
'Invalid URL (POST /v1/edits)'

Solution

  • The API expects a JSON request body,not a form-encoded request. And, you need to use the requests.post() method to send the right HTTP method.

    Use the json argument, not the data argument, and the right method:

    requests.post(url, headers=headers, json=data)
    

    See the Create completion section of the OpenAI documentation, where the curl source code sample posts JSON:

    curl https://api.openai.com/v1/completions \
      -H 'Content-Type: application/json' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -d '{
      "model": "text-davinci-002",
      "prompt": "Say this is a test",
      "max_tokens": 6,
      "temperature": 0
    }'
    

    as well as the More complicated POST requests section of the documentation:

    Typically, you want to send some form-encoded data — much like an HTML form. To do this, simply pass a dictionary to the data argument. Your dictionary of data will automatically be form-encoded when the request is made[.]

    [...]

    There are times that you may want to send data that is not form-encoded.

    [...].

    If you need [the application/json header] set and you don’t want to encode the dict yourself, you can also pass it directly using the json parameter (added in version 2.4.2) and it will be encoded automatically[.]

    (Bold emphasis mine, slightly edited for clarity).

    Demo:

    >>> import requests
    >>> key = "<APIKEY>"
    >>> headers = {"Authorization": f"Bearer {key}"}
    >>> data = {'model': 'text-davinci-002', 'prompt': 'Once upon a time'}
    >>> requests.post(url, headers=headers, json=data).json()
    {'id': 'cmpl-6HIPWd1eDo6veh3FkTRsv9aJyezBv', 'object': 'text_completion', 'created': 1669580366, 'model': 'text-davinci-002', 'choices': [{'text': ' there was a castle up in space. In this castle there was a queen who', 'index': 0, 'logprobs': None, 'finish_reason': 'length'}], 'usage': {'prompt_tokens': 4, 'completion_tokens': 16, 'total_tokens': 20}}
    

    The openai Python library uses the requests library under the hood but takes care of details like how to send HTTP requests correctly for you.