Closed failable closed 2 months ago
It seems like you need partials. Please read this article.
If I understand correctly you want to dynamically change your page by creating input visual elements.
@FlorianJacta Hello, I want to adjust the numbers of the visual elements, not the items of a single element like selector
.
In streamlit, it looks like
Notice how the numbers of text input elements changed when the different collections dropdown is selected.
Revalent code:
def sidebar_qdrant() -> tuple[QdrantClient, str, dict | None, int]:
qdrant_url = os.getenv("QDRANT_URL", "http://localhost:6333")
qdrant_url = st.sidebar.text_input("Qdrant url", qdrant_url)
qdrant_client = QdrantClient(qdrant_url)
collections = qdrant_client.get_collections().collections
collection_names = [x.name for x in collections]
collection_name = st.sidebar.selectbox("Collection", collection_names)
collection_info = qdrant_client.get_collection(collection_name)
filterable_payload_types = ["keyword", "text"]
payload_schema = {
k: v
for k, v in collection_info.payload_schema.items()
if v.data_type in filterable_payload_types
}
# Fixed field ordering for better user experience.
payload_schema = dict(
sorted(payload_schema.items(), key=lambda x: (x[1].data_type, x[0])),
)
query_filter = None
if payload_schema:
st.sidebar.markdown("### Filters")
filters = []
for field, schema in payload_schema.items():
value = st.sidebar.text_input(
f"{field} ({str.capitalize(schema.data_type)})",
) # <--------------------------- !!!!!! Dynamically created text inputs
if value:
filters += [
create_filter(field, schema, value),
]
if filters:
query_filter = {
"must": filters,
}
limit = st.sidebar.text_input("Limit", 10)
return qdrant_client, collection_name, query_filter, limit
You can almost use the same code that you use in Streamlit by having a partial that you can change in real-time. Some documentation on it: https://docs.taipy.io/en/develop/tutorials/visuals/4_partials/
Thanks for the link! I'm going to figure it out. Will comment back if I need further help.
The only difficult part is to bind these variables to Python variables. To do so, you can use a dictionary with all the keys you need for all your forms. Or you can dynamically change your dictionary. You have to create this forms variable containing every variable of your form. Also, you have to separate the logic of the page and the logic of your app interactivity.
The code below does not work; this is just to demonstrate what I mean.
def sidebar_qdrant(state) -> tuple[QdrantClient, str, dict | None, int]:
with tgb.Page() as new_partial:
qdrant_url = os.getenv("QDRANT_URL", "http://localhost:6333")
# tgb.input(label="Qdrant URL", "{qdrant_url}") # - create it somewhere else
qdrant_client = QdrantClient(state.qdrant_url)
collections = qdrant_client.get_collections().collections
collection_names = [x.name for x in collections]
collection_name = st.sidebar.selectbox("Collection", collection_names)
collection_info = qdrant_client.get_collection(collection_name)
filterable_payload_types = ["keyword", "text"]
payload_schema = {
k: v
for k, v in collection_info.payload_schema.items()
if v.data_type in filterable_payload_types
}
# Fixed field ordering for better user experience.
payload_schema = dict(
sorted(payload_schema.items(), key=lambda x: (x[1].data_type, x[0])),
)
query_filter = None
if payload_schema:
tgb.text("### Filters", mode="md")
filters = []
for field, schema in payload_schema.items():
tgb.input(
value="{forms."+str(field)+"}",
label=f"{field} ({str.capitalize(schema.data_type)})",
) # <--------------------------- !!!!!! Dynamically created text inputs
if value:
filters += [
create_filter(field, schema, value),
]
if filters:
query_filter = {
"must": filters,
}
tgb.input("{forms.limit}", label="Limit")
state.forms = payload_schema
state.your_partial.update_content(state, new_partial)
Hello, I came up with this https://gist.github.com/failable/0379edf7a5d82024a69a50194295372f
Any idea why I got two of the filter parts? The below one is not updated when I change the collection name.
Thanks.
Could you rephrase? I am not sure to understand what you mean. Why is there a blue and a white part?
Why is there a blue and a white part?
Yes. The white part seems to be the correct one while the blue part is not.
Is the blue part not supposed to be there at all, or is it just incorrect? Can you do some print inside your "for"?
Is the blue part not supposed to be there at all
Yes
When I launch the app, the logs look like
and the page looks like
When I change the collection
to news
, the logs look like
and the page look like
The filters of the last collection is left in the blue part. And the blue part is not supposed to be there at all when the app is launched.
The blueprint seems to be created when the on_init is called. Try to change this
gui.add_partial("filter_parial")
to gui.add_partial("")
And try to erase the indent you have with the section about the GUI so it is at the level of your if
.
gui = Gui(page=page)
filter_partial = gui.add_partial("filter_partial")
gui.run(
title="Qdrant viewer",
dark_mode=False,
debug=True,
use_reloader=True,
port=5001,
)
Then, try to put use_reloader to False.
Try to change this gui.add_partial("filter_parial") to gui.add_partial("")
Not working
Then, try to put use_reloader to False.
Not working
And try to erase the indent you have with the section about the GUI so it is at the level of your if.
This works!
Thanks for taking time to dig into this issue!
Great!
What would you like to share or ask?
When user select different
collection
dropdown, I'd like to display all thecolumns
of that collection using multipleinput
s to accept user input values to filter and query. Since different collections have different numbers of columns, how can I dynamically adjust the numbers ofinput
s ?Thanks.
Code of Conduct