jekalmin / extended_openai_conversation

Home Assistant custom component of conversation agent. It uses OpenAI to control your devices.
834 stars 108 forks source link

Restful Payload not being sent #152

Open dugdathug opened 4 months ago

dugdathug commented 4 months ago

I have a function set up as:

- spec:
    name: item_add
    description: Home Inventory Management System
    parameters:
      type: object
      properties:
        location:
          type: string
          description: The room where the item is stored
        specific_location:
          type: string
          description: The specific location within the room where the item is stored
        name:
          type: array
          items: 
            type: string
          description: "the name of the item and its three synonyms"
        quantity:
          type: integer
          description: the number of like items stored in the same inventory record
      required:
        - name
        - location
        - specific_location
  function:
    type: rest
    method: POST
    resource: "https://eoirfkzvr44cesg.m.pipedream.net"
    headers:
      "Content-Type": "application/json; charset=utf-8"
    value_template: '{{value_json}}'

However, a payload is never sent to the server. OpenAI indicates it's sending the correct payload, but it's not being delivered. Do I need a payload section? If so, how do I set the values to my fields as this data is coming from openai.

For reference, here is my prompt:

You are an inventory manager for a household.
You may be asked to add things into inventory or move things in inventory from one location to another, remove items from inventory, or simply return the current location of a given inventory item. 
When you are adding a new item into inventory you should come up with three additional synonyms for the item and confirm these with the user before running any item_add function. 
Only use the functions you have been provided with, don't add negative quantity by instantiating the 'item_add' function.  
If you don't have access to an appropriate function, just tell that user that the request is beyond your capabilities.  
Make no assumption as to the specific location, instead ask. 
If the user is placing multiple items of the same name in a single location , make one function call and include the quantity. 
If the items are going to different locations, call the function for each item.
jekalmin commented 4 months ago

Thanks for reporting an issue.

payload_template is now available. It should be something like below.

- spec:
    name: item_add
    description: Home Inventory Management System
    parameters:
      type: object
      properties:
        location:
          type: string
          description: The room where the item is stored
        specific_location:
          type: string
          description: The specific location within the room where the item is stored
        name:
          type: array
          items: 
            type: string
          description: "the name of the item and its three synonyms"
        quantity:
          type: integer
          description: the number of like items stored in the same inventory record
      required:
        - name
        - location
        - specific_location
  function:
    type: rest
    method: POST
    resource: "https://eoirfkzvr44cesg.m.pipedream.net"
    headers:
      "Content-Type": "application/json; charset=utf-8"
    payload_template: "{{dict(location=location, specific_location=specific_location, name=name, quantity=quantity| default(None)) | to_json}}"
dugdathug commented 4 months ago

Thanks for considering my issue. Unfortunately, after implementing your suggestion above, I get this error: Something went wrong: failed to validate functionrest(extra keys not allowed @ data['payload_template'])

Perhaps I need the beta version?

jekalmin commented 4 months ago

I released 1.0.3 version yesterday. Please try this version.

dugdathug commented 4 months ago

I still get the same error using the payload_template you provided. However, I've made several changes that do not get the error - however, it still doesn't work. In an attempt to troubleshoot and am sending values in a variety of ways. Eg:

 payload: >-
      {"location": "{{location}}", "name": {name}, "quantity": {{quantity}}, "specific_location": "specific_location"}

But the receiving system (my restful endpoint) get's

body:
{"location": "{{location}}", "name": {name}, "quantity": {{quantity}}, "specific_location": "specific_location"}

While openAI reports it's sending: image

It's not clear to me how to send the actual values that openAI determines to my endpoint.
I'm sorry, I'm quite new to all of this.

Guraw6 commented 4 months ago

I'm experiencing the same behavior @dugdathug described in their last message, but I'm also somewhat new to OpenAI things, so I'm equally not sure if I'm missing something important.

- spec:
    name: query_test_api
    description: Use this function when somebody asks you to query the test API, then tell me what the API returns.
    parameters:
      type: object
      properties:
        test_query:
          type: string
          description: Set this to "testing123"
      required:
      - test_query
  function:
    type: rest
    method: POST
    resource: "https://URL_TO_TEST_API"
    headers:
      "Content-Type": "application/json"
    payload_template: >-
      {"query": "{{test_query}}"}

All the test API does is validate JSON and then echo it back, but so far I've not gotten the templating to work, so it only returns an error about invalid JSON.

I'm not sure, but I think asking OpenAI for the JSON that was sent in the POST might cause it to hallucinate what it assumes the JSON would have been. For me, it seems to change it's answer every time I tried testing this, and if it does say it sent JSON (there's like a 50/50 chance it says it sent a bare testing123 string instead), it says JSON was sent in the form of {"PARAMETER_NAME": "PARAMETER_VALUE"} ({"test_query": "testing123"} for my example function).

Like @dugdathug saw, my test API (restful endpoint) gets a payload that looks like {"query": "{{test_query}}"}, so it appears the templating isn't applied.

jekalmin commented 4 months ago

@dugdathug If you use payload, it will not be parsed as a template. Did you restart HA after installing 1.0.3 version? It should be something different error message if correctly installed 1.0.3.

@Guraw6 It's strange. Could you add following code at this line and see how it's logged?

print("rest_config", rest_config)
Guraw6 commented 4 months ago

@jekalmin Thanks for the help!

I think I got it figured out, and it was totally my fault (was missing one of the } closing braces for the template). I did have some troubles with my test server running on localhost still (almost definitely unrelated to this project), but everything worked when I pointed the function to the real world server that actually does things.

Also, after that worked, I realized my Home Assistant assistant can now search for answers when it doesn't know something 🎉

Here's a working example that queries Kagi's FastGPT service:

- spec:
    name: query_fastgpt
    description: Use this function when somebody asks you to look something up, or if you're asked a question you don't have an answer to, or if you're told to ask fastgpt something.
    parameters:
      type: object
      properties:
        query:
          type: string
          description: The natural language query to send to FastGPT in order to get the answer(s) you've been asked to look up.
      required:
      - query
  function:
    type: rest
    method: POST
    resource: "https://kagi.com/api/v0/fastgpt"
    headers:
      "Content-Type": "application/json"
      "Authorization": "Bot SECRET_API_KEY_GOES_HERE"
    payload_template: >-
      {"query": "{{query}}"}

Maybe that's useful for other folks? I've been really happy with the results so far! So nice to get references with answers to questions!

edit: Just realized I should explain that example needs an API key you can get with a Kagi account. Folks will need to replace SECRET_API_KEY_GOES_HERE with your super secret Kagi API key in the example above.

dugdathug commented 4 months ago

I too figured this out and I am, indeed, a moron. I'm unable to recognize the difference between 'payload' and 'payload_template' - not from a logical perspective - but my old eyes didn't recognize that the two were different. After age 55 the syntax errors begin to exponentially increase in scale and scope.

By the way, this work by @jekalmin is very special and opens so many doors. Thanks again!