Streamlit image/file upload to deta drive

This was also on streamlit discussion

I want to help others who are facing the same problem!

Upvotes: 1

Views: 5653

Answers (2)

ferdy
ferdy

Reputation: 5014

You can directly use the bytes data. Here is an example code uploading a single file for demo purposes.

"""Upload image file from disk to deta using streamlit.

References:

  streamlit:
    https://docs.streamlit.io/library/api-reference/widgets/st.file_uploader

  deta:
    https://docs.deta.sh/docs/drive/sdk#put
"""

import streamlit as st
from deta import Deta

# Initialize a project with project key from deta.
project = Deta("your_project_key")

# Define the drive to store the files.
drive_name = 'project_2_drive_1'
drive = project.Drive(drive_name)

# Initialize a streamlit file uploader widget.
uploaded_file = st.file_uploader("Choose a file")

# If user attempts to upload a file.
if uploaded_file is not None:
    bytes_data = uploaded_file.getvalue()

    # Show the image filename and image.
    st.write(f'filename: {uploaded_file.name}')
    st.image(bytes_data)

    # Upload the image to deta using put with filename and data.
    drive.put(uploaded_file.name, data=bytes_data)

Upvotes: 2

Hi this question I found on streamlit discussions, Posting answer on stack overflow might help others who are facing a similar problem. U can find the anser here.

If we use st.image() it works because you are taking the input from st.file_uploader() or st.camera_input(), and displaying it through st.image.

It works perfectly fine, because st.file_uploader() converts files into bytes stream(BytesIO) and st.image() expects bytesIO/ndarray, etc. Refer this docs.

But uploading image to a deta drive(by drive.put()) require two things mainly:

  1. name of the image
  2. path of the image

But unfortunately streamlit doesn't provide these both. So this approach of mine might help you, First we need one of the deprecated features, We need to enable automatic decoding of files which is deprecated in the release Version 0.64.0

st.set_option('deprecation.showfileUploaderEncoding', False)

Next step is to store the uploaded data in a variable by using st.file_uploader(), then read the file using .read() and write the file locally with the name you want. The file will be saved to the root folder. So finally we can access the file using its name and path. So after uploading it to deta base, You can use os.delete(filename) to delete the file.

Here's the final code for multi file/image upload:

# Imports
import streamlit as st
from deta import Deta

DETA_KEY = "XXXX...." # Secret key to connect to deta drive
deta = Deta(DETA_KEY) # Initialize deta object with a project key

drive = deta.Drive("drive_name") # Connecting to the Deta drive

# Here i'm taking the input from `st.file_uploader`, same principle can be  applied.
uploaded_files = st.file_uploader("Choose photos to upload", accept_multiple_files=True, type=['png', 'jpeg', 'jpg'])
    st.set_option('deprecation.showfileUploaderEncoding', False) # Enabling the automatic file decoder
    submit_button = st.button(label='Upload Photos') # Submit button
pic_names = [] # Later used for deleting the local files after being uploaded
    for uploaded_file in uploaded_files: # Iterating over each file uploaded
        file = uploaded_file.read() # Read the data
        image_result = open(uploaded_file.name, 'wb') # creates a writable image and later we can write the decoded result
        image_result.write(file) # Saves the file with the name uploaded_file.name to the root path('./')
        pic_names.append(uploaded_file.name) # Append the name of image to the list
        image_result.close() # Close the file pointer
if submit_button:
        for i in range(len(pic_names)): # Iterating over each file name
            name = pic_names[i] # Getting the name of current file
            path ='./'+pic_names[i] # Creating path string which is basically ["./image.jpg"]
            drive.put(name, path=path) # so, we have our file name and path, so uploading images to the drive
            os.remove(pic_names[i]) # Finally deleting it from root folder
        st.success('Thanks for uploading!') # Success message

This will work perfectly fine, but it has its limitations. As the processing of converitng and deleting the files takes some work upfront. It may have limitations but works fast! :rocket: and it's the only way upto my Knowledge.

You can checkout my actual implementation in my repo here.

Happy Coding! 😎

Thanks&Regards, Srinivas Menta

Upvotes: 1

Related Questions