jekalmin / extended_openai_conversation

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

Integrating ytube_music_player #38

Open Zelaf opened 7 months ago

Zelaf commented 7 months ago

I'm trying to add some specs for full ytube_music_player integration.

Currently I'm trying to have it play from a list of playlist. I've added this in my prompt:

YouTube Music playlists:
```csv
playlist_id,playlist_name
*playlistid*,My Mix 1
*playlistid*,My Mix 2
*playlistid*,My Mix 3
*playlistid*,My Mix 4
*playlistid*,My Mix 5
*playlistid*,My Mix 6
*playlistid*,My Mix 7
*playlistid*,Chill Mix 1
*playlistid*,Chill Mix 2
*playlistid*,Chill Mix 3
*playlistid*,Energy Mix 1
*playlistid*,Energy Mix 2
*playlistid*,Energy Mix 3

And then this is what I'm trying for the spec:

- spec:
    name: play_music_playlist
    description: Use this function to play music from a playlist.
    parameters:
      type: object
      properties:
        playlist_id:
          type: string
          description: The ID of the playlist
      required:
      - playlist_id
  function:
    type: composite
    sequence:
    - type: script
      sequence:
      - service: media_player.play_media
        data:
          entity_id: media_player.youtube_music
          media_content_id: {{playlist_id}}
          media_content_type: playlist
          announce: true

However I'm getting

Sorry, I had a problem talking to OpenAI: [] is too short - 'functions'

I'm planning to add a function to each ytube_music_player function to have full control of it. Including picking a media player. Is there a way in the spec config to choose an already exposed media player?

Zelaf commented 7 months ago

It seemed to have been a indentation error. I formatted it in vscode and then the error gone away. I however seemed to have been trying to do a search instead of choosing one of the playlists IDs. It seemed to be working after I removed the "search_music" spec. I read from the logs that it tried to call that one instead. It started the playlist at least. Is there a way to specify so that it doesn't mix them up?

New spec:

- spec:
    name: play_music_playlist
    description: Use this function to play music from a playlist.
    parameters:
      type: object
      properties:
        playlist_id:
          type: string
          description: The ID of the playlist
      required:
        - playlist_id
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: media_player.play_media
            data:
              entity_id: media_player.youtube_music
              media_content_id: "{{ playlist_id }}"
              media_content_type: playlist
              announce: true
jekalmin commented 7 months ago

Sorry, I had a problem talking to OpenAI: [] is too short - 'functions'

I will change an error message and not even call API in next release if failed to load yaml functions.

Is there a way to specify so that it doesn't mix them up?

Please correct me if I'm wrong. What you are trying to do is that you want gpt to look for playlists from prompt first, and search for playlists if it's not present in prompt.

As far as I know, you can try to tell gpt to do so by modifying prompt or description or name of functions. Achieving this with general prompt is ideal, but specifically tell gpt about your case is totally fine like below (I haven't tested). Do not search music for playlists if provided

Zelaf commented 7 months ago

As far as I know, you can try to tell gpt to do so by modifying prompt or description or name of functions. Achieving this with general prompt is ideal, but specifically tell gpt about your case is totally fine like below (I haven't tested). Do not search music for playlists if provided

That's smart, I'll test that!

I'm also thinking if it's possible to make "if"-type statements for a spec. If ytube_music_player already has a chosen media player or is playing media already to have it either skip choosing a media player or switch media player. Perhaps that can be put in the specs description too.

jekalmin commented 7 months ago

Oh, I haven't thought about it. Could you give me an example of spec that you want to achieve?

Can't you achieve it by putting either choose or skip media player in prompt?

Zelaf commented 7 months ago

I'm still experimenting around at the moment with trying out the prompt. My ultimate goal is for the AI to be fully able to control ytube_music_player so gonna have to write a spec for every function I think.

Progress is a bit slow right now due to my setup and school. So far I got this:

- spec:
    name: music_playlist
    description: Use this function to play music from a playlist. If asked to play a playlist do not use the search_music function
    parameters:
      type: object
      properties:
        playlist_id:
          type: string
          description: The ID of the playlist
      required:
        - playlist_id
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: media_player.play_media
            data:
              entity_id: media_player.youtube_music
              media_content_id: "{{ playlist_id }}"
              media_content_type: playlist
              announce: true

- spec:
    name: music_start_radio
    description: Start a radio of the current song that plays similar music.
    parameters:
      type: object
      properties:
        dummy:
          type: string
          description: Nothing
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: ytube_music_player.start_radio
            data:
              entity_id: media_player.youtube_music
              interrupt: false

- spec:
    name: search_music
    description: Use this function to search music. Do not search if a playlist name is provided.
    parameters:
      type: object
      properties:
        query:
          type: string
          description: The query
      required:
      - query
  function:
    type: composite
    sequence:
    - type: script
      sequence:
      - service: ytube_music_player.search
        data:
          entity_id: media_player.youtube_music
          query: "{{ query }}"
    - type: template
      value_template: >-
        media_content_type,media_content_id,title
        {% for media in state_attr('sensor.ytube_music_player_extra', 'search') -%}
          {{media.type}},{{media.id}},{{media.title}}
        {% endfor%}

- spec:
    name: music_choose_player
    description: This function will choose the player to play back media to. Can also be used to switch current playback device.
    parameters:
      type: object
      properties:
        playback_device:
          type: string
          description: The speaker to play music on. Use entity ID of a speaker.
      required:
        - playback_device:
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: media_player.select_source
            data:
              source: "{{playback_device}}"
              entity_id: media_player.youtube_music

I'm wondering if there's other properties for the different settings? Does the parameters have different types other than object or a different property type other than string for example?

Edit: Also here's the current error I'm trying to fix, not sure if my way to do it is possible; Sorry, I had a problem talking to OpenAI: Invalid schema for function 'music_choose_player': {'playback_device': None} is not of type 'string'

Zelaf commented 7 months ago

Perhaps like the search_music spec I could do something in the template section? Since the ytube_music_player device shows which device is currently playing, it could perhaps base of off that?

So if the device is selected on the ytube_media_player property remote_player_id: don't initiate choose_player, else initiate choose.player.

jekalmin commented 7 months ago

Edit: Also here's the current error I'm trying to fix, not sure if my way to do it is possible; Sorry, I had a problem talking to OpenAI: Invalid schema for function 'music_choose_player': {'playback_device': None} is not of type 'string'

In required field, I think it should be changed from - playback_device: to - playback_device like below.

- spec:
    name: music_choose_player
    description: This function will choose the player to play back media to. Can also be used to switch current playback device.
    parameters:
      type: object
      properties:
        playback_device:
          type: string
          description: The speaker to play music on. Use entity ID of a speaker.
      required:
        - playback_device
  function:
    type: composite
    sequence:
      - type: script
        sequence:
          - service: media_player.select_source
            data:
              source: "{{playback_device}}"
              entity_id: media_player.youtube_music

Perhaps like the search_music spec I could do something in the template section? Since the ytube_music_player device shows which device is currently playing, it could perhaps base of off that?

It seems that you want a feature like if-then in script function.

The "script" type function is designed to be same as script integration in Home Assistant, but it currently has a bug when using if-then statement. I'm working on it, and it will probably be fixed in the next release.

However, you can achieve if-then clause by creating a separate script.

Currently not working (will be fixed in the next release)

Functions

- spec:
    ...
  function:
    type: script
    sequence:
      - if:
          - condition: state
            entity_id: ...
            state: "..."
        then:
          - service: media_player.select_source
            data: ...

Workaround

Functions

- spec:
    ...
  function:
    type: script
    sequence:
      - service: script.youtube_music_select_source

script.youtube_music_select_source

alias: youtube_music_select_source
sequence:
  - if:
      - condition: state
        entity_id: ...
        state: "..."
    then:
      - service: media_player.select_source
        data: ...
mode: single
jekalmin commented 6 months ago

The script function now supports if-then statement in 0.0.9.