How to find arbitrary asset path?

What I’m trying to do:
Load an mp3 file into memory from the “Assets”, and play it.

What I’ve tried and what’s not working:
I added “test.mp3” into the assets and attempted to return a media object it into memory with the following code…

@anvil.server.callable
def get_audio_file():
    #file_path = 'files/test.mp3'
    file_path = 'test.mp3'
    audio_file_path = file_path
    with open(audio_file_path, 'rb') as f:
        return anvil.media.from_file(f, 'audio/mp3', 'test.mp3')

and then to call this function in the client code…

  def button_play_audio_click(self, **event_args):
    audio_file = anvil.server.call('get_audio_file')
    audio_player = f'<audio src="{audio_file.url}" autoplay controls></audio>'

However when I try and click the button I get this error:

FileNotFoundError: [Errno 2] No such file or directory: 'test.mp3'

I’m not really sure the way the asset paths work.

Clone link:
share a copy of your app

On the client you use _/theme/test.mp3 to get to the test.mp3 file stored at the root of your Assets. No need to involve the server, which apparently can’t access Asset files using the same path anyway.

audio_player = f'<audio src="_/theme/test.mp3" autoplay controls></audio>'
2 Likes

Gotcha… Sorry to keep asking questions, but is there any trick to actually playing the audio file with the audio_player?

What have you tried? If you update your clone with your latest attempt, and describe what happens with it, it’d be easier to offer advice.

How do we access the asset files from a server module? I tried setting my button_click function to:

  def button_2_click(self, **event_args):
    """This method is called when the button is clicked"""
    url = anvil.server.get_app_origin() + "/_/theme/vdespa-medium-whisper-api.mp3"
    anvil.server.call('transcribe', url)

And then on the server module I have:

def transcribe(file_path):
    openai.api_key = os.getenv("xxx")
    audio_file = open(file_path, "rb")
    transcript = openai.Audio.translate("whisper-1", audio_file)
    transcription_text = transcript["text"]
    mistakes = None  # placeholder

    return transcription_text, mistakes

However I get a file-not-found error.
Although when I navigate to the URL given as “file not found” in my browser, it is accessible and plays correctly.

Server code runs on a physically distant computer, not in the browser, so it has its own storage system to look at.

For server-side files, look here:

How about allowing the user to upload files to the app and have them be accessible by server modules?

And I am still confused why I would be getting a File Not Found error when I am providing the function with an absolute (publicly internet-accessible) file path. The server code must have normal internet access since I am interacting with APIs and the like?

As I understand it, anvil.server.get_app_origin() + "/_/theme/vdespa-medium-whisper-api.mp3" produces a URL (e.g, 'https://www.your_domain_name.com/_/theme/vdespa-medium-whisper-api.mp3').

In contrast, Python’s open() function is intended to work not with the Internet, but with a local file system. It understands Linux file paths, like ./temp/your_file_name_here.xyz.

 >py
Python 3.7.5 (tags/v3.7.5:5c02a39a0b, Oct 15 2019, 00:11:34) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('https://anvil.works/forum/t/how-to-find-arbitrary-asset-path/16802/6')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument: 'https://anvil.works/forum/t/how-to-find-arbitrary-asset-path/16802/6'
>>>

This is why open() fails: it doesn’t understand URLs.

Asset files are definitely stored as part of the App. But not necessarily in a location where a Server-side open() can see them. (They might be database entries, or Git repository entries, for example.) I haven’t tried it, so I don’t know.

If someone knows a Server-side path to the app’s Assets, that would help.

There are examples of this throughout this forum and in the educational materials, if you look.

You can download your asset files on the server and then use them as normal python files.

def download_asset_file(file_name):
    import requests
    asset_url=f'{anvil.server.get_app_origin()}/_/theme/{file_name}'
    asset_data=requests.get(asset_url).content
    with open(file_name,'wb') as f:
        f.write(asset_data)
file_name='my_audio.mp3'
download_asset_file(file_name)
with open(file_name,'rb') as f:
     #Do something with the file here
1 Like