Announcing Genie Builder, a no-code plugin to quickly build web GUIs & dashboards

Great work!

I think no-code editor not recognize upload forms like this:

<%     uploader(label="Upload Dataset", :autoupload, :multiple, accept=".csv", method="POST", url="http://localhost:9101", fieldname="csv_file")     %>

It should… All no-code gets converted into low-code API calls. What error are you getting?

When I put in builder (to app.jl.htm), I get the result bellow. On site it look fine.

Yes, that’s to be expected. The code between <% %> is run on the server and the no-code editor does not know how to handle it. You can put it inside a div to have it constrained to a container. Once we’ll have a proper no-code uploader component we’ll use that and it will look nice.

1 Like

Hey @essenciary, This is awesome, thanks for posting it!

I was wondering if you know if it’s possible to host a Genie server in a HuggingFace space?

HuggingFace for those who don’t know is a way to freely host in-browser demos of ML models – the popular example being stable diffusion: runwayml/stable-diffusion-v1-5 · Hugging Face. It’s nice because it lets you hosting arbitrary interactive code with a complex environment and backend, so people can try out your model in-browser without you needing to host the server yourself.

Now, the unfortunate thing is that their spaces API is largely Python: Spaces. I’ve tried to set up a Julia demo in the past on it: PySR - a Hugging Face Space by MilesCranmer (a live demo of PySR - the PyJulia frontend of SymbolicRegression.jl), but it was super hacky and only worked sometimes. I basically wrote a thin Gradio frontend which would execute system commands to install Julia command and then the packages I need. However, the current demo started segfaulting so I just gave up.

However, seeing how mature Genie.jl is makes me wonder whether it’s possible to run a Julia server directly within HuggingFace’s stack, rather than try to interface through PyJulia. Most people don’t know how to host a server themselves, but can put together a script and push it to a git repo - which is pretty much all you need to define a HuggingFace space.

They do have docs on hosting custom HTML here: Static HTML Spaces as well as custom Python: Custom Python Spaces. One could probably run a full Julia runtime behind the scenes, given they let you use large PyTorch transformers. Maybe worth a shot? HuggingFace is such a valuable resource in ML (and non-ML demos too) that it would be awesome if there was a way to host Julia code on it - maybe Genie makes this possible!

Cheers,
Miles

1 Like

@MilesCranmer Excellent idea, thanks for sharing! Don’t have an answer right now but I’ve added it to our todo list to investigate :slight_smile:

1 Like

Hi!

Try to understand how to link file upload and ReactiveModel and can’t found docs about @handlers macro (0 docs found). It is very difficult to search solution in examples… :slight_smile: For my case, I have upload route

route("/", method = POST) do
  files = Genie.Requests.filespayload()
  if length(files) == 0
      @info "No file uploaded"
  end
  return "Upload finished"
end

Than I want to make something with this files inside model:

module App
  using GenieFramework
  using CSV, DataFrames
  @genietools
  export AppModel
  @reactive mutable struct AppModel <: ReactiveModel
    df::R{DataFrame}
  end
 # do something with files, parse them, and put in model.df... 
  @handlers begin
    @out message = "Hello World!"
    @onchange isready begin
      @show "App is loaded"
    end
  end
  @page("/", "app.jl.html")
end

how to link them without make file on disk…

When I use part from example:

route("/", method = POST) do
    model = AppModel |> init |> handlers
    # Somecode...
end

I have:

┌ Error: 2022-11-28 21:15:03 UndefVarError: __model__ not defined

I’ll write a snippet and share.

1 Like

I revamped the event handler that @wildart added to include event info.
With this we can easily build a file upload:

using Stipple, StippleUI, Stipple.ReactiveTools
using CSV, DataFrames

const UPLOAD = "upload"

write(joinpath(pwd(), "test.csv"), "a,b\n1,2\n10,11")

# do something with files, parse them, and put in model.df... 
@handlers begin
    @out message = ""
    @private df = DataFrame()
    @out table = DataTable()
    @onchange isready begin
        @show "App is loaded"
    end
    @onchange df table = DataTable(df)
end

@event :uploaded begin
    for f in event["files"]
        f["__status"] == "uploaded" || continue
        filepath = joinpath(pwd(), UPLOAD, f["fname"])
        message *= f["fname"] * ":<br>first line: " * readline(filepath) * "<br><br><br>"
        if endswith(filepath, r"csv"i)
            df = CSV.read(filepath, DataFrame)
        end
        rm(filepath)
    end
end

@event :clear begin                                                                                                                                                 
    model.message[] = ""                                                                                                                                              
    println(event)                                                                                                                                                    
end

function ui()
    [
        uploader("Upload files", url = "/upload" , autoupload = true, :multiple,
            @on(:uploaded, :uploaded, "for (let f in event.files) { event.files[f].fname = event.files[f].name }")
        )

        card(class = "q-mt-lg q-pa-md text-white",
            style = "background: radial-gradient(circle, #35a2ff 0%, #014a88 100%); width: 30%",
            [
                cardsection(Stipple.Html.div(class = "text-h5 text-white", "Upload logs"))
                separator()
                cardsection(span(v__html = :message))
            ]
        )

        btn(class = "q-mt-lg", "Clear Log", color = "primary", @on(:click, :clear))

        table(class = "q-mt-lg", :table)
    ] |> join
end


@page("/", ui)


route("/upload", method = POST) do
    files = Genie.Requests.filespayload()
    upload_dir = joinpath(pwd(), UPLOAD)
    mkpath(upload_dir)

    for f in files
        filepath = joinpath(upload_dir, f[2].name)
        write(filepath, f[2].data)
        @info "Uploading: " * f[2].name
        # if no model context is necessary, the data can be loaded here
        if endswith(filepath, r"csv"i)
            df = CSV.read(filepath, DataFrame)
            @info df
        end
    end

    if length(files) == 0
        @info "No file uploaded"
    end

end

up()

It’s also up on StippleDemos.
Note that you have to use the Stipple#master until we release the next version…

EDIT: Latest change supports field usage without preceeding model. and succeeding []. Manual addressing of the model now needs to be preceeded by __model__, e.g.
__model__.message[!] = "Shush!"
for silent, i.e. non-notifying, updates of a field. This is analogous to the usage of @onchange

I just built a quick demo to run a Genie webapp in Huggingface Spaces demo using Docker spaces! Genie.jl on HuggingFace Demo - a Hugging Face Space by nooji

I’m currently working with the team to figure out how to leverage gpu docker images as well, so we can host demos that can leverage GPUs. I think they just need to enable this on the infra-side when building and running the images.

2 Likes

Awesome! I’m excited to see where this goes :slight_smile:

Hi everybody! Super exciting and important update! :mega:

We’ve released the private beta version of Genie Cloud, the no-code platform to quickly build and deploy Genie web apps. :tada:

For more details check out the announcement thread here: Announcing Genie Cloud (Private Beta), the no-code platform to quickly build and deploy Genie apps

:white_check_mark: Learn more and register for a free account here: https://www.geniecloud.io/

:video_camera: Watch a demo video: Genie Cloud Demo - YouTube

9 Likes

Hey everyone! :rocket: We’ve released Genie Builder v0.3, an improved version of our no-code UI builder. :star2: Key updates include:

:one: Side-by-side app preview for seamless development
:two: Quick app export via download button
:three: Enhanced tooltips to better understand component properties

GB v0.3

:point_right:You can download or upgrade Genie Builder via VSCode to run it locally:Genie Builder - Visual Studio Marketplace

:point_right: OR Sign up for a free Genie Cloud account for a managed version with one-click deploys: https://www.geniecloud.io/

12 Likes

Hi there @essenciary
congrats on this launch and we know you will be successful especially as we watched one of the best pitch videos we have seen. informative and provocative.
well done all.

2 Likes

I haven’t been able to install GenieBuilder. I get the following error:
I get the following error:

Pkg.add(url = “GitHub - GenieFramework/GenieBuilder.jl”)
Cloning git-repo https://github.com/GenieFramework/GenieBuilder.jl.git
Updating git-repo https://github.com/GenieFramework/GenieBuilder.jl.git
Resolving package versions…
ERROR: Unsatisfiable requirements detected for package Temporal [a110ec8f]:
Temporal [a110ec8f] log:
├─possible versions are: 0.5.0-0.8.1 or uninstalled
├─restricted by compatibility requirements with HTTP [cd3eb016] to versions: uninstalled
│ └─HTTP [cd3eb016] log:
│ ├─possible versions are: 0.6.10-1.10.0 or uninstalled
│ └─restricted to versions 1 by GenieBuilder [c9453c14], leaving only versions: 1.0.0-1.10.0
│ └─GenieBuilder [c9453c14] log:
│ ├─possible versions are: 0.15.12 or uninstalled
│ └─GenieBuilder [c9453c14] is fixed to version 0.15.12

I have uninstalled Temporal but I still get the same error. What is going on?

I have also posted it as a separate thread but haven’t received any response. Hence posting here.
GenieBuilder unable to install package - General Usage / Performance - Julia Programming Language (julialang.org)

The issue is being duscissed at the original seperate thread.