jekalmin / extended_openai_conversation

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

service fan.set_speed not found #111

Open momoz opened 8 months ago

momoz commented 8 months ago

image

Ask you can see when I just state office fan 50% I get an error fan.set_speed not found, but turn office fan on 50% it works.

Thoughts?

momoz commented 8 months ago

I did add this to the prompt: If service fan.set_speed is to be used, use fan.set_percentage instead.

and it works now. Where does OpenAI learn the services? is that from this integration or the LLM knowledge?
Edit: Found this: The fan.set_speed service is deprecated and will fail in 2022.3 and later, use fan.set_percentage or fan.set_preset_mode instead

jekalmin commented 8 months ago

Thanks for reporting an issue!

Currently, how you have resolved is the way to get it work. There was a similar issue, and the workaround was about the same.

Where does OpenAI learn the services? is that from this integration or the LLM knowledge?

It's from LLM knowledge.

So hopefully the model trains recent data more.

jleinenbach commented 4 months ago

I chose a more complicated solution with PythonScriptsPro, as mentioned here: https://github.com/jekalmin/extended_openai_conversation/issues/193

- spec:
    name: is_valid_service
    description: >
      Checks if a given domain.service exists.
    parameters:
      type: object
      properties:
        domain:
          type: string
          description: "Domain of the service to be called."
        service:
          type: string
          description: "Name of the service to be called."
      required:
        - domain
        - service
  function:
    type: composite
    sequence:
      - type: template
        value_template: >
          {{ domain | tojson }}
        response_variable: domain_json
      - type: template
        value_template: >
          {{ service | tojson }}
        response_variable: service_json
      - type: script
        sequence:
          - service: python_script.exec
            data:
              source: |
                import json

                # Load the domain and service from input variables
                domain = json.loads('{{ domain_json }}')
                service = json.loads('{{ service_json }}')
                service_exists = False

                # Check if the specified service exists within the given domain
                if domain in hass.services.async_services():
                    service_exists = service in hass.services.async_services()[domain]

                # Set the result to True or False based on availability
                result = json.dumps(service_exists)
            response_variable: _function_result
        response_variable: service_existence
      - type: template
        value_template: "{{ service_existence.result }}"
- spec:
    name: get_service_domains
    description: >
      Lists all available service domains in Home Assistant.
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: python_script.exec
            data:
              source: |
                domains = list(hass.services.async_services().keys())
                # Outputting the dictionary directly to Home Assistants standardized output
                # for script results which will be captured in _function_result automatically
            response_variable: _function_result
        response_variable: variables
      - type: template
        value_template: >
          {{ variables.domains }}
- spec:
    name: get_services_by_domain
    description: >
      Lists all services available within a specified service domain in Home Assistant,
      including descriptions and parameters.
    parameters:
      type: object
      properties:
        domain:
          type: string
          description: The reliable service domain for which to list all available services.
      required:
        - domain
  function:
    type: composite
    sequence:
      - type: template
        value_template: "{{ domain | tojson }}"
        response_variable: domain_json
      - type: script
        sequence:
          - service: python_script.exec
            data:
              source: |
                import json

                # Load the domain from the input variable
                try:
                    domain = json.loads('{{ domain_json }}')
                except json.JSONDecodeError:
                    domain = 'default_domain'  # Safe fallback if JSON parsing fails

                services_info = {}
                if domain in hass.services.async_services():
                    for service_name in hass.services.async_services()[domain].keys():
                        # Format each service name with the domain prefix
                        full_service_name = f"{domain}.{service_name}"
                        services_info[full_service_name] = {}

                # Convert the result to JSON without introductory text
                result = json.dumps({domain: services_info})
            response_variable: _function_result
        response_variable: variables
      - type: template
        value_template: "{{ variables.result }}"